LibWeb/CSS: Ask CSSNestedDeclarations for selectors and layer directly

This is preparation for nested declarations inside `@scope`. User code
no longer makes assumptions about there being a style rule parent, as
there may not be one.

We cache the absolutized selectors because `@scope` will require us to
modify the parent's selectors instead of using them directly.
This commit is contained in:
Sam Atkins 2026-05-21 13:34:03 +01:00
parent 43f4ecde5c
commit c67172f368
4 changed files with 30 additions and 5 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2024-2025, Sam Atkins <sam@ladybird.org>
* Copyright (c) 2024-2026, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -45,6 +45,27 @@ void CSSNestedDeclarations::visit_edges(Cell::Visitor& visitor)
visitor.visit(m_parent_style_rule);
}
static SelectorList absolutize_parent_selectors(CSSNestedDeclarations const& nested_declarations)
{
for (auto const* parent_rule = nested_declarations.parent_rule(); parent_rule; parent_rule = parent_rule->parent_rule()) {
if (auto const* parent_style_rule = as_if<CSSStyleRule>(parent_rule))
return parent_style_rule->absolutized_selectors();
}
// NB: CSSNestedDeclarations can only exist inside an ancestor rule that provides selectors, so we cannot get here
// unless something has gone very wrong.
VERIFY_NOT_REACHED();
}
SelectorList const& CSSNestedDeclarations::absolutized_selectors() const
{
if (m_cached_absolutized_selectors.has_value())
return m_cached_absolutized_selectors.value();
m_cached_absolutized_selectors = absolutize_parent_selectors(*this);
return m_cached_absolutized_selectors.value();
}
GC::Ref<CSSStyleProperties> CSSNestedDeclarations::style()
{
return m_declaration;
@ -79,6 +100,7 @@ void CSSNestedDeclarations::clear_caches()
{
Base::clear_caches();
m_parent_style_rule = nullptr;
m_cached_absolutized_selectors.clear();
}
void CSSNestedDeclarations::dump(StringBuilder& builder, int indent_levels) const

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2024-2025, Sam Atkins <sam@ladybird.org>
* Copyright (c) 2024-2026, Sam Atkins <sam@ladybird.org>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
@ -22,6 +22,8 @@ public:
virtual ~CSSNestedDeclarations() override = default;
SelectorList const& absolutized_selectors() const;
[[nodiscard]] FlyString const& qualified_layer_name() const { return parent_layer_internal_qualified_name(); }
CSSStyleProperties const& declaration() const { return m_declaration; }
GC::Ref<CSSStyleProperties> style();
@ -39,6 +41,7 @@ private:
GC::Ref<CSSStyleProperties> m_declaration;
GC::Ptr<CSSStyleRule const> mutable m_parent_style_rule;
mutable Optional<SelectorList> m_cached_absolutized_selectors;
};
template<>

View file

@ -109,7 +109,7 @@ SelectorList const& MatchingRule::absolutized_selectors() const
if (rule->type() == CSSRule::Type::Style)
return static_cast<CSSStyleRule const&>(*rule).absolutized_selectors();
if (rule->type() == CSSRule::Type::NestedDeclarations)
return static_cast<CSSNestedDeclarations const&>(*rule).parent_style_rule().absolutized_selectors();
return static_cast<CSSNestedDeclarations const&>(*rule).absolutized_selectors();
VERIFY_NOT_REACHED();
}
@ -118,7 +118,7 @@ FlyString const& MatchingRule::qualified_layer_name() const
if (rule->type() == CSSRule::Type::Style)
return static_cast<CSSStyleRule const&>(*rule).qualified_layer_name();
if (rule->type() == CSSRule::Type::NestedDeclarations)
return static_cast<CSSNestedDeclarations const&>(*rule).parent_style_rule().qualified_layer_name();
return static_cast<CSSNestedDeclarations const&>(*rule).qualified_layer_name();
VERIFY_NOT_REACHED();
}

View file

@ -364,7 +364,7 @@ void StyleScope::make_rule_cache_for_cascade_origin(CascadeOrigin cascade_origin
if (rule.type() == CSSRule::Type::Style)
return static_cast<CSSStyleRule const&>(rule).absolutized_selectors();
if (rule.type() == CSSRule::Type::NestedDeclarations)
return static_cast<CSSNestedDeclarations const&>(rule).parent_style_rule().absolutized_selectors();
return static_cast<CSSNestedDeclarations const&>(rule).absolutized_selectors();
VERIFY_NOT_REACHED();
}();