mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-10-24 00:49:46 +00:00
LibWeb: Compute and propagate tree-counting function resolution context
Tree counting functions should be resolved at style computation time - to do this we will need to know the element's sibling count and index. This commit computes that information and propagates it to the various `StyleValue::to_computed_value` methods.
This commit is contained in:
parent
fd31fbd84b
commit
9cd23e3ae5
Notes:
github-actions[bot]
2025-10-20 15:13:50 +00:00
Author: https://github.com/Calme1709
Commit: 9cd23e3ae5
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/6426
Reviewed-by: https://github.com/AtkinsSJ ✅
9 changed files with 78 additions and 12 deletions
|
|
@ -19,12 +19,14 @@ struct CalculationResolutionContext {
|
||||||
|
|
||||||
PercentageBasis percentage_basis {};
|
PercentageBasis percentage_basis {};
|
||||||
Optional<Length::ResolutionContext> length_resolution_context {};
|
Optional<Length::ResolutionContext> length_resolution_context {};
|
||||||
|
Optional<TreeCountingFunctionResolutionContext> tree_counting_function_resolution_context {};
|
||||||
|
|
||||||
static CalculationResolutionContext from_computation_context(ComputationContext const& computation_context, PercentageBasis percentage_basis = {})
|
static CalculationResolutionContext from_computation_context(ComputationContext const& computation_context, PercentageBasis percentage_basis = {})
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
.percentage_basis = percentage_basis,
|
.percentage_basis = percentage_basis,
|
||||||
.length_resolution_context = computation_context.length_resolution_context,
|
.length_resolution_context = computation_context.length_resolution_context,
|
||||||
|
.tree_counting_function_resolution_context = computation_context.tree_counting_function_resolution_context
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1068,10 +1068,12 @@ 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 const& inheritance_parent = abstract_element.element_to_inherit_style_from();
|
||||||
auto inheritance_parent_has_computed_properties = inheritance_parent.has_value() && inheritance_parent->computed_properties();
|
auto inheritance_parent_has_computed_properties = inheritance_parent.has_value() && inheritance_parent->computed_properties();
|
||||||
ComputationContext font_computation_context {
|
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())
|
.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
|
||||||
};
|
};
|
||||||
|
|
||||||
if (auto const& font_size_specified_value = specified_values.get(PropertyID::FontSize); font_size_specified_value.has_value()) {
|
if (auto const& font_size_specified_value = specified_values.get(PropertyID::FontSize); font_size_specified_value.has_value()) {
|
||||||
|
|
@ -1115,7 +1117,8 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element
|
||||||
computed_properties.font_size(),
|
computed_properties.font_size(),
|
||||||
computed_properties.first_available_computed_font().pixel_metrics(),
|
computed_properties.first_available_computed_font().pixel_metrics(),
|
||||||
inheritance_parent_has_computed_properties ? inheritance_parent->computed_properties()->line_height() : InitialValues::line_height() },
|
inheritance_parent_has_computed_properties ? inheritance_parent->computed_properties()->line_height() : InitialValues::line_height() },
|
||||||
.root_font_metrics = m_root_element_font_metrics }
|
.root_font_metrics = m_root_element_font_metrics },
|
||||||
|
.tree_counting_function_resolution_context = tree_counting_function_resolution_context
|
||||||
};
|
};
|
||||||
|
|
||||||
result.set(PropertyID::LineHeight, compute_line_height(*line_height_specified_value.value(), line_height_computation_context));
|
result.set(PropertyID::LineHeight, compute_line_height(*line_height_specified_value.value(), line_height_computation_context));
|
||||||
|
|
@ -1126,6 +1129,7 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element
|
||||||
.viewport_rect = viewport_rect(),
|
.viewport_rect = viewport_rect(),
|
||||||
.font_metrics = font_metrics,
|
.font_metrics = font_metrics,
|
||||||
.root_font_metrics = m_root_element_font_metrics },
|
.root_font_metrics = m_root_element_font_metrics },
|
||||||
|
.tree_counting_function_resolution_context = tree_counting_function_resolution_context
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE: This doesn't necessarily return the specified value if we reach into computed_properties but that
|
// NOTE: This doesn't necessarily return the specified value if we reach into computed_properties but that
|
||||||
|
|
@ -2031,8 +2035,12 @@ 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_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 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 {
|
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())
|
.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
|
||||||
};
|
};
|
||||||
|
|
||||||
auto const& font_size_specified_value = style.property(PropertyID::FontSize, ComputedProperties::WithAnimationsApplied::No);
|
auto const& font_size_specified_value = style.property(PropertyID::FontSize, ComputedProperties::WithAnimationsApplied::No);
|
||||||
|
|
@ -2086,7 +2094,8 @@ void StyleComputer::compute_font(ComputedProperties& style, Optional<DOM::Abstra
|
||||||
.viewport_rect = viewport_rect(),
|
.viewport_rect = viewport_rect(),
|
||||||
.font_metrics = line_height_font_metrics,
|
.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,
|
.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
|
||||||
};
|
};
|
||||||
|
|
||||||
auto const& line_height_specified_value = style.property(CSS::PropertyID::LineHeight, ComputedProperties::WithAnimationsApplied::No);
|
auto const& line_height_specified_value = style.property(CSS::PropertyID::LineHeight, ComputedProperties::WithAnimationsApplied::No);
|
||||||
|
|
@ -2147,7 +2156,7 @@ Gfx::Font const& StyleComputer::initial_font() const
|
||||||
return font;
|
return font;
|
||||||
}
|
}
|
||||||
|
|
||||||
void StyleComputer::compute_property_values(ComputedProperties& style) const
|
void StyleComputer::compute_property_values(ComputedProperties& style, Optional<DOM::AbstractElement> abstract_element) const
|
||||||
{
|
{
|
||||||
Length::FontMetrics font_metrics {
|
Length::FontMetrics font_metrics {
|
||||||
style.font_size(),
|
style.font_size(),
|
||||||
|
|
@ -2161,6 +2170,7 @@ void StyleComputer::compute_property_values(ComputedProperties& style) const
|
||||||
.font_metrics = font_metrics,
|
.font_metrics = font_metrics,
|
||||||
.root_font_metrics = m_root_element_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 })
|
||||||
};
|
};
|
||||||
|
|
||||||
// NOTE: This doesn't necessarily return the specified value if we have already computed this property but that
|
// NOTE: This doesn't necessarily return the specified value if we have already computed this property but that
|
||||||
|
|
@ -2392,7 +2402,7 @@ GC::Ref<ComputedProperties> StyleComputer::create_document_style() const
|
||||||
|
|
||||||
compute_math_depth(style, {});
|
compute_math_depth(style, {});
|
||||||
compute_font(style, {});
|
compute_font(style, {});
|
||||||
compute_property_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::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::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)));
|
style->set_property(CSS::PropertyID::Display, CSS::DisplayStyleValue::create(CSS::Display::from_short(CSS::Display::Short::Block)));
|
||||||
|
|
@ -2643,7 +2653,7 @@ GC::Ref<ComputedProperties> StyleComputer::compute_properties(DOM::AbstractEleme
|
||||||
compute_font(computed_style, abstract_element);
|
compute_font(computed_style, abstract_element);
|
||||||
|
|
||||||
// 4. Convert properties into their computed forms
|
// 4. Convert properties into their computed forms
|
||||||
compute_property_values(computed_style);
|
compute_property_values(computed_style, abstract_element);
|
||||||
|
|
||||||
// FIXME: Support multiple entries for `animation` properties
|
// FIXME: Support multiple entries for `animation` properties
|
||||||
// Animation declarations [css-animations-2]
|
// Animation declarations [css-animations-2]
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,7 @@ public:
|
||||||
|
|
||||||
[[nodiscard]] GC::Ref<ComputedProperties> compute_properties(DOM::AbstractElement, CascadedProperties&) const;
|
[[nodiscard]] GC::Ref<ComputedProperties> compute_properties(DOM::AbstractElement, CascadedProperties&) const;
|
||||||
|
|
||||||
void compute_property_values(ComputedProperties&) const;
|
void compute_property_values(ComputedProperties&, Optional<DOM::AbstractElement>) const;
|
||||||
void compute_font(ComputedProperties&, Optional<DOM::AbstractElement>) const;
|
void compute_font(ComputedProperties&, Optional<DOM::AbstractElement>) const;
|
||||||
|
|
||||||
[[nodiscard]] inline bool should_reject_with_ancestor_filter(Selector const&) const;
|
[[nodiscard]] inline bool should_reject_with_ancestor_filter(Selector const&) const;
|
||||||
|
|
|
||||||
|
|
@ -10,8 +10,14 @@
|
||||||
|
|
||||||
namespace Web::CSS {
|
namespace Web::CSS {
|
||||||
|
|
||||||
|
struct TreeCountingFunctionResolutionContext {
|
||||||
|
size_t sibling_count;
|
||||||
|
size_t sibling_index;
|
||||||
|
};
|
||||||
|
|
||||||
struct ComputationContext {
|
struct ComputationContext {
|
||||||
Length::ResolutionContext length_resolution_context;
|
Length::ResolutionContext length_resolution_context;
|
||||||
|
Optional<TreeCountingFunctionResolutionContext> tree_counting_function_resolution_context {};
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,42 @@ Document& AbstractElement::document() const
|
||||||
return m_element->document();
|
return m_element->document();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CSS::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
|
||||||
|
// the originating element. It follows that for nested pseudo elements the resolution will recursively walk
|
||||||
|
// the originating elements until a real element is found.
|
||||||
|
|
||||||
|
// FIXME: A tree counting function is a tree-scoped reference where it references an implicit tree-scoped name for
|
||||||
|
// the element it resolves against. This is done to not leak tree information to an outer tree. A tree
|
||||||
|
// counting function that is scoped to an outer tree relative to the element it resolves against, will alway
|
||||||
|
// resolve to 0.
|
||||||
|
auto const& element_to_resolve_tree_counting_function_against = element();
|
||||||
|
|
||||||
|
// The sibling-count() functional notation represents, as an <integer>, the total number of child elements in the
|
||||||
|
// parent of the element on which the notation is used.
|
||||||
|
auto const& parent = element_to_resolve_tree_counting_function_against.parent_element();
|
||||||
|
|
||||||
|
// If there is no parent we are the root node
|
||||||
|
if (!parent)
|
||||||
|
return { .sibling_count = 1, .sibling_index = 1 };
|
||||||
|
|
||||||
|
size_t count = 0;
|
||||||
|
size_t index = 0;
|
||||||
|
|
||||||
|
for (auto const* child = parent->first_child_of_type<DOM::Element>(); child; child = child->next_element_sibling()) {
|
||||||
|
++count;
|
||||||
|
if (child == &element_to_resolve_tree_counting_function_against)
|
||||||
|
index = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
.sibling_count = count,
|
||||||
|
.sibling_index = index
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
GC::Ptr<Layout::NodeWithStyle> AbstractElement::layout_node()
|
GC::Ptr<Layout::NodeWithStyle> AbstractElement::layout_node()
|
||||||
{
|
{
|
||||||
if (m_pseudo_element.has_value())
|
if (m_pseudo_element.has_value())
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,8 @@ public:
|
||||||
GC::Ptr<Layout::NodeWithStyle> layout_node();
|
GC::Ptr<Layout::NodeWithStyle> layout_node();
|
||||||
GC::Ptr<Layout::NodeWithStyle const> layout_node() const { return const_cast<AbstractElement*>(this)->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;
|
||||||
|
|
||||||
GC::Ptr<Element const> parent_element() const;
|
GC::Ptr<Element const> parent_element() const;
|
||||||
Optional<AbstractElement> element_to_inherit_style_from() const;
|
Optional<AbstractElement> element_to_inherit_style_from() const;
|
||||||
Optional<AbstractElement> previous_in_tree_order() { return walk_layout_tree(WalkMethod::Previous); }
|
Optional<AbstractElement> previous_in_tree_order() { return walk_layout_tree(WalkMethod::Previous); }
|
||||||
|
|
|
||||||
|
|
@ -844,8 +844,10 @@ CSS::RequiredInvalidationAfterStyleChange Element::recompute_inherited_style()
|
||||||
if (invalidation.is_none() && old_values_with_relative_units.is_empty())
|
if (invalidation.is_none() && old_values_with_relative_units.is_empty())
|
||||||
return invalidation;
|
return invalidation;
|
||||||
|
|
||||||
document().style_computer().compute_font(*computed_properties, AbstractElement { *this });
|
AbstractElement abstract_element { *this };
|
||||||
document().style_computer().compute_property_values(*computed_properties);
|
|
||||||
|
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 [property_id, old_value] : old_values_with_relative_units) {
|
||||||
auto const& new_value = computed_properties->property(static_cast<CSS::PropertyID>(property_id));
|
auto const& new_value = computed_properties->property(static_cast<CSS::PropertyID>(property_id));
|
||||||
|
|
|
||||||
|
|
@ -401,6 +401,7 @@ struct CalculationResolutionContext;
|
||||||
struct CSSStyleSheetInit;
|
struct CSSStyleSheetInit;
|
||||||
struct GridRepeatParams;
|
struct GridRepeatParams;
|
||||||
struct StyleSheetIdentifier;
|
struct StyleSheetIdentifier;
|
||||||
|
struct TreeCountingFunctionResolutionContext;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,6 +82,7 @@ public:
|
||||||
// and with system fonts being computed to explicit values.
|
// and with system fonts being computed to explicit values.
|
||||||
// FIXME: with the 'line-height' component forced to 'normal'
|
// FIXME: with the 'line-height' component forced to 'normal'
|
||||||
// FIXME: with the 'font-size' component converted to CSS pixels
|
// FIXME: with the 'font-size' component converted to CSS pixels
|
||||||
|
// FIXME: Disallow tree counting functions if this is an offscreen canvas
|
||||||
auto font_style_value_result = parse_css_value(CSS::Parser::ParsingParams {}, font, CSS::PropertyID::Font);
|
auto font_style_value_result = parse_css_value(CSS::Parser::ParsingParams {}, font, CSS::PropertyID::Font);
|
||||||
|
|
||||||
// If the new value is syntactically incorrect (including using property-independent style sheet syntax like 'inherit' or 'initial'), then it must be ignored, without assigning a new font value.
|
// If the new value is syntactically incorrect (including using property-independent style sheet syntax like 'inherit' or 'initial'), then it must be ignored, without assigning a new font value.
|
||||||
|
|
@ -115,6 +116,7 @@ public:
|
||||||
// FIXME: Investigate whether this is the correct resolution context (i.e. whether we should instead use
|
// FIXME: Investigate whether this is the correct resolution context (i.e. whether we should instead use
|
||||||
// a font-size of 10px) for OffscreenCanvas
|
// a font-size of 10px) for OffscreenCanvas
|
||||||
auto length_resolution_context = CSS::Length::ResolutionContext::for_window(*document->window());
|
auto length_resolution_context = CSS::Length::ResolutionContext::for_window(*document->window());
|
||||||
|
Optional<CSS::TreeCountingFunctionResolutionContext> tree_counting_function_resolution_context;
|
||||||
|
|
||||||
if constexpr (SameAs<CanvasType, HTML::HTMLCanvasElement>) {
|
if constexpr (SameAs<CanvasType, HTML::HTMLCanvasElement>) {
|
||||||
// NOTE: The canvas itself is considered the inheritance parent
|
// NOTE: The canvas itself is considered the inheritance parent
|
||||||
|
|
@ -124,12 +126,17 @@ public:
|
||||||
inherited_math_depth = canvas_element.computed_properties()->math_depth();
|
inherited_math_depth = canvas_element.computed_properties()->math_depth();
|
||||||
inherited_font_size = canvas_element.computed_properties()->font_size();
|
inherited_font_size = canvas_element.computed_properties()->font_size();
|
||||||
inherited_font_weight = canvas_element.computed_properties()->font_weight();
|
inherited_font_weight = canvas_element.computed_properties()->font_weight();
|
||||||
length_resolution_context = CSS::Length::ResolutionContext::for_element(DOM::AbstractElement { canvas_element });
|
|
||||||
|
DOM::AbstractElement abstract_element { canvas_element };
|
||||||
|
|
||||||
|
length_resolution_context = CSS::Length::ResolutionContext::for_element(abstract_element);
|
||||||
|
tree_counting_function_resolution_context = abstract_element.tree_counting_function_resolution_context();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
CSS::ComputationContext computation_context {
|
CSS::ComputationContext computation_context {
|
||||||
.length_resolution_context = length_resolution_context
|
.length_resolution_context = length_resolution_context,
|
||||||
|
.tree_counting_function_resolution_context = tree_counting_function_resolution_context
|
||||||
};
|
};
|
||||||
|
|
||||||
auto const& computed_font_size = CSS::StyleComputer::compute_font_size(font_size, computed_math_depth, inherited_font_size, inherited_math_depth, computation_context);
|
auto const& computed_font_size = CSS::StyleComputer::compute_font_size(font_size, computed_math_depth, inherited_font_size, inherited_math_depth, computation_context);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue