diff options
author | Enver Balalic <balalic.enver@gmail.com> | 2022-09-16 11:46:22 +0200 |
---|---|---|
committer | Andreas Kling <kling@serenityos.org> | 2022-09-16 14:52:03 +0200 |
commit | 11a44ffb69c46cd7fae6a95ec35d7e8348f8da5b (patch) | |
tree | 5c6287f7d973e1f2e442f49354c48f9d7566e6e0 | |
parent | e6306d459a638fadfebcb58bf0ee707bf5c86c5d (diff) | |
download | serenity-11a44ffb69c46cd7fae6a95ec35d7e8348f8da5b.zip |
LibGfx: Recurse TrueType composite glyphs until a simple glyph is found
This fixes a bug in ladybird where it was crashing while rendering
characters like Ε‘ΔΔΕΎ in the Noto Sans Regular font.
That font renders those characters as a composite where the caret
has numberOfContours = -1. When using the rasterize_impl simple path
for that, it would negatively overflow the offsets.
-rw-r--r-- | Userland/Libraries/LibGfx/Font/TrueType/Glyf.h | 31 |
1 files changed, 23 insertions, 8 deletions
diff --git a/Userland/Libraries/LibGfx/Font/TrueType/Glyf.h b/Userland/Libraries/LibGfx/Font/TrueType/Glyf.h index ef4de03ac0..153334680b 100644 --- a/Userland/Libraries/LibGfx/Font/TrueType/Glyf.h +++ b/Userland/Libraries/LibGfx/Font/TrueType/Glyf.h @@ -103,24 +103,39 @@ public: void rasterize_impl(Rasterizer&, Gfx::AffineTransform const&) const; RefPtr<Gfx::Bitmap> rasterize_simple(i16 ascender, i16 descender, float x_scale, float y_scale) const; + template<typename GlyphCb> - RefPtr<Gfx::Bitmap> rasterize_composite(i16 font_ascender, i16 font_descender, float x_scale, float y_scale, GlyphCb glyph_callback) const + void rasterize_composite_loop(Rasterizer& rasterizer, Gfx::AffineTransform& transform, GlyphCb glyph_callback) const { - u32 width = (u32)(ceilf((m_xmax - m_xmin) * x_scale)) + 1; - u32 height = (u32)(ceilf((font_ascender - font_descender) * y_scale)) + 1; - Rasterizer rasterizer(Gfx::IntSize(width, height)); - auto affine = Gfx::AffineTransform().scale(x_scale, -y_scale).translate(-m_xmin, -font_ascender); ComponentIterator component_iterator(m_slice); + while (true) { auto opt_item = component_iterator.next(); if (!opt_item.has_value()) { break; } auto item = opt_item.value(); - auto affine_here = affine.multiply(item.affine); - auto glyph = glyph_callback(item.glyph_id); - glyph.rasterize_impl(rasterizer, affine_here); + auto affine_here = transform.multiply(item.affine); + Glyph glyph = glyph_callback(item.glyph_id); + + if (glyph.m_type == Type::Simple) { + glyph.rasterize_impl(rasterizer, affine_here); + } else { + glyph.rasterize_composite_loop(rasterizer, transform, glyph_callback); + } } + } + + template<typename GlyphCb> + RefPtr<Gfx::Bitmap> rasterize_composite(i16 font_ascender, i16 font_descender, float x_scale, float y_scale, GlyphCb glyph_callback) const + { + u32 width = (u32)(ceilf((m_xmax - m_xmin) * x_scale)) + 1; + u32 height = (u32)(ceilf((font_ascender - font_descender) * y_scale)) + 1; + Rasterizer rasterizer(Gfx::IntSize(width, height)); + auto affine = Gfx::AffineTransform().scale(x_scale, -y_scale).translate(-m_xmin, -font_ascender); + + rasterize_composite_loop(rasterizer, affine, glyph_callback); + return rasterizer.accumulate(); } |