LibGfx/OpenType: Ignore glyphs with bogus offsets

Some fonts (like the Bootstrap Icons webfont) have bogus glyph offsets
in the `loca` table that point past the end of the `glyf` table.

AFAICT other rasterizers simply ignore these glyphs and treat them as if
they were missing. So let's do the same.

This makes https://changelog.serenityos.org/ actually work! :^)
This commit is contained in:
Andreas Kling 2023-03-28 21:51:57 +02:00
parent d01ac59b82
commit 264b9b73ac
Notes: sideshowbarker 2024-07-16 22:58:46 +09:00
3 changed files with 20 additions and 10 deletions

View file

@ -664,9 +664,11 @@ Gfx::ScaledGlyphMetrics Font::glyph_metrics(u32 glyph_id, float x_scale, float y
auto horizontal_metrics = m_hmtx.get_glyph_horizontal_metrics(glyph_id);
auto glyph_offset = m_loca->get_glyph_offset(glyph_id);
auto glyph = m_glyf->glyph(glyph_offset);
if (!glyph.has_value())
return {};
return Gfx::ScaledGlyphMetrics {
.ascender = static_cast<float>(glyph.ascender()) * y_scale,
.descender = static_cast<float>(glyph.descender()) * y_scale,
.ascender = static_cast<float>(glyph->ascender()) * y_scale,
.descender = static_cast<float>(glyph->descender()) * y_scale,
.advance_width = static_cast<float>(horizontal_metrics.advance_width) * x_scale,
.left_side_bearing = static_cast<float>(horizontal_metrics.left_side_bearing) * x_scale,
};
@ -708,6 +710,8 @@ RefPtr<Gfx::Bitmap> Font::rasterize_glyph(u32 glyph_id, float x_scale, float y_s
return nullptr;
auto glyph = m_glyf->glyph(glyph_offset0);
if (!glyph.has_value())
return nullptr;
i16 ascender = 0;
i16 descender = 0;
@ -720,7 +724,7 @@ RefPtr<Gfx::Bitmap> Font::rasterize_glyph(u32 glyph_id, float x_scale, float y_s
descender = m_hhea.descender();
}
return glyph.rasterize(ascender, descender, x_scale, y_scale, subpixel_offset, [&](u16 glyph_id) {
return glyph->rasterize(ascender, descender, x_scale, y_scale, subpixel_offset, [&](u16 glyph_id) {
if (glyph_id >= glyph_count()) {
glyph_id = 0;
}
@ -857,7 +861,9 @@ Optional<ReadonlyBytes> Font::glyph_program(u32 glyph_id) const
auto glyph_offset = m_loca->get_glyph_offset(glyph_id);
auto glyph = m_glyf->glyph(glyph_offset);
return glyph.program();
if (!glyph.has_value())
return {};
return glyph->program();
}
u32 Font::glyph_id_for_code_point(u32 code_point) const

View file

@ -367,8 +367,10 @@ RefPtr<Gfx::Bitmap> Glyf::Glyph::rasterize_simple(i16 font_ascender, i16 font_de
return rasterizer.accumulate();
}
Glyf::Glyph Glyf::glyph(u32 offset) const
Optional<Glyf::Glyph> Glyf::glyph(u32 offset) const
{
if (offset + sizeof(GlyphHeader) > m_slice.size())
return {};
VERIFY(m_slice.size() >= offset + sizeof(GlyphHeader));
auto const& glyph_header = *bit_cast<GlyphHeader const*>(m_slice.offset_pointer(offset));
i16 num_contours = glyph_header.number_of_contours;

View file

@ -113,12 +113,14 @@ public:
auto item = opt_item.value();
Gfx::AffineTransform affine_here { transform };
affine_here.multiply(item.affine);
Glyph glyph = glyph_callback(item.glyph_id);
auto glyph = glyph_callback(item.glyph_id);
if (!glyph.has_value())
continue;
if (glyph.m_type == Type::Simple) {
glyph.rasterize_impl(rasterizer, affine_here);
if (glyph->m_type == Type::Simple) {
glyph->rasterize_impl(rasterizer, affine_here);
} else {
glyph.rasterize_composite_loop(rasterizer, transform, glyph_callback);
glyph->rasterize_composite_loop(rasterizer, transform, glyph_callback);
}
}
}
@ -152,7 +154,7 @@ public:
: m_slice(slice)
{
}
Glyph glyph(u32 offset) const;
Optional<Glyph> glyph(u32 offset) const;
private:
// https://learn.microsoft.com/en-us/typography/opentype/spec/glyf#glyph-headers