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 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(); + 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(); + 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 +#include +#include #include #include #include @@ -31,7 +33,7 @@ public: virtual RefPtr 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 m_kern; Optional m_fpgm; Optional 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 m_glyph_page_zero; + + mutable HashMap> m_glyph_pages; + + GlyphPage const& glyph_page(size_t page_index) const; + void populate_glyph_page(GlyphPage&, size_t page_index) const; }; }