LibWeb: Resolve more calculated values in ComputedProperties

We simplify these at style computation time so there is no need to
maintain them as {Number|Length}OrCalculated

Reduces the time spent in `Length::ResolutionContext::for_layout_node`
from 3.3% to 0.4% when loading
https://en.wikipedia.org/wiki/2023_in_American_television
This commit is contained in:
Callum Law 2025-11-09 16:28:32 +13:00 committed by Andreas Kling
parent 201803f601
commit 7a5b948b5b
Notes: github-actions[bot] 2025-11-10 11:13:07 +00:00
8 changed files with 33 additions and 54 deletions

View file

@ -494,17 +494,15 @@ StrokeLinejoin ComputedProperties::stroke_linejoin() const
return keyword_to_stroke_linejoin(value.to_keyword()).release_value();
}
NumberOrCalculated ComputedProperties::stroke_miterlimit() const
double ComputedProperties::stroke_miterlimit() const
{
auto const& value = property(PropertyID::StrokeMiterlimit);
if (value.is_calculated()) {
auto const& math_value = value.as_calculated();
VERIFY(math_value.resolves_to_number());
return NumberOrCalculated { math_value };
return value.as_calculated().resolve_number({}).value();
}
return NumberOrCalculated { value.as_number().number() };
return value.as_number().number();
}
float ComputedProperties::stroke_opacity() const
@ -914,23 +912,23 @@ PointerEvents ComputedProperties::pointer_events() const
return keyword_to_pointer_events(value.to_keyword()).release_value();
}
Variant<LengthOrCalculated, NumberOrCalculated> ComputedProperties::tab_size() const
Variant<Length, double> ComputedProperties::tab_size() const
{
auto const& value = property(PropertyID::TabSize);
if (value.is_calculated()) {
auto const& math_value = value.as_calculated();
if (math_value.resolves_to_length()) {
return LengthOrCalculated { math_value };
return math_value.resolve_length({}).value();
}
if (math_value.resolves_to_number()) {
return NumberOrCalculated { math_value };
return math_value.resolve_number({}).value();
}
}
if (value.is_length())
return LengthOrCalculated { value.as_length().length() };
return value.as_length().length();
return NumberOrCalculated { value.as_number().number() };
return value.as_number().number();
}
WordBreak ComputedProperties::word_break() const
@ -1589,7 +1587,7 @@ FontVariantPosition ComputedProperties::font_variant_position() const
return keyword_to_font_variant_position(value.to_keyword()).release_value();
}
Optional<HashMap<FlyString, IntegerOrCalculated>> ComputedProperties::font_feature_settings() const
HashMap<StringView, u8> ComputedProperties::font_feature_settings() const
{
auto const& value = property(PropertyID::FontFeatureSettings);
@ -1598,7 +1596,7 @@ Optional<HashMap<FlyString, IntegerOrCalculated>> ComputedProperties::font_featu
if (value.is_value_list()) {
auto const& feature_tags = value.as_value_list().values();
HashMap<FlyString, IntegerOrCalculated> result;
HashMap<StringView, u8> result;
result.ensure_capacity(feature_tags.size());
for (auto const& tag_value : feature_tags) {
auto const& feature_tag = tag_value->as_open_type_tagged();
@ -1607,7 +1605,7 @@ Optional<HashMap<FlyString, IntegerOrCalculated>> ComputedProperties::font_featu
result.set(feature_tag.tag(), feature_tag.value()->as_integer().integer());
} else {
VERIFY(feature_tag.value()->is_calculated());
result.set(feature_tag.tag(), IntegerOrCalculated { feature_tag.value()->as_calculated() });
result.set(feature_tag.tag(), feature_tag.value()->as_calculated().resolve_integer({}).value());
}
}
return result;

View file

@ -109,7 +109,7 @@ public:
ContentDataAndQuoteNestingLevel content(DOM::AbstractElement&, u32 initial_quote_nesting_level) const;
ContentVisibility content_visibility() const;
Vector<CursorData> cursor() const;
Variant<LengthOrCalculated, NumberOrCalculated> tab_size() const;
Variant<Length, double> tab_size() const;
WhiteSpaceCollapse white_space_collapse() const;
WhiteSpaceTrimData white_space_trim() const;
WordBreak word_break() const;
@ -159,7 +159,7 @@ public:
FontVariantPosition font_variant_position() const;
FontKerning font_kerning() const;
Optional<FlyString> font_language_override() const;
Optional<HashMap<FlyString, IntegerOrCalculated>> font_feature_settings() const;
HashMap<StringView, u8> font_feature_settings() const;
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings() const;
GridTrackSizeList grid_auto_columns() const;
GridTrackSizeList grid_auto_rows() const;
@ -215,7 +215,7 @@ public:
float fill_opacity() const;
StrokeLinecap stroke_linecap() const;
StrokeLinejoin stroke_linejoin() const;
NumberOrCalculated stroke_miterlimit() const;
double stroke_miterlimit() const;
float stroke_opacity() const;
FillRule fill_rule() const;
ClipRule clip_rule() const;

View file

@ -151,7 +151,7 @@ public:
static WordBreak word_break() { return WordBreak::Normal; }
static CSSPixels word_spacing() { return 0; }
static CSSPixels letter_spacing() { return 0; }
static Variant<LengthOrCalculated, NumberOrCalculated> tab_size() { return NumberOrCalculated(8.0f); }
static Variant<Length, double> tab_size() { return 8; }
static TextAlign text_align() { return TextAlign::Start; }
static TextJustify text_justify() { return TextJustify::Auto; }
static Positioning position() { return Positioning::Static; }
@ -495,7 +495,7 @@ public:
Display display() const { return m_noninherited.display; }
Display display_before_box_type_transformation() const { return m_noninherited.display_before_box_type_transformation; }
Optional<int> const& z_index() const { return m_noninherited.z_index; }
Variant<LengthOrCalculated, NumberOrCalculated> tab_size() const { return m_inherited.tab_size; }
Variant<Length, double> tab_size() const { return m_inherited.tab_size; }
TextAlign text_align() const { return m_inherited.text_align; }
TextJustify text_justify() const { return m_inherited.text_justify; }
LengthPercentage const& text_indent() const { return m_inherited.text_indent; }
@ -610,7 +610,7 @@ public:
LengthPercentage const& stroke_dashoffset() const { return m_inherited.stroke_dashoffset; }
StrokeLinecap stroke_linecap() const { return m_inherited.stroke_linecap; }
StrokeLinejoin stroke_linejoin() const { return m_inherited.stroke_linejoin; }
NumberOrCalculated stroke_miterlimit() const { return m_inherited.stroke_miterlimit; }
double stroke_miterlimit() const { return m_inherited.stroke_miterlimit; }
float stroke_opacity() const { return m_inherited.stroke_opacity; }
LengthPercentage const& stroke_width() const { return m_inherited.stroke_width; }
Color stop_color() const { return m_noninherited.stop_color; }
@ -652,7 +652,7 @@ public:
FontVariantPosition font_variant_position() const { return m_inherited.font_variant_position; }
FontKerning font_kerning() const { return m_inherited.font_kerning; }
Optional<FlyString> font_language_override() const { return m_inherited.font_language_override; }
Optional<HashMap<FlyString, IntegerOrCalculated>> font_feature_settings() const { return m_inherited.font_feature_settings; }
HashMap<StringView, u8> font_feature_settings() const { return m_inherited.font_feature_settings; }
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings() const { return m_inherited.font_variation_settings; }
CSSPixels line_height() const { return m_inherited.line_height; }
Time transition_delay() const { return m_noninherited.transition_delay; }
@ -697,7 +697,7 @@ protected:
FontVariantPosition font_variant_position { FontVariantPosition::Normal };
FontKerning font_kerning { InitialValues::font_kerning() };
Optional<FlyString> font_language_override;
Optional<HashMap<FlyString, IntegerOrCalculated>> font_feature_settings;
HashMap<StringView, u8> font_feature_settings;
Optional<HashMap<FlyString, NumberOrCalculated>> font_variation_settings;
CSSPixels line_height { InitialValues::line_height() };
BorderCollapse border_collapse { InitialValues::border_collapse() };
@ -714,7 +714,7 @@ protected:
Vector<CursorData> cursor { InitialValues::cursor() };
ImageRendering image_rendering { InitialValues::image_rendering() };
PointerEvents pointer_events { InitialValues::pointer_events() };
Variant<LengthOrCalculated, NumberOrCalculated> tab_size { InitialValues::tab_size() };
Variant<Length, double> tab_size { InitialValues::tab_size() };
TextAlign text_align { InitialValues::text_align() };
TextJustify text_justify { InitialValues::text_justify() };
TextTransform text_transform { InitialValues::text_transform() };
@ -743,7 +743,7 @@ protected:
LengthPercentage stroke_dashoffset { InitialValues::stroke_dashoffset() };
StrokeLinecap stroke_linecap { InitialValues::stroke_linecap() };
StrokeLinejoin stroke_linejoin { InitialValues::stroke_linejoin() };
NumberOrCalculated stroke_miterlimit { InitialValues::stroke_miterlimit() };
double stroke_miterlimit { InitialValues::stroke_miterlimit() };
float stroke_opacity { InitialValues::stroke_opacity() };
LengthPercentage stroke_width { InitialValues::stroke_width() };
TextAnchor text_anchor { InitialValues::text_anchor() };
@ -909,7 +909,7 @@ public:
void set_font_variant_position(FontVariantPosition font_variant_position) { m_inherited.font_variant_position = font_variant_position; }
void set_font_kerning(FontKerning font_kerning) { m_inherited.font_kerning = font_kerning; }
void set_font_language_override(Optional<FlyString> font_language_override) { m_inherited.font_language_override = move(font_language_override); }
void set_font_feature_settings(Optional<HashMap<FlyString, IntegerOrCalculated>> value) { m_inherited.font_feature_settings = move(value); }
void set_font_feature_settings(HashMap<StringView, u8> value) { m_inherited.font_feature_settings = move(value); }
void set_font_variation_settings(Optional<HashMap<FlyString, NumberOrCalculated>> value) { m_inherited.font_variation_settings = move(value); }
void set_line_height(CSSPixels line_height) { m_inherited.line_height = line_height; }
void set_border_spacing_horizontal(Length border_spacing_horizontal) { m_inherited.border_spacing_horizontal = move(border_spacing_horizontal); }
@ -929,7 +929,7 @@ public:
void set_float(Float value) { m_noninherited.float_ = value; }
void set_clear(Clear value) { m_noninherited.clear = value; }
void set_z_index(Optional<int> value) { m_noninherited.z_index = move(value); }
void set_tab_size(Variant<LengthOrCalculated, NumberOrCalculated> value) { m_inherited.tab_size = move(value); }
void set_tab_size(Variant<Length, double> value) { m_inherited.tab_size = move(value); }
void set_text_align(TextAlign text_align) { m_inherited.text_align = text_align; }
void set_text_justify(TextJustify text_justify) { m_inherited.text_justify = text_justify; }
void set_text_decoration_line(Vector<TextDecorationLine> value) { m_noninherited.text_decoration_line = move(value); }
@ -1067,7 +1067,7 @@ public:
void set_stroke_dashoffset(LengthPercentage value) { m_inherited.stroke_dashoffset = move(value); }
void set_stroke_linecap(StrokeLinecap value) { m_inherited.stroke_linecap = move(value); }
void set_stroke_linejoin(StrokeLinejoin value) { m_inherited.stroke_linejoin = move(value); }
void set_stroke_miterlimit(NumberOrCalculated value) { m_inherited.stroke_miterlimit = move(value); }
void set_stroke_miterlimit(double value) { m_inherited.stroke_miterlimit = value; }
void set_stroke_opacity(float value) { m_inherited.stroke_opacity = value; }
void set_stroke_width(LengthPercentage value) { m_inherited.stroke_width = move(value); }
void set_stop_color(Color value) { m_noninherited.stop_color = value; }

View file

@ -467,14 +467,7 @@ Gfx::ShapeFeatures InlineLevelIterator::create_and_merge_font_features() const
// FIXME 4. Feature settings determined by properties other than font-variant or font-feature-settings. For example, setting a non-default value for the letter-spacing property disables common ligatures.
// 5. Font features implied by the value of font-feature-settings property.
CSS::CalculationResolutionContext calculation_context { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*m_current_node.ptr()) };
auto font_feature_settings = computed_values.font_feature_settings();
if (font_feature_settings.has_value()) {
auto const& feature_settings = font_feature_settings.value();
for (auto const& [key, feature_value] : feature_settings) {
merged_features.set(key, feature_value.resolved(calculation_context).value_or(0));
}
}
merged_features.update(computed_values.font_feature_settings());
Gfx::ShapeFeatures shape_features;
shape_features.ensure_capacity(merged_features.size());
@ -554,18 +547,11 @@ Optional<InlineLevelIterator::Item> InlineLevelIterator::next_without_lookahead(
}
// https://drafts.csswg.org/css-text/#tab-size-property
CSS::CalculationResolutionContext calculation_context { .length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(*text_node) };
auto tab_size = text_node->computed_values().tab_size();
CSSPixels tab_width;
tab_width = tab_size.visit(
[&](CSS::LengthOrCalculated const& t) -> CSSPixels {
return t.resolved(calculation_context)
.map([&](auto& it) { return it.to_px(*text_node); })
.value_or(0);
auto tab_width = text_node->computed_values().tab_size().visit(
[&](CSS::Length const& length) -> CSSPixels {
return length.absolute_length_to_px();
},
[&](CSS::NumberOrCalculated const& n) -> CSSPixels {
auto tab_number = n.resolved(calculation_context).value_or(0);
[&](double tab_number) -> CSSPixels {
return CSSPixels::nearest_value_for(tab_number * (chunk.font->glyph_width(' ') + word_spacing.to_float() + letter_spacing.to_float()));
});

View file

@ -528,8 +528,6 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
if (auto maybe_font_language_override = computed_style.font_language_override(); maybe_font_language_override.has_value())
computed_values.set_font_language_override(maybe_font_language_override.release_value());
if (auto maybe_font_feature_settings = computed_style.font_feature_settings(); maybe_font_feature_settings.has_value())
computed_values.set_font_feature_settings(maybe_font_feature_settings.release_value());
if (auto maybe_font_variant_alternates = computed_style.font_variant_alternates(); maybe_font_variant_alternates.has_value())
computed_values.set_font_variant_alternates(maybe_font_variant_alternates.release_value());
computed_values.set_font_variant_caps(computed_style.font_variant_caps());
@ -540,6 +538,7 @@ void NodeWithStyle::apply_style(CSS::ComputedProperties const& computed_style)
computed_values.set_font_variant_ligatures(maybe_font_variant_ligatures.release_value());
if (auto maybe_font_variant_numeric = computed_style.font_variant_numeric(); maybe_font_variant_numeric.has_value())
computed_values.set_font_variant_numeric(maybe_font_variant_numeric.release_value());
computed_values.set_font_feature_settings(computed_style.font_feature_settings());
computed_values.set_font_variant_position(computed_style.font_variant_position());
if (auto maybe_font_variation_settings = computed_style.font_variation_settings(); maybe_font_variation_settings.has_value())
computed_values.set_font_variation_settings(maybe_font_variation_settings.release_value());

View file

@ -152,11 +152,7 @@ void SVGPathPaintable::paint(DisplayListRecordingContext& context, PaintPhase ph
break;
}
CSS::CalculationResolutionContext calculation_context {
.length_resolution_context = CSS::Length::ResolutionContext::for_layout_node(layout_node()),
};
auto miter_limit = graphics_element.stroke_miterlimit().value_or(CSS::InitialValues::stroke_miterlimit()).resolved(calculation_context).value_or(0);
auto miter_limit = graphics_element.stroke_miterlimit().value_or(0);
auto stroke_opacity = graphics_element.stroke_opacity().value_or(1);
// Note: This is assuming .x_scale() == .y_scale() (which it does currently).

View file

@ -225,7 +225,7 @@ Optional<CSS::StrokeLinejoin> SVGGraphicsElement::stroke_linejoin() const
return layout_node()->computed_values().stroke_linejoin();
}
Optional<CSS::NumberOrCalculated> SVGGraphicsElement::stroke_miterlimit() const
Optional<double> SVGGraphicsElement::stroke_miterlimit() const
{
if (!layout_node())
return {};

View file

@ -44,7 +44,7 @@ public:
CSS::PaintOrderList paint_order() const;
Optional<CSS::StrokeLinecap> stroke_linecap() const;
Optional<CSS::StrokeLinejoin> stroke_linejoin() const;
Optional<CSS::NumberOrCalculated> stroke_miterlimit() const;
Optional<double> stroke_miterlimit() const;
Optional<float> stroke_opacity() const;
Optional<FillRule> fill_rule() const;
Optional<ClipRule> clip_rule() const;