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

LibGfx/OpenType: Load x-height metrics from OS/2 table if available

Before this change we always returned the font's point size as the
x-height which was basically never correct.

We now get it from the OS/2 table (if one with version >= 2 is available
in the file). Otherwise we fall back to using the ascent of the 'x'
glyph. Most fonts appear to have a sufficiently modern OS/2 table.
This commit is contained in:
Andreas Kling 2023-06-10 14:50:03 +02:00
parent 8090adf268
commit 69c33bd4ca
6 changed files with 50 additions and 1 deletions

View file

@ -0,0 +1,4 @@
Viewport <#document> at (0,0) content-size 800x600 children: not-inline
BlockContainer <html> at (0,0) content-size 800x177.132812 [BFC] children: not-inline
BlockContainer <body> at (8,8) content-size 784x161.132812 children: not-inline
BlockContainer <div> at (8,8) content-size 107.421875x161.132812 children: not-inline

View file

@ -0,0 +1,8 @@
<!doctype html><style>
div {
font: 20px SerenitySans;
width: 10ex;
height: 15ex;
background: red;
}
</style><div>

View file

@ -574,21 +574,28 @@ Gfx::ScaledFontMetrics Font::metrics([[maybe_unused]] float x_scale, float y_sca
i16 raw_ascender;
i16 raw_descender;
i16 raw_line_gap;
Optional<i16> x_height;
if (m_os2.has_value() && m_os2->use_typographic_metrics()) {
raw_ascender = m_os2->typographic_ascender();
raw_descender = m_os2->typographic_descender();
raw_line_gap = m_os2->typographic_line_gap();
x_height = m_os2->x_height();
} else {
raw_ascender = m_hhea.ascender();
raw_descender = m_hhea.descender();
raw_line_gap = m_hhea.line_gap();
}
if (!x_height.has_value()) {
x_height = glyph_metrics(glyph_id_for_code_point('x'), 1, 1, 1, 1).ascender;
}
return Gfx::ScaledFontMetrics {
.ascender = static_cast<float>(raw_ascender) * y_scale,
.descender = -static_cast<float>(raw_descender) * y_scale,
.line_gap = static_cast<float>(raw_line_gap) * y_scale,
.x_height = static_cast<float>(x_height.value()) * y_scale,
};
}
@ -854,6 +861,13 @@ bool OS2::use_typographic_metrics() const
return header().fs_selection & 0x80;
}
Optional<i16> OS2::x_height() const
{
if (header().version < 2)
return {};
return header_v2().sx_height;
}
Optional<ReadonlyBytes> Font::font_program() const
{
if (m_fpgm.has_value())

View file

@ -243,6 +243,8 @@ public:
bool use_typographic_metrics() const;
[[nodiscard]] Optional<i16> x_height() const;
explicit OS2(ReadonlyBytes slice)
: m_slice(slice)
{
@ -282,7 +284,27 @@ private:
BigEndian<u16> us_win_descent;
};
struct Version1 {
Version0 version0;
BigEndian<u32> ul_code_page_range1;
BigEndian<u32> ul_code_page_range2;
};
struct Version2 {
Version1 version1;
BigEndian<i16> sx_height;
BigEndian<i16> s_cap_height;
BigEndian<u16> us_default_char;
BigEndian<u16> us_break_char;
BigEndian<u16> us_max_context;
};
Version0 const& header() const { return *bit_cast<Version0 const*>(m_slice.data()); }
Version2 const& header_v2() const
{
VERIFY(header().version >= 2);
return *bit_cast<Version2 const*>(m_slice.data());
}
ReadonlyBytes m_slice;
};

View file

@ -27,7 +27,7 @@ ScaledFont::ScaledFont(NonnullRefPtr<VectorFont> font, float point_width, float
m_pixel_metrics = Gfx::FontPixelMetrics {
.size = (float)pixel_size(),
.x_height = (float)x_height(),
.x_height = metrics.x_height,
.advance_of_ascii_zero = (float)glyph_width('0'),
.glyph_spacing = (float)glyph_spacing(),
.ascent = metrics.ascender,

View file

@ -17,6 +17,7 @@ struct ScaledFontMetrics {
float ascender { 0 };
float descender { 0 };
float line_gap { 0 };
float x_height { 0 };
float height() const
{