1
Fork 0
mirror of https://github.com/RGBCube/serenity synced 2025-07-25 19:57:35 +00:00

LibTTF+LibGfx: Improve vertical alignment of glyphs

Before this patch, some glyphs had a weird off-by-1 vertical position
which looked really jarring at small font sizes.

This was caused by glyph bitmaps having different heights from each
other. (Each glyph bitmap was minimally sized to fit only the glyph
itself, and then vertically positioned during the paint phase.
Since this vertical positioning was integer based, subpixel precision
was lost and things ended up looking wonky.)

Fix this by making all glyph bitmaps be the same height so we can blit
them at the same integer y position. We use the typographic ascent from
the OS/2 table to transform the glyph coordinates.

The end result is a huge improvement visually. :^)
This commit is contained in:
Andreas Kling 2021-07-20 01:43:39 +02:00
parent e984200206
commit 9f601fcbcf
4 changed files with 12 additions and 12 deletions

View file

@ -1160,7 +1160,7 @@ FLATTEN void Painter::draw_glyph(const IntPoint& point, u32 code_point, Color co
FLATTEN void Painter::draw_glyph(const IntPoint& point, u32 code_point, const Font& font, Color color)
{
auto glyph = font.glyph(code_point);
auto top_left = point + IntPoint(glyph.left_bearing(), font.glyph_height() - glyph.ascent());
auto top_left = point + IntPoint(glyph.left_bearing(), 0);
if (glyph.is_glyph_bitmap()) {
draw_bitmap(top_left, glyph.glyph_bitmap(), color);

View file

@ -425,7 +425,7 @@ RefPtr<Gfx::Bitmap> Font::rasterize_glyph(u32 glyph_id, float x_scale, float y_s
}
auto glyph_offset = m_loca.get_glyph_offset(glyph_id);
auto glyph = m_glyf.glyph(glyph_offset);
return glyph.rasterize(x_scale, y_scale, [&](u16 glyph_id) {
return glyph.rasterize(m_os2.typographic_ascender(), m_os2.typographic_descender(), x_scale, y_scale, [&](u16 glyph_id) {
if (glyph_id >= glyph_count()) {
glyph_id = 0;
}

View file

@ -478,12 +478,12 @@ void Glyf::Glyph::rasterize_impl(Rasterizer& rasterizer, Gfx::AffineTransform co
rasterizer.draw_path(path);
}
RefPtr<Gfx::Bitmap> Glyf::Glyph::rasterize_simple(float x_scale, float y_scale) const
RefPtr<Gfx::Bitmap> Glyf::Glyph::rasterize_simple(i16 font_ascender, i16 font_descender, float x_scale, float y_scale) const
{
u32 width = (u32)(ceilf((m_xmax - m_xmin) * x_scale)) + 2;
u32 height = (u32)(ceilf((m_ymax - m_ymin) * y_scale)) + 2;
u32 height = (u32)(ceilf((font_ascender - font_descender) * y_scale)) + 2;
Rasterizer rasterizer(Gfx::IntSize(width, height));
auto affine = Gfx::AffineTransform().scale(x_scale, -y_scale).translate(-m_xmin, -m_ymax);
auto affine = Gfx::AffineTransform().scale(x_scale, -y_scale).translate(-m_xmin, -font_ascender);
rasterize_impl(rasterizer, affine);
return rasterizer.accumulate();
}

View file

@ -63,13 +63,13 @@ public:
}
}
template<typename GlyphCb>
RefPtr<Gfx::Bitmap> rasterize(float x_scale, float y_scale, GlyphCb glyph_callback) const
RefPtr<Gfx::Bitmap> rasterize(i16 font_ascender, i16 font_descender, float x_scale, float y_scale, GlyphCb glyph_callback) const
{
switch (m_type) {
case Type::Simple:
return rasterize_simple(x_scale, y_scale);
return rasterize_simple(font_ascender, font_descender, x_scale, y_scale);
case Type::Composite:
return rasterize_composite(x_scale, y_scale, glyph_callback);
return rasterize_composite(font_ascender, font_descender, x_scale, y_scale, glyph_callback);
}
VERIFY_NOT_REACHED();
}
@ -102,14 +102,14 @@ public:
};
void rasterize_impl(Rasterizer&, Gfx::AffineTransform const&) const;
RefPtr<Gfx::Bitmap> rasterize_simple(float x_scale, float y_scale) 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(float x_scale, float y_scale, GlyphCb glyph_callback) const
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((m_ymax - m_ymin) * y_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, -m_ymax);
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();