/* * Copyright (c) 2024-2026, Sam Atkins * * SPDX-License-Identifier: BSD-2-Clause */ #include "CSSNestedDeclarations.h" #include #include #include #include #include #include namespace Web::CSS { GC_DEFINE_ALLOCATOR(CSSNestedDeclarations); GC::Ref CSSNestedDeclarations::create(JS::Realm& realm, Parser::Parser& parser, Vector const& declarations) { return realm.create(realm, parser.convert_to_style_declaration(declarations)); } GC::Ref CSSNestedDeclarations::create(JS::Realm& realm, CSSStyleProperties& declaration) { return realm.create(realm, declaration); } CSSNestedDeclarations::CSSNestedDeclarations(JS::Realm& realm, CSSStyleProperties& declaration) : CSSRule(realm, Type::NestedDeclarations) , m_declaration(declaration) { m_declaration->set_parent_rule(*this); } void CSSNestedDeclarations::initialize(JS::Realm& realm) { WEB_SET_PROTOTYPE_FOR_INTERFACE(CSSNestedDeclarations); Base::initialize(realm); } void CSSNestedDeclarations::visit_edges(Cell::Visitor& visitor) { Base::visit_edges(visitor); visitor.visit(m_declaration); visitor.visit(m_parent_style_rule); } static SelectorList absolutize_parent_selectors(CSSNestedDeclarations const& nested_declarations) { static SelectorList s_root_selector_list { Selector::create({ Selector::CompoundSelector { .combinator = Selector::Combinator::None, .simple_selectors = { Selector::SimpleSelector { .type = Selector::SimpleSelector::Type::PseudoClass, .value = Selector::SimpleSelector::PseudoClassSelector { .type = PseudoClass::Root, }, }, }, }, }), }; 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(parent_rule)) return parent_style_rule->absolutized_selectors(); if (auto const* parent_scope_rule = as_if(parent_rule)) { // https://drafts.csswg.org/css-cascade-6/#scope-limits // Finding the scoping root(s) auto scoping_root_selector = [&] { // For each element matched by , create a scope using that element as the scoping root. if (auto const& scope_start = parent_scope_rule->start_selectors_for_matching(); scope_start.has_value()) return scope_start.value(); // If no is specified, the scoping root is the parent element of the owner node of the // stylesheet where the @scope rule is defined. // FIXME: This means the scoping root is the `