1
0
mirror of https://github.com/SerenityOS/serenity synced 2024-07-05 21:55:08 +00:00

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.
This commit is contained in:
Andreas Kling 2023-01-30 19:13:39 +01:00
parent e147d0b572
commit ce6636e78e
2 changed files with 53 additions and 1 deletions

View File

@ -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);
}
}
}

View File

@ -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;
};
}