diff options
author | Andreas Kling <kling@serenityos.org> | 2023-01-30 19:13:39 +0100 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2023-01-31 17:14:57 +0100 |
commit | ce6636e78e0f6ec9a54774405faf147635552923 (patch) | |
tree | 71af7e00600f77d150517f5162eb412c0ca0f3ef /Userland/Libraries | |
parent | e147d0b57290b09a5a29aad8b9296e60bca09e80 (diff) | |
download | serenity-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.cpp | 34 | ||||
-rw-r--r-- | Userland/Libraries/LibGfx/Font/OpenType/Font.h | 20 |
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; }; } |