diff --git a/Tests/LibWeb/Layout/expected/css-ex-unit.txt b/Tests/LibWeb/Layout/expected/css-ex-unit.txt
new file mode 100644
index 0000000000..62644b4cc8
--- /dev/null
+++ b/Tests/LibWeb/Layout/expected/css-ex-unit.txt
@@ -0,0 +1,4 @@
+Viewport <#document> at (0,0) content-size 800x600 children: not-inline
+ BlockContainer at (0,0) content-size 800x177.132812 [BFC] children: not-inline
+ BlockContainer
at (8,8) content-size 784x161.132812 children: not-inline
+ BlockContainer at (8,8) content-size 107.421875x161.132812 children: not-inline
diff --git a/Tests/LibWeb/Layout/input/css-ex-unit.html b/Tests/LibWeb/Layout/input/css-ex-unit.html
new file mode 100644
index 0000000000..f583eb8fad
--- /dev/null
+++ b/Tests/LibWeb/Layout/input/css-ex-unit.html
@@ -0,0 +1,8 @@
+
\ No newline at end of file
diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp b/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp
index 8e1efccf00..45cb2fccb5 100644
--- a/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp
+++ b/Userland/Libraries/LibGfx/Font/OpenType/Font.cpp
@@ -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 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(raw_ascender) * y_scale,
.descender = -static_cast(raw_descender) * y_scale,
.line_gap = static_cast(raw_line_gap) * y_scale,
+ .x_height = static_cast(x_height.value()) * y_scale,
};
}
@@ -854,6 +861,13 @@ bool OS2::use_typographic_metrics() const
return header().fs_selection & 0x80;
}
+Optional OS2::x_height() const
+{
+ if (header().version < 2)
+ return {};
+ return header_v2().sx_height;
+}
+
Optional Font::font_program() const
{
if (m_fpgm.has_value())
diff --git a/Userland/Libraries/LibGfx/Font/OpenType/Tables.h b/Userland/Libraries/LibGfx/Font/OpenType/Tables.h
index 15c0b301d9..b70b059b3d 100644
--- a/Userland/Libraries/LibGfx/Font/OpenType/Tables.h
+++ b/Userland/Libraries/LibGfx/Font/OpenType/Tables.h
@@ -243,6 +243,8 @@ public:
bool use_typographic_metrics() const;
+ [[nodiscard]] Optional x_height() const;
+
explicit OS2(ReadonlyBytes slice)
: m_slice(slice)
{
@@ -282,7 +284,27 @@ private:
BigEndian us_win_descent;
};
+ struct Version1 {
+ Version0 version0;
+ BigEndian ul_code_page_range1;
+ BigEndian ul_code_page_range2;
+ };
+
+ struct Version2 {
+ Version1 version1;
+ BigEndian sx_height;
+ BigEndian s_cap_height;
+ BigEndian us_default_char;
+ BigEndian us_break_char;
+ BigEndian us_max_context;
+ };
+
Version0 const& header() const { return *bit_cast(m_slice.data()); }
+ Version2 const& header_v2() const
+ {
+ VERIFY(header().version >= 2);
+ return *bit_cast(m_slice.data());
+ }
ReadonlyBytes m_slice;
};
diff --git a/Userland/Libraries/LibGfx/Font/ScaledFont.cpp b/Userland/Libraries/LibGfx/Font/ScaledFont.cpp
index 441639bc97..f5022eefcd 100644
--- a/Userland/Libraries/LibGfx/Font/ScaledFont.cpp
+++ b/Userland/Libraries/LibGfx/Font/ScaledFont.cpp
@@ -27,7 +27,7 @@ ScaledFont::ScaledFont(NonnullRefPtr 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,
diff --git a/Userland/Libraries/LibGfx/Font/VectorFont.h b/Userland/Libraries/LibGfx/Font/VectorFont.h
index 06a5693488..945eb1e54e 100644
--- a/Userland/Libraries/LibGfx/Font/VectorFont.h
+++ b/Userland/Libraries/LibGfx/Font/VectorFont.h
@@ -17,6 +17,7 @@ struct ScaledFontMetrics {
float ascender { 0 };
float descender { 0 };
float line_gap { 0 };
+ float x_height { 0 };
float height() const
{