summaryrefslogtreecommitdiff
path: root/Userland/Libraries
diff options
context:
space:
mode:
authorAndreas Kling <kling@serenityos.org>2023-01-30 19:13:39 +0100
committerAndreas Kling <kling@serenityos.org>2023-01-31 17:14:57 +0100
commitce6636e78e0f6ec9a54774405faf147635552923 (patch)
tree71af7e00600f77d150517f5162eb412c0ca0f3ef /Userland/Libraries
parente147d0b57290b09a5a29aad8b9296e60bca09e80 (diff)
downloadserenity-ce6636e78e0f6ec9a54774405faf147635552923.zip
LibGfx: Make glyph ID lookup faster with a cache
This patch adds a "GlyphPage" cache which stores the mapping between code points and glyph IDs in a segmented table of "pages". This makes Font::glyph_id_for_code_point() significantly faster by not reparsing the font tables every time you call it. In the future, we can add more information to GlyphPage (such as horizontal metrics for each glyph) to further reduce time spent in text layout and painting.
Diffstat (limited to 'Userland/Libraries')
-rw-r--r--Userland/Libraries/LibGfx/Font/OpenType/Font.cpp34
-rw-r--r--Userland/Libraries/LibGfx/Font/OpenType/Font.h20
2 files changed, 53 insertions, 1 deletions
diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp b/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp
index b203c94ae4..64f39fdc2f 100644
--- a/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp
+++ b/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp
@@ -726,4 +726,38 @@ Optional<ReadonlyBytes> Font::glyph_program(u32 glyph_id) const
return glyph.program();
}
+u32 Font::glyph_id_for_code_point(u32 code_point) const
+{
+ return glyph_page(code_point / GlyphPage::glyphs_per_page).glyph_ids[code_point % GlyphPage::glyphs_per_page];
+}
+
+Font::GlyphPage const& Font::glyph_page(size_t page_index) const
+{
+ if (page_index == 0) {
+ if (!m_glyph_page_zero) {
+ m_glyph_page_zero = make<GlyphPage>();
+ populate_glyph_page(*m_glyph_page_zero, 0);
+ }
+ return *m_glyph_page_zero;
+ }
+ if (auto it = m_glyph_pages.find(page_index); it != m_glyph_pages.end()) {
+ return *it->value;
+ }
+
+ auto glyph_page = make<GlyphPage>();
+ populate_glyph_page(*glyph_page, page_index);
+ auto const* glyph_page_ptr = glyph_page.ptr();
+ m_glyph_pages.set(page_index, move(glyph_page));
+ return *glyph_page_ptr;
+}
+
+void Font::populate_glyph_page(GlyphPage& glyph_page, size_t page_index) const
+{
+ u32 first_code_point = page_index * GlyphPage::glyphs_per_page;
+ for (size_t i = 0; i < GlyphPage::glyphs_per_page; ++i) {
+ u32 code_point = first_code_point + i;
+ glyph_page.glyph_ids[i] = m_cmap.glyph_id_for_code_point(code_point);
+ }
+}
+
}
diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Font.h b/Userland/Libraries/LibGfx/Font/OpenType/Font.h
index a1e27a7789..2061decc34 100644
--- a/Userland/Libraries/LibGfx/Font/OpenType/Font.h
+++ b/Userland/Libraries/LibGfx/Font/OpenType/Font.h
@@ -7,6 +7,8 @@
#pragma once
#include <AK/Noncopyable.h>
+#include <AK/NonnullOwnPtr.h>
+#include <AK/OwnPtr.h>
#include <AK/RefCounted.h>
#include <AK/StringView.h>
#include <LibGfx/Bitmap.h>
@@ -31,7 +33,7 @@ public:
virtual RefPtr<Gfx::Bitmap> rasterize_glyph(u32 glyph_id, float x_scale, float y_scale, Gfx::GlyphSubpixelOffset) const override;
virtual u32 glyph_count() const override;
virtual u16 units_per_em() const override;
- virtual u32 glyph_id_for_code_point(u32 code_point) const override { return m_cmap.glyph_id_for_code_point(code_point); }
+ virtual u32 glyph_id_for_code_point(u32 code_point) const override;
virtual DeprecatedString family() const override;
virtual DeprecatedString variant() const override;
virtual u16 weight() const override;
@@ -90,6 +92,22 @@ private:
Optional<Kern> m_kern;
Optional<Fpgm> m_fpgm;
Optional<Prep> m_prep;
+
+ // This cache stores information per code point.
+ // It's segmented into pages with data about 256 code points each.
+ struct GlyphPage {
+ static constexpr size_t glyphs_per_page = 256;
+
+ u32 glyph_ids[glyphs_per_page];
+ };
+
+ // Fast cache for GlyphPage #0 (code points 0-255) to avoid hash lookups for all of ASCII and Latin-1.
+ mutable OwnPtr<GlyphPage> m_glyph_page_zero;
+
+ mutable HashMap<size_t, NonnullOwnPtr<GlyphPage>> m_glyph_pages;
+
+ GlyphPage const& glyph_page(size_t page_index) const;
+ void populate_glyph_page(GlyphPage&, size_t page_index) const;
};
}