LibWeb/DOM: Invalidate children with relative font-weight/font-size

`font-weight` and `font-size` both can have keywords that are relative
to their inherited value, and so need recomputing when that changes.

Fixes all but one subtest in font-weight-computed.html, because that
remaining one uses container-query units. No font-size tests seem to be
affected: font-size-computed.html doesn't update the parent element's
`font-size` so this invalidation bug didn't apply.
This commit is contained in:
Sam Atkins 2025-11-20 09:52:17 +00:00 committed by Jelle Raaijmakers
parent 813986237e
commit 29666e1d83
Notes: github-actions[bot] 2025-11-20 11:23:12 +00:00
2 changed files with 53 additions and 44 deletions

View file

@ -830,23 +830,32 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_inherited_style()
CSS::RequiredInvalidationAfterStyleChange invalidation;
HashMap<size_t, RefPtr<CSS::StyleValue const>> old_values_with_relative_units;
HashMap<size_t, RefPtr<CSS::StyleValue const>> property_values_affected_by_inherited_style;
for (auto i = to_underlying(CSS::first_longhand_property_id); i <= to_underlying(CSS::last_longhand_property_id); ++i) {
auto property_id = static_cast<CSS::PropertyID>(i);
// FIXME: We should use the specified value rather than the cascaded value as the cascaded value may include
// unresolved CSS-wide keywords (e.g. 'initial' or 'inherit') rather than the resolved value.
auto const& preabsolutized_value = m_cascaded_properties->property(property_id);
RefPtr old_value = computed_properties->property(property_id);
// FIXME: Consider other style values that rely on relative lengths (e.g. CalculatedStyleValue, StyleValues which contain lengths (e.g. StyleValueList))
// Update property if it uses relative units as it might have been affected by a change in ancestor element style.
if (preabsolutized_value && preabsolutized_value->is_length() && preabsolutized_value->as_length().length().is_font_relative()) {
auto is_inherited = computed_properties->is_property_inherited(property_id);
computed_properties->set_property(property_id, *preabsolutized_value, is_inherited ? CSS::ComputedProperties::Inherited::Yes : CSS::ComputedProperties::Inherited::No);
old_values_with_relative_units.set(i, old_value);
if (preabsolutized_value) {
// A property needs updating if:
// - It uses relative units as it might have been affected by a change in ancestor element style.
// FIXME: Consider other style values that rely on relative lengths (e.g. CalculatedStyleValue,
// StyleValues which contain lengths (e.g. StyleValueList))
// - font-weight is `bolder` or `lighter`
// - font-size is `larger` or `smaller`
// FIXME: Consider any other properties that rely on inherited values for computation.
auto needs_updating = (preabsolutized_value->is_length() && preabsolutized_value->as_length().length().is_font_relative())
|| (property_id == CSS::PropertyID::FontWeight && first_is_one_of(preabsolutized_value->to_keyword(), CSS::Keyword::Bolder, CSS::Keyword::Lighter))
|| (property_id == CSS::PropertyID::FontSize && first_is_one_of(preabsolutized_value->to_keyword(), CSS::Keyword::Larger, CSS::Keyword::Smaller));
if (needs_updating) {
auto is_inherited = computed_properties->is_property_inherited(property_id);
computed_properties->set_property(property_id, *preabsolutized_value, is_inherited ? CSS::ComputedProperties::Inherited::Yes : CSS::ComputedProperties::Inherited::No);
property_values_affected_by_inherited_style.set(i, old_value);
}
}
// FIXME: We should also consider properties which depend on their inherited values for computation (e.g.
// relative font-sizes or font-weights)
if (!computed_properties->is_property_inherited(property_id))
continue;
@ -867,7 +876,7 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_inherited_style()
invalidation |= CSS::compute_property_invalidation(property_id, old_value, new_value);
}
if (invalidation.is_none() && old_values_with_relative_units.is_empty())
if (invalidation.is_none() && property_values_affected_by_inherited_style.is_empty())
return invalidation;
AbstractElement abstract_element { *this };
@ -875,7 +884,7 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_inherited_style()
document().style_computer().compute_font(*computed_properties, abstract_element);
document().style_computer().compute_property_values(*computed_properties, abstract_element);
for (auto [property_id, old_value] : old_values_with_relative_units) {
for (auto const& [property_id, old_value] : property_values_affected_by_inherited_style) {
auto const& new_value = computed_properties->property(static_cast<CSS::PropertyID>(property_id));
invalidation |= CSS::compute_property_invalidation(static_cast<CSS::PropertyID>(property_id), old_value, new_value);
}

View file

@ -2,8 +2,8 @@ Harness status: OK
Found 58 tests
26 Pass
32 Fail
57 Pass
1 Fail
Pass Property font-weight value 'normal'
Pass Property font-weight value 'bold'
Pass Property font-weight value '1'
@ -30,35 +30,35 @@ Pass 100 made bolder computes to 400
Pass 200 made bolder computes to 400
Pass 300 made bolder computes to 400
Pass 349 made bolder computes to 400
Fail 350 made bolder computes to 700
Fail 400 made bolder computes to 700
Fail 500 made bolder computes to 700
Fail 549 made bolder computes to 700
Fail 550 made bolder computes to 900
Fail 600 made bolder computes to 900
Fail 700 made bolder computes to 900
Fail 749 made bolder computes to 900
Fail 750 made bolder computes to 900
Fail 800 made bolder computes to 900
Fail 900 made bolder computes to 900
Fail 950 made bolder computes to 950
Fail 1000 made bolder computes to 1000
Pass 350 made bolder computes to 700
Pass 400 made bolder computes to 700
Pass 500 made bolder computes to 700
Pass 549 made bolder computes to 700
Pass 550 made bolder computes to 900
Pass 600 made bolder computes to 900
Pass 700 made bolder computes to 900
Pass 749 made bolder computes to 900
Pass 750 made bolder computes to 900
Pass 800 made bolder computes to 900
Pass 900 made bolder computes to 900
Pass 950 made bolder computes to 950
Pass 1000 made bolder computes to 1000
Pass 1 made lighter computes to 1
Fail 50 made lighter computes to 50
Fail 100 made lighter computes to 100
Fail 200 made lighter computes to 100
Fail 300 made lighter computes to 100
Fail 349 made lighter computes to 100
Fail 350 made lighter computes to 100
Fail 400 made lighter computes to 100
Fail 500 made lighter computes to 100
Fail 549 made lighter computes to 100
Fail 550 made lighter computes to 400
Fail 600 made lighter computes to 400
Fail 700 made lighter computes to 400
Fail 749 made lighter computes to 400
Fail 750 made lighter computes to 700
Fail 800 made lighter computes to 700
Fail 900 made lighter computes to 700
Fail 950 made lighter computes to 700
Fail 1000 made lighter computes to 700
Pass 50 made lighter computes to 50
Pass 100 made lighter computes to 100
Pass 200 made lighter computes to 100
Pass 300 made lighter computes to 100
Pass 349 made lighter computes to 100
Pass 350 made lighter computes to 100
Pass 400 made lighter computes to 100
Pass 500 made lighter computes to 100
Pass 549 made lighter computes to 100
Pass 550 made lighter computes to 400
Pass 600 made lighter computes to 400
Pass 700 made lighter computes to 400
Pass 749 made lighter computes to 400
Pass 750 made lighter computes to 700
Pass 800 made lighter computes to 700
Pass 900 made lighter computes to 700
Pass 950 made lighter computes to 700
Pass 1000 made lighter computes to 700