LibWeb: Initial work to store ComputedProperties in computed form

`StyleValue`s stored within `ComputedProperties` should be in their
computed forms, this is for various reasons including:
 - Inheritance should be of computed values
 - Animations should work on computed values
 - Triggering transitions should work on computed values

Currently we store `StyleValue`s in an absolutized version of the
specified value - this is equivalent to the computed form in many cases
which is why this hasn't been causing significant issues but there are
some cases - such as `border-*-width` keywords where this is not the
case.

No functionality change as we are yet to implement any properties
This commit is contained in:
Callum Law 2025-08-26 14:48:47 +12:00 committed by Sam Atkins
commit f9e5332d16
Notes: github-actions[bot] 2025-08-28 08:31:40 +00:00
3 changed files with 43 additions and 10 deletions

View file

@ -1098,7 +1098,7 @@ void StyleComputer::collect_animation_into(DOM::Element& element, Optional<CSS::
};
compute_font(computed_properties, &element, pseudo_element);
absolutize_values(computed_properties);
compute_property_values(computed_properties);
Length::FontMetrics font_metrics {
computed_properties.font_size(),
computed_properties.first_available_computed_font().pixel_metrics()
@ -2149,7 +2149,7 @@ Gfx::Font const& StyleComputer::initial_font() const
return font;
}
void StyleComputer::absolutize_values(ComputedProperties& style) const
void StyleComputer::compute_property_values(ComputedProperties& style) const
{
Length::FontMetrics font_metrics {
style.font_size(),
@ -2169,9 +2169,26 @@ void StyleComputer::absolutize_values(ComputedProperties& style) const
style.set_property(PropertyID::LineHeight, computed_value, is_inherited);
}
style.for_each_property([&](PropertyID property_id, auto& value) {
auto const& absolutized_value = value.absolutized(viewport_rect(), font_metrics, m_root_element_font_metrics);
auto is_inherited = style.is_property_inherited(property_id) ? ComputedProperties::Inherited::Yes : ComputedProperties::Inherited::No;
PropertyValueComputationContext computation_context {
.length_resolution_context = {
.viewport_rect = viewport_rect(),
.font_metrics = font_metrics,
.root_font_metrics = m_root_element_font_metrics,
}
};
// NOTE: This doesn't necessarily return the specified value if we have already computed this property but that
// doesn't matter as a computed value is always valid as a specified value.
Function<NonnullRefPtr<StyleValue const>(PropertyID)> const get_property_specified_value = [&](auto property_id) -> NonnullRefPtr<StyleValue const> {
return style.property(property_id);
};
style.for_each_property([&](PropertyID property_id, auto& specified_value) {
auto const& computed_value = compute_value_of_property(property_id, specified_value, get_property_specified_value, computation_context);
// FIXME: Any required absolutization should be done within compute_value_of_property() - we can remove this once that's implemented.
auto const& absolutized_value = computed_value->absolutized(viewport_rect(), font_metrics, m_root_element_font_metrics);
auto const& is_inherited = style.is_property_inherited(property_id) ? ComputedProperties::Inherited::Yes : ComputedProperties::Inherited::No;
style.set_property(property_id, absolutized_value, is_inherited);
});
@ -2393,7 +2410,7 @@ GC::Ref<ComputedProperties> StyleComputer::create_document_style() const
compute_math_depth(style, {});
compute_font(style, nullptr, {});
absolutize_values(style);
compute_property_values(style);
style->set_property(CSS::PropertyID::Width, CSS::LengthStyleValue::create(CSS::Length::make_px(viewport_rect().width())));
style->set_property(CSS::PropertyID::Height, CSS::LengthStyleValue::create(CSS::Length::make_px(viewport_rect().height())));
style->set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::Block)));
@ -2702,8 +2719,8 @@ GC::Ref<ComputedProperties> StyleComputer::compute_properties(DOM::Element& elem
// 3. Compute the font, since that may be needed for font-relative CSS units
compute_font(computed_style, &element, pseudo_element);
// 4. Absolutize values, turning font/viewport relative lengths into absolute lengths
absolutize_values(computed_style);
// 4. Convert properties into their computed forms
compute_property_values(computed_style);
// 5. Run automatic box type transformations
transform_box_type_if_needed(computed_style, element, pseudo_element);
@ -3157,6 +3174,17 @@ void StyleComputer::compute_custom_properties(ComputedProperties&, DOM::Abstract
abstract_element.set_custom_properties(move(resolved_custom_properties));
}
NonnullRefPtr<StyleValue const> StyleComputer::compute_value_of_property(PropertyID property_id, NonnullRefPtr<StyleValue const> const& specified_value, Function<NonnullRefPtr<StyleValue const>(PropertyID)> const&, PropertyValueComputationContext const&)
{
switch (property_id) {
default:
// FIXME: We should replace this with a VERIFY_NOT_REACHED() once all properties have their own handling.
return specified_value;
}
VERIFY_NOT_REACHED();
}
void StyleComputer::compute_math_depth(ComputedProperties& style, Optional<DOM::AbstractElement> element) const
{
// https://w3c.github.io/mathml-core/#propdef-math-depth

View file

@ -189,13 +189,18 @@ public:
[[nodiscard]] GC::Ref<ComputedProperties> compute_properties(DOM::Element&, Optional<PseudoElement>, CascadedProperties&) const;
void absolutize_values(ComputedProperties&) const;
void compute_property_values(ComputedProperties&) const;
void compute_font(ComputedProperties&, DOM::Element const*, Optional<CSS::PseudoElement>) const;
[[nodiscard]] inline bool should_reject_with_ancestor_filter(Selector const&) const;
static NonnullRefPtr<StyleValue const> compute_value_of_custom_property(DOM::AbstractElement, FlyString const& custom_property, Optional<Parser::GuardedSubstitutionContexts&> = {});
struct PropertyValueComputationContext {
Length::ResolutionContext length_resolution_context;
};
static NonnullRefPtr<StyleValue const> compute_value_of_property(PropertyID, NonnullRefPtr<StyleValue const> const& specified_value, Function<NonnullRefPtr<StyleValue const>(PropertyID)> const& get_property_specified_value, PropertyValueComputationContext const&);
private:
virtual void visit_edges(Visitor&) override;

View file

@ -835,7 +835,7 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_inherited_style()
return invalidation;
document().style_computer().compute_font(*computed_properties, this, {});
document().style_computer().absolutize_values(*computed_properties);
document().style_computer().compute_property_values(*computed_properties);
for (auto [property_id, old_value] : old_values_with_relative_units) {
auto const& new_value = computed_properties->property(static_cast<CSS::PropertyID>(property_id));