LibWeb: Pass AbstractElement in ComputationContext

Passing the `AbstractElement` rather than the
`TreeCountingFunctionResolutionContext` allows us to only compute the
resolution context when necessary (i.e. when we actually need to resolve
a tree counting function)
This commit is contained in:
Callum Law 2025-10-22 00:06:38 +13:00 committed by Jelle Raaijmakers
parent a4184fda1f
commit 5b9a36b172
9 changed files with 28 additions and 31 deletions

View File

@ -19,14 +19,14 @@ struct CalculationResolutionContext {
PercentageBasis percentage_basis {};
Optional<Length::ResolutionContext> length_resolution_context {};
Optional<TreeCountingFunctionResolutionContext> tree_counting_function_resolution_context {};
Optional<DOM::AbstractElement> abstract_element {};
static CalculationResolutionContext from_computation_context(ComputationContext const& computation_context, PercentageBasis percentage_basis = {})
{
return {
.percentage_basis = percentage_basis,
.length_resolution_context = computation_context.length_resolution_context,
.tree_counting_function_resolution_context = computation_context.tree_counting_function_resolution_context
.abstract_element = computation_context.abstract_element
};
}
};

View File

@ -1078,12 +1078,11 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element
});
}
auto tree_counting_function_resolution_context = abstract_element.tree_counting_function_resolution_context();
auto const& inheritance_parent = abstract_element.element_to_inherit_style_from();
auto inheritance_parent_has_computed_properties = inheritance_parent.has_value() && inheritance_parent->computed_properties();
ComputationContext font_computation_context {
.length_resolution_context = inheritance_parent_has_computed_properties ? Length::ResolutionContext::for_element(inheritance_parent.value()) : Length::ResolutionContext::for_window(*m_document->window()),
.tree_counting_function_resolution_context = tree_counting_function_resolution_context
.abstract_element = abstract_element
};
if (auto const& font_size_specified_value = specified_values.get(PropertyID::FontSize); font_size_specified_value.has_value()) {
@ -1140,7 +1139,7 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element
computed_properties.first_available_computed_font().pixel_metrics(),
inheritance_parent_has_computed_properties ? inheritance_parent->computed_properties()->line_height() : InitialValues::line_height() },
.root_font_metrics = m_root_element_font_metrics },
.tree_counting_function_resolution_context = tree_counting_function_resolution_context
.abstract_element = abstract_element
};
PropertyComputationDependencies property_computation_dependencies;
@ -1153,7 +1152,7 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element
.viewport_rect = viewport_rect(),
.font_metrics = font_metrics,
.root_font_metrics = m_root_element_font_metrics },
.tree_counting_function_resolution_context = tree_counting_function_resolution_context
.abstract_element = abstract_element
};
// NOTE: This doesn't necessarily return the specified value if we reach into computed_properties but that
@ -2062,11 +2061,9 @@ void StyleComputer::compute_font(ComputedProperties& style, Optional<DOM::Abstra
auto inherited_font_size = inheritance_parent_has_computed_properties ? inheritance_parent->computed_properties()->font_size() : InitialValues::font_size();
auto inherited_math_depth = inheritance_parent_has_computed_properties ? inheritance_parent->computed_properties()->math_depth() : InitialValues::math_depth();
auto tree_counting_function_resolution_context = abstract_element.map([](auto abstract_element) { return abstract_element.tree_counting_function_resolution_context(); }).value_or({ .sibling_count = 1, .sibling_index = 1 });
ComputationContext font_computation_context {
.length_resolution_context = inheritance_parent_has_computed_properties ? Length::ResolutionContext::for_element(inheritance_parent.value()) : Length::ResolutionContext::for_window(*m_document->window()),
.tree_counting_function_resolution_context = tree_counting_function_resolution_context
.abstract_element = abstract_element
};
auto const& font_size_specified_value = style.property(PropertyID::FontSize, ComputedProperties::WithAnimationsApplied::No);
@ -2129,7 +2126,7 @@ void StyleComputer::compute_font(ComputedProperties& style, Optional<DOM::Abstra
.font_metrics = line_height_font_metrics,
.root_font_metrics = abstract_element.has_value() && is<HTML::HTMLHtmlElement>(abstract_element->element()) ? line_height_font_metrics : m_root_element_font_metrics,
},
.tree_counting_function_resolution_context = tree_counting_function_resolution_context
.abstract_element = abstract_element
};
auto const& line_height_specified_value = style.property(CSS::PropertyID::LineHeight, ComputedProperties::WithAnimationsApplied::No);
@ -2206,7 +2203,7 @@ void StyleComputer::compute_property_values(ComputedProperties& style, Optional<
.font_metrics = font_metrics,
.root_font_metrics = m_root_element_font_metrics,
},
.tree_counting_function_resolution_context = abstract_element.map([](auto abstract_element) { return abstract_element.tree_counting_function_resolution_context(); }).value_or({ .sibling_count = 1, .sibling_index = 1 })
.abstract_element = abstract_element
};
// NOTE: This doesn't necessarily return the specified value if we have already computed this property but that

View File

@ -7,17 +7,13 @@
#pragma once
#include <LibWeb/CSS/Length.h>
#include <LibWeb/DOM/AbstractElement.h>
namespace Web::CSS {
struct TreeCountingFunctionResolutionContext {
size_t sibling_count;
size_t sibling_index;
};
struct ComputationContext {
Length::ResolutionContext length_resolution_context;
Optional<TreeCountingFunctionResolutionContext> tree_counting_function_resolution_context {};
Optional<DOM::AbstractElement> abstract_element {};
};
}

View File

@ -23,10 +23,12 @@ String TreeCountingFunctionStyleValue::to_string(SerializationMode) const
VERIFY_NOT_REACHED();
}
size_t TreeCountingFunctionStyleValue::resolve(TreeCountingFunctionResolutionContext const& tree_counting_function_resolution_context, PropertyComputationDependencies& property_computation_dependencies) const
size_t TreeCountingFunctionStyleValue::resolve(DOM::AbstractElement const& abstract_element, PropertyComputationDependencies& property_computation_dependencies) const
{
property_computation_dependencies.tree_counting_function = true;
auto tree_counting_function_resolution_context = abstract_element.tree_counting_function_resolution_context();
switch (m_function) {
case TreeCountingFunction::SiblingCount:
return tree_counting_function_resolution_context.sibling_count;
@ -39,20 +41,20 @@ size_t TreeCountingFunctionStyleValue::resolve(TreeCountingFunctionResolutionCon
RefPtr<CalculationNode const> TreeCountingFunctionStyleValue::resolve_to_calculation_node(CalculationContext const& calculation_context, CalculationResolutionContext const& calculation_resolution_context, PropertyComputationDependencies* property_computation_dependencies) const
{
if (!calculation_resolution_context.tree_counting_function_resolution_context.has_value())
if (!calculation_resolution_context.abstract_element.has_value())
return nullptr;
VERIFY(property_computation_dependencies);
return NumericCalculationNode::create(Number { Number::Type::Number, static_cast<double>(resolve(calculation_resolution_context.tree_counting_function_resolution_context.value(), *property_computation_dependencies)) }, calculation_context);
return NumericCalculationNode::create(Number { Number::Type::Number, static_cast<double>(resolve(calculation_resolution_context.abstract_element.value(), *property_computation_dependencies)) }, calculation_context);
}
ValueComparingNonnullRefPtr<StyleValue const> TreeCountingFunctionStyleValue::absolutized(ComputationContext const& computation_context, PropertyComputationDependencies& property_computation_dependencies) const
{
// FIXME: We should clamp this value in case it falls outside the valid range for the context it is in
VERIFY(computation_context.tree_counting_function_resolution_context.has_value());
VERIFY(computation_context.abstract_element.has_value());
size_t value = resolve(computation_context.tree_counting_function_resolution_context.value(), property_computation_dependencies);
size_t value = resolve(computation_context.abstract_element.value(), property_computation_dependencies);
switch (m_computed_type) {
case ComputedType::Integer:

View File

@ -30,7 +30,7 @@ public:
virtual String to_string(SerializationMode) const override;
size_t resolve(TreeCountingFunctionResolutionContext const&, PropertyComputationDependencies&) const;
size_t resolve(DOM::AbstractElement const&, PropertyComputationDependencies&) const;
virtual RefPtr<CalculationNode const> resolve_to_calculation_node(CalculationContext const&, CalculationResolutionContext const&, PropertyComputationDependencies*) const override;
virtual ValueComparingNonnullRefPtr<StyleValue const> absolutized(ComputationContext const&, PropertyComputationDependencies&) const override;

View File

@ -27,7 +27,7 @@ Document& AbstractElement::document() const
return m_element->document();
}
CSS::TreeCountingFunctionResolutionContext AbstractElement::tree_counting_function_resolution_context() const
AbstractElement::TreeCountingFunctionResolutionContext AbstractElement::tree_counting_function_resolution_context() const
{
// FIXME: When used on an element-backed pseudo-element which is also a real element, the tree counting functions
// resolve for that real element. For other pseudo elements, they resolve as if they were resolved against

View File

@ -27,7 +27,11 @@ public:
GC::Ptr<Layout::NodeWithStyle> layout_node();
GC::Ptr<Layout::NodeWithStyle const> layout_node() const { return const_cast<AbstractElement*>(this)->layout_node(); }
CSS::TreeCountingFunctionResolutionContext tree_counting_function_resolution_context() const;
struct TreeCountingFunctionResolutionContext {
size_t sibling_count;
size_t sibling_index;
};
TreeCountingFunctionResolutionContext tree_counting_function_resolution_context() const;
GC::Ptr<Element const> parent_element() const;
Optional<AbstractElement> element_to_inherit_style_from() const;

View File

@ -402,7 +402,6 @@ struct CalculationResolutionContext;
struct CSSStyleSheetInit;
struct GridRepeatParams;
struct StyleSheetIdentifier;
struct TreeCountingFunctionResolutionContext;
}

View File

@ -116,7 +116,7 @@ public:
// FIXME: Investigate whether this is the correct resolution context (i.e. whether we should instead use
// a font-size of 10px) for OffscreenCanvas
auto length_resolution_context = CSS::Length::ResolutionContext::for_window(*document->window());
Optional<CSS::TreeCountingFunctionResolutionContext> tree_counting_function_resolution_context;
Optional<DOM::AbstractElement> abstract_element;
if constexpr (SameAs<CanvasType, HTML::HTMLCanvasElement>) {
// NOTE: The canvas itself is considered the inheritance parent
@ -127,16 +127,15 @@ public:
inherited_font_size = canvas_element.computed_properties()->font_size();
inherited_font_weight = canvas_element.computed_properties()->font_weight();
DOM::AbstractElement abstract_element { canvas_element };
abstract_element = DOM::AbstractElement { canvas_element };
length_resolution_context = CSS::Length::ResolutionContext::for_element(abstract_element);
tree_counting_function_resolution_context = abstract_element.tree_counting_function_resolution_context();
length_resolution_context = CSS::Length::ResolutionContext::for_element(abstract_element.value());
}
}
CSS::ComputationContext computation_context {
.length_resolution_context = length_resolution_context,
.tree_counting_function_resolution_context = tree_counting_function_resolution_context
.abstract_element = abstract_element
};
// FIXME: Should font be recomputed on canvas element style change?