LibWeb: Use computed line-height for FontMetrics

We were already doing this within `compute_property_values` where
we resolved most relative lengths but the remainder was instead
incorrectly using the font's line-spacing
This commit is contained in:
Callum Law 2025-09-23 00:18:51 +12:00 committed by Tim Ledbetter
parent a5139733cc
commit 3b15c303f6
6 changed files with 48 additions and 40 deletions

View File

@ -20,14 +20,14 @@
namespace Web::CSS {
Length::FontMetrics::FontMetrics(CSSPixels font_size, Gfx::FontPixelMetrics const& pixel_metrics)
Length::FontMetrics::FontMetrics(CSSPixels font_size, Gfx::FontPixelMetrics const& pixel_metrics, CSSPixels line_height)
: font_size(font_size)
, x_height(pixel_metrics.x_height)
// FIXME: This is only approximately the cap height. The spec suggests measuring the "O" glyph:
// https://www.w3.org/TR/css-values-4/#cap
, cap_height(pixel_metrics.ascent)
, zero_advance(pixel_metrics.advance_of_ascii_zero)
, line_height(round(pixel_metrics.line_spacing()))
, line_height(line_height)
{
}
@ -137,8 +137,8 @@ Length::ResolutionContext Length::ResolutionContext::for_element(DOM::AbstractEl
return Length::ResolutionContext {
.viewport_rect = element.element().navigable()->viewport_rect(),
.font_metrics = { element.computed_properties()->font_size(), element.computed_properties()->first_available_computed_font().pixel_metrics() },
.root_font_metrics = { root_element->computed_properties()->font_size(), root_element->computed_properties()->first_available_computed_font().pixel_metrics() }
.font_metrics = { element.computed_properties()->font_size(), element.computed_properties()->first_available_computed_font().pixel_metrics(), element.computed_properties()->line_height() },
.root_font_metrics = { root_element->computed_properties()->font_size(), root_element->computed_properties()->first_available_computed_font().pixel_metrics(), element.computed_properties()->line_height() }
};
}
@ -146,7 +146,7 @@ Length::ResolutionContext Length::ResolutionContext::for_window(HTML::Window con
{
auto const& initial_font = window.associated_document().style_computer().initial_font();
Gfx::FontPixelMetrics const& initial_font_metrics = initial_font.pixel_metrics();
Length::FontMetrics font_metrics { CSSPixels { initial_font.pixel_size() }, initial_font_metrics };
Length::FontMetrics font_metrics { CSSPixels { initial_font.pixel_size() }, initial_font_metrics, InitialValues::line_height() };
return Length::ResolutionContext {
.viewport_rect = window.page().web_exposed_screen_area(),
.font_metrics = font_metrics,
@ -169,8 +169,8 @@ Length::ResolutionContext Length::ResolutionContext::for_layout_node(Layout::Nod
return Length::ResolutionContext {
.viewport_rect = node.navigable()->viewport_rect(),
.font_metrics = { node.computed_values().font_size(), node.first_available_font().pixel_metrics() },
.root_font_metrics = { root_layout_node->computed_values().font_size(), root_layout_node->first_available_font().pixel_metrics() },
.font_metrics = { node.computed_values().font_size(), node.first_available_font().pixel_metrics(), node.computed_values().line_height() },
.root_font_metrics = { root_layout_node->computed_values().font_size(), root_layout_node->first_available_font().pixel_metrics(), node.computed_values().line_height() },
};
}
@ -192,10 +192,12 @@ CSSPixels Length::to_px_slow_case(Layout::Node const& layout_node) const
FontMetrics font_metrics {
layout_node.computed_values().font_size(),
layout_node.first_available_font().pixel_metrics(),
layout_node.computed_values().line_height()
};
FontMetrics root_font_metrics {
root_element->layout_node()->computed_values().font_size(),
root_element->layout_node()->first_available_font().pixel_metrics(),
layout_node.computed_values().line_height()
};
return font_relative_length_to_px(font_metrics, root_font_metrics);

View File

@ -21,7 +21,7 @@ namespace Web::CSS {
class WEB_API Length {
public:
struct FontMetrics {
FontMetrics(CSSPixels font_size, Gfx::FontPixelMetrics const&);
FontMetrics(CSSPixels font_size, Gfx::FontPixelMetrics const&, CSSPixels line_height);
CSSPixels font_size;
CSSPixels x_height;

View File

@ -203,7 +203,7 @@ MatchResult MediaFeature::compare(HTML::Window const& window, MediaFeatureValue
auto const& initial_font = window.associated_document().style_computer().initial_font();
Gfx::FontPixelMetrics const& initial_font_metrics = initial_font.pixel_metrics();
Length::FontMetrics font_metrics { CSSPixels { initial_font.point_size() }, initial_font_metrics };
Length::FontMetrics font_metrics { CSSPixels { initial_font.point_size() }, initial_font_metrics, InitialValues::line_height() };
left_px = left_length.to_px(viewport_rect, font_metrics, font_metrics);
right_px = right_length.to_px(viewport_rect, font_metrics, font_metrics);

View File

@ -184,7 +184,7 @@ OwnFontFaceKey::operator FontFaceKey() const
StyleComputer::StyleComputer(DOM::Document& document)
: m_document(document)
, m_default_font_metrics(16, Platform::FontPlugin::the().default_font(16)->pixel_metrics())
, m_default_font_metrics(16, Platform::FontPlugin::the().default_font(16)->pixel_metrics(), InitialValues::line_height())
, m_root_element_font_metrics(m_default_font_metrics)
{
m_ancestor_filter = make<CountingBloomFilter<u8, 14>>();
@ -977,7 +977,8 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element
compute_property_values(computed_properties);
Length::FontMetrics font_metrics {
computed_properties.font_size(),
computed_properties.first_available_computed_font().pixel_metrics()
computed_properties.first_available_computed_font().pixel_metrics(),
computed_properties.line_height()
};
HashMap<PropertyID, RefPtr<StyleValue const>> specified_values;
@ -1707,7 +1708,7 @@ Length::FontMetrics StyleComputer::calculate_root_element_font_metrics(ComputedP
auto const& root_value = style.property(CSS::PropertyID::FontSize);
auto font_pixel_metrics = style.first_available_computed_font().pixel_metrics();
Length::FontMetrics font_metrics { m_default_font_metrics.font_size, font_pixel_metrics };
Length::FontMetrics font_metrics { m_default_font_metrics.font_size, font_pixel_metrics, InitialValues::line_height() };
font_metrics.font_size = root_value.as_length().length().to_px(viewport_rect(), font_metrics, font_metrics);
font_metrics.line_height = style.compute_line_height(viewport_rect(), font_metrics, font_metrics);
@ -2090,7 +2091,9 @@ void StyleComputer::compute_property_values(ComputedProperties& style) const
{
Length::FontMetrics font_metrics {
style.font_size(),
style.first_available_computed_font().pixel_metrics()
style.first_available_computed_font().pixel_metrics(),
// FIXME: Use the correct value for line height here.
CSSPixels { round(style.first_available_computed_font().pixel_metrics().line_spacing()) }
};
auto const& line_height_specified_value = style.property(CSS::PropertyID::LineHeight, ComputedProperties::WithAnimationsApplied::No);
@ -2525,7 +2528,10 @@ RefPtr<StyleValue const> StyleComputer::recascade_font_size_if_needed(DOM::Abstr
}
VERIFY(font_size_value->is_length());
current_size_in_px = font_size_value->as_length().length().to_px(viewport_rect(), Length::FontMetrics { current_size_in_px, monospace_font->with_size(current_size_in_px * 0.75f)->pixel_metrics() }, m_root_element_font_metrics);
auto inherited_line_height = ancestor.element_to_inherit_style_from().map([](auto& parent_element) { return parent_element.computed_properties()->line_height(); }).value_or(InitialValues::line_height());
current_size_in_px = font_size_value->as_length().length().to_px(viewport_rect(), Length::FontMetrics { current_size_in_px, monospace_font->with_size(current_size_in_px * 0.75f)->pixel_metrics(), inherited_line_height }, m_root_element_font_metrics);
};
return CSS::LengthStyleValue::create(CSS::Length::make_px(current_size_in_px));

View File

@ -1,26 +1,26 @@
Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-inline
BlockContainer <html> at [0,0] [0+0+0 800 0+0+0] [0+0+0 66 0+0+0] [BFC] children: not-inline
BlockContainer <body> at [8,8] [8+0+0 784 0+0+8] [8+0+0 50 0+0+8] children: inline
frag 0 from BlockContainer start: 0, length: 0, rect: [11,11 240x44] baseline: 20.5
BlockContainer <html> at [0,0] [0+0+0 800 0+0+0] [0+0+0 68 0+0+0] [BFC] children: not-inline
BlockContainer <body> at [8,8] [8+0+0 784 0+0+8] [8+0+0 52 0+0+8] children: inline
frag 0 from BlockContainer start: 0, length: 0, rect: [11,11 240x46] baseline: 20.5
frag 1 from TextNode start: 0, length: 1, rect: [254,11 10x23] baseline: 17.5
" "
frag 2 from BlockContainer start: 0, length: 0, rect: [267,11 240x44] baseline: 20.5
frag 3 from BlockContainer start: 0, length: 0, rect: [513,11 240x44] baseline: 20.5
frag 2 from BlockContainer start: 0, length: 0, rect: [267,11 240x46] baseline: 20.5
frag 3 from BlockContainer start: 0, length: 0, rect: [513,11 240x46] baseline: 20.5
TextNode <#text> (not painted)
BlockContainer <textarea> at [11,11] inline-block [0+1+2 240 2+1+0] [0+1+2 44 2+1+0] [BFC] children: not-inline
BlockContainer <textarea> at [11,11] inline-block [0+1+2 240 2+1+0] [0+1+2 46 2+1+0] [BFC] children: not-inline
BlockContainer <div> at [11,11] [0+0+0 240 0+0+0] [0+0+0 23 0+0+0] children: not-inline
BlockContainer <div> at [11,11] [0+0+0 240 0+0+0] [0+0+0 23 0+0+0] children: inline
frag 0 from TextNode start: 0, length: 17, rect: [11,11 190.28125x23] baseline: 17.5
"Bonjour mon amis!"
TextNode <#text> (not painted)
TextNode <#text> (not painted)
BlockContainer <textarea> at [267,11] inline-block [0+1+2 240 2+1+0] [0+1+2 44 2+1+0] [BFC] children: not-inline
BlockContainer <textarea> at [267,11] inline-block [0+1+2 240 2+1+0] [0+1+2 46 2+1+0] [BFC] children: not-inline
BlockContainer <div> at [267,11] [0+0+0 240 0+0+0] [0+0+0 23 0+0+0] children: not-inline
BlockContainer <div> at [267,11] [0+0+0 240 0+0+0] [0+0+0 23 0+0+0] children: inline
frag 0 from TextNode start: 0, length: 19, rect: [267,11 177.734375x23] baseline: 17.5
"Well hello friends!"
TextNode <#text> (not painted)
BlockContainer <textarea> at [513,11] inline-block [0+1+2 240 2+1+0] [0+1+2 44 2+1+0] [BFC] children: not-inline
BlockContainer <textarea> at [513,11] inline-block [0+1+2 240 2+1+0] [0+1+2 46 2+1+0] [BFC] children: not-inline
BlockContainer <div> at [513,11] [0+0+0 240 0+0+0] [0+0+0 23 0+0+0] children: not-inline
BlockContainer <div> at [513,11] [0+0+0 240 0+0+0] [0+0+0 23 0+0+0] children: inline
frag 0 from TextNode start: 0, length: 15, rect: [513,11 154.078125x23] baseline: 17.5
@ -29,21 +29,21 @@ Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-
TextNode <#text> (not painted)
ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x66]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x50]
PaintableWithLines (BlockContainer<TEXTAREA>) [8,8 246x50]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x68]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x52]
PaintableWithLines (BlockContainer<TEXTAREA>) [8,8 246x52]
PaintableWithLines (BlockContainer<DIV>) [11,11 240x23]
PaintableWithLines (BlockContainer<DIV>) [11,11 240x23]
TextPaintable (TextNode<#text>)
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<TEXTAREA>) [264,8 246x50]
PaintableWithLines (BlockContainer<TEXTAREA>) [264,8 246x52]
PaintableWithLines (BlockContainer<DIV>) [267,11 240x23]
PaintableWithLines (BlockContainer<DIV>) [267,11 240x23]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer<TEXTAREA>) [510,8 246x50]
PaintableWithLines (BlockContainer<TEXTAREA>) [510,8 246x52]
PaintableWithLines (BlockContainer<DIV>) [513,11 240x23]
PaintableWithLines (BlockContainer<DIV>) [513,11 240x23]
TextPaintable (TextNode<#text>)
SC for Viewport<#document> [0,0 800x600] [children: 1] (z-index: auto)
SC for BlockContainer<HTML> [0,0 800x66] [children: 0] (z-index: auto)
SC for BlockContainer<HTML> [0,0 800x68] [children: 0] (z-index: auto)

View File

@ -1,29 +1,29 @@
Viewport <#document> at [0,0] [0+0+0 800 0+0+0] [0+0+0 600 0+0+0] children: not-inline
BlockContainer <html> at [0,0] [0+0+0 800 0+0+0] [0+0+0 50 0+0+0] [BFC] children: not-inline
BlockContainer <body> at [8,8] [8+0+0 784 0+0+8] [8+0+0 34 0+0+8] children: not-inline
BlockContainer <form#form> at [8,8] [0+0+0 784 0+0+0] [0+0+0 34 0+0+0] children: inline
frag 0 from BlockContainer start: 0, length: 0, rect: [11,11 160x28] baseline: 14.390625
BlockContainer <html> at [0,0] [0+0+0 800 0+0+0] [0+0+0 52 0+0+0] [BFC] children: not-inline
BlockContainer <body> at [8,8] [8+0+0 784 0+0+8] [8+0+0 36 0+0+8] children: not-inline
BlockContainer <form#form> at [8,8] [0+0+0 784 0+0+0] [0+0+0 36 0+0+0] children: inline
frag 0 from BlockContainer start: 0, length: 0, rect: [11,11 160x30] baseline: 14.390625
TextNode <#text> (not painted)
BlockContainer <textarea#textarea> at [11,11] inline-block [0+1+2 160 2+1+0] [0+1+2 28 2+1+0] [BFC] children: not-inline
BlockContainer <textarea#textarea> at [11,11] inline-block [0+1+2 160 2+1+0] [0+1+2 30 2+1+0] [BFC] children: not-inline
BlockContainer <div> at [11,11] [0+0+0 160 0+0+0] [0+0+0 15 0+0+0] children: not-inline
BlockContainer <div> at [11,11] [0+0+0 160 0+0+0] [0+0+0 15 0+0+0] children: inline
frag 0 from TextNode start: 0, length: 14, rect: [11,11 88.109375x15] baseline: 11.390625
"Original value"
TextNode <#text> (not painted)
TextNode <#text> (not painted)
BlockContainer <(anonymous)> at [8,42] [0+0+0 784 0+0+0] [0+0+0 0 0+0+0] children: inline
BlockContainer <(anonymous)> at [8,44] [0+0+0 784 0+0+0] [0+0+0 0 0+0+0] children: inline
TextNode <#text> (not painted)
TextNode <#text> (not painted)
ViewportPaintable (Viewport<#document>) [0,0 800x600]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x50]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x34]
PaintableWithLines (BlockContainer<FORM>#form) [8,8 784x34]
PaintableWithLines (BlockContainer<TEXTAREA>#textarea) [8,8 166x34]
PaintableWithLines (BlockContainer<HTML>) [0,0 800x52]
PaintableWithLines (BlockContainer<BODY>) [8,8 784x36]
PaintableWithLines (BlockContainer<FORM>#form) [8,8 784x36]
PaintableWithLines (BlockContainer<TEXTAREA>#textarea) [8,8 166x36]
PaintableWithLines (BlockContainer<DIV>) [11,11 160x15]
PaintableWithLines (BlockContainer<DIV>) [11,11 160x15]
TextPaintable (TextNode<#text>)
PaintableWithLines (BlockContainer(anonymous)) [8,42 784x0]
PaintableWithLines (BlockContainer(anonymous)) [8,44 784x0]
SC for Viewport<#document> [0,0 800x600] [children: 1] (z-index: auto)
SC for BlockContainer<HTML> [0,0 800x50] [children: 0] (z-index: auto)
SC for BlockContainer<HTML> [0,0 800x52] [children: 0] (z-index: auto)