diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp b/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp index 9195aeb3fd..8e1efccf00 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp +++ b/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp @@ -676,15 +676,30 @@ Gfx::ScaledGlyphMetrics Font::glyph_metrics(u32 glyph_id, float x_scale, float y float Font::glyphs_horizontal_kerning(u32 left_glyph_id, u32 right_glyph_id, float x_scale) const { - if (m_gpos.has_value()) { - auto kerning = m_gpos->glyph_kerning(left_glyph_id, right_glyph_id); - if (kerning.has_value()) - return kerning.value() * x_scale; + if (!m_gpos.has_value() && !m_kern.has_value()) + return 0.0f; + + // NOTE: OpenType glyph IDs are 16-bit, so this is safe. + auto cache_key = (left_glyph_id << 16) | right_glyph_id; + if (auto it = m_kerning_cache.find(cache_key); it != m_kerning_cache.end()) { + return it->value * x_scale; } - if (m_kern.has_value()) - return m_kern->get_glyph_kerning(left_glyph_id, right_glyph_id) * x_scale; + if (m_gpos.has_value()) { + auto kerning = m_gpos->glyph_kerning(left_glyph_id, right_glyph_id); + if (kerning.has_value()) { + m_kerning_cache.set(cache_key, kerning.value()); + return kerning.value() * x_scale; + } + } + if (m_kern.has_value()) { + auto kerning = m_kern->get_glyph_kerning(left_glyph_id, right_glyph_id) * x_scale; + m_kerning_cache.set(cache_key, kerning); + return kerning; + } + + m_kerning_cache.set(cache_key, 0); return 0.0f; } diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Font.h b/Userland/Libraries/LibGfx/Font/OpenType/Font.h index f38d77ac44..80a0dd1637 100644 --- a/Userland/Libraries/LibGfx/Font/OpenType/Font.h +++ b/Userland/Libraries/LibGfx/Font/OpenType/Font.h @@ -141,6 +141,8 @@ private: mutable HashMap> m_glyph_pages; + mutable HashMap m_kerning_cache; + GlyphPage const& glyph_page(size_t page_index) const; void populate_glyph_page(GlyphPage&, size_t page_index) const; };