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 {};
|
||||
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 = {})
|
||||
{
|
||||
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
|
||||
};
|
||||
}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -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 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())
|
||||
.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()) {
|
||||
|
|
@ -1115,7 +1117,8 @@ void StyleComputer::collect_animation_into(DOM::AbstractElement abstract_element
|
|||
computed_properties.font_size(),
|
||||
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 }
|
||||
.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));
|
||||
|
|
@ -1126,6 +1129,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
|
||||
};
|
||||
|
||||
// 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_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())
|
||||
.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);
|
||||
|
|
@ -2086,7 +2094,8 @@ void StyleComputer::compute_font(ComputedProperties& style, Optional<DOM::Abstra
|
|||
.viewport_rect = viewport_rect(),
|
||||
.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
|
||||
};
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
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 {
|
||||
style.font_size(),
|
||||
|
|
@ -2161,6 +2170,7 @@ void StyleComputer::compute_property_values(ComputedProperties& style) const
|
|||
.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 })
|
||||
};
|
||||
|
||||
// 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_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::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)));
|
||||
|
|
@ -2643,7 +2653,7 @@ GC::Ref<ComputedProperties> StyleComputer::compute_properties(DOM::AbstractEleme
|
|||
compute_font(computed_style, abstract_element);
|
||||
|
||||
// 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
|
||||
// Animation declarations [css-animations-2]
|
||||
|
|
|
|||
|
|
@ -191,7 +191,7 @@ public:
|
|||
|
||||
[[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;
|
||||
|
||||
[[nodiscard]] inline bool should_reject_with_ancestor_filter(Selector const&) const;
|
||||
|
|
|
|||
|
|
@ -10,8 +10,14 @@
|
|||
|
||||
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 {};
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,6 +26,42 @@ Document& AbstractElement::document() const
|
|||
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()
|
||||
{
|
||||
if (m_pseudo_element.has_value())
|
||||
|
|
|
|||
|
|
@ -27,6 +27,8 @@ 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;
|
||||
|
||||
GC::Ptr<Element const> parent_element() const;
|
||||
Optional<AbstractElement> element_to_inherit_style_from() const;
|
||||
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())
|
||||
return invalidation;
|
||||
|
||||
document().style_computer().compute_font(*computed_properties, AbstractElement { *this });
|
||||
document().style_computer().compute_property_values(*computed_properties);
|
||||
AbstractElement abstract_element { *this };
|
||||
|
||||
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) {
|
||||
auto const& new_value = computed_properties->property(static_cast<CSS::PropertyID>(property_id));
|
||||
|
|
|
|||
|
|
@ -401,6 +401,7 @@ struct CalculationResolutionContext;
|
|||
struct CSSStyleSheetInit;
|
||||
struct GridRepeatParams;
|
||||
struct StyleSheetIdentifier;
|
||||
struct TreeCountingFunctionResolutionContext;
|
||||
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -82,6 +82,7 @@ public:
|
|||
// and with system fonts being computed to explicit values.
|
||||
// FIXME: with the 'line-height' component forced to 'normal'
|
||||
// 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);
|
||||
|
||||
// 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
|
||||
// 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;
|
||||
|
||||
if constexpr (SameAs<CanvasType, HTML::HTMLCanvasElement>) {
|
||||
// NOTE: The canvas itself is considered the inheritance parent
|
||||
|
|
@ -124,12 +126,17 @@ public:
|
|||
inherited_math_depth = canvas_element.computed_properties()->math_depth();
|
||||
inherited_font_size = canvas_element.computed_properties()->font_size();
|
||||
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 {
|
||||
.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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue