/* * Copyright (c) 2025, Andreas Kling * * SPDX-License-Identifier: BSD-2-Clause */ #pragma once #include #include #include #include #include #include #include #include #include #include namespace Web::CSS { struct MatchingRule { GC::Ptr shadow_root; GC::Ptr rule; // Either CSSStyleRule or CSSNestedDeclarations GC::Ptr sheet; Optional default_namespace; Selector const& selector; size_t style_sheet_index { 0 }; size_t rule_index { 0 }; u32 specificity { 0 }; CascadeOrigin cascade_origin; bool contains_pseudo_element { false }; bool slotted { false }; // Helpers to deal with the fact that `rule` might be a CSSStyleRule or a CSSNestedDeclarations CSSStyleProperties const& declaration() const; SelectorList const& absolutized_selectors() const; FlyString const& qualified_layer_name() const; }; struct RuleCache { HashMap> rules_by_id; HashMap> rules_by_class; HashMap> rules_by_tag_name; HashMap, AK::ASCIICaseInsensitiveFlyStringTraits> rules_by_attribute_name; Array, to_underlying(CSS::PseudoElement::KnownPseudoElementCount)> rules_by_pseudo_element; Vector root_rules; Vector slotted_rules; Vector other_rules; HashMap> rules_by_animation_keyframes; void add_rule(MatchingRule const&, Optional, bool contains_root_pseudo_class); void for_each_matching_rules(DOM::AbstractElement, Function const&)> callback) const; }; struct RuleCaches { RuleCache main; HashMap> by_layer; }; struct SelectorInsights { bool has_has_selectors { false }; }; class StyleScope { public: explicit StyleScope(GC::Ref); DOM::Node& node() const { return m_node; } DOM::Document& document() const; RuleCaches const& author_rule_cache() const { return *m_author_rule_cache; } RuleCaches const& user_rule_cache() const { return *m_user_rule_cache; } RuleCaches const& user_agent_rule_cache() const { return *m_user_agent_rule_cache; } [[nodiscard]] bool has_valid_rule_cache() const { return m_author_rule_cache; } void invalidate_rule_cache(); [[nodiscard]] RuleCache const& get_pseudo_class_rule_cache(PseudoClass) const; template void for_each_stylesheet(CascadeOrigin, Callback) const; void make_rule_cache_for_cascade_origin(CascadeOrigin, SelectorInsights&); void build_rule_cache(); void build_rule_cache_if_needed() const; static void collect_selector_insights(Selector const&, SelectorInsights&); void build_qualified_layer_names_cache(); [[nodiscard]] bool may_have_has_selectors() const; [[nodiscard]] bool have_has_selectors() const; void for_each_active_css_style_sheet(Function&& callback) const; void invalidate_style_of_elements_affected_by_has(); void schedule_ancestors_style_invalidation_due_to_presence_of_has(DOM::Node& node) { m_pending_nodes_for_style_invalidation_due_to_presence_of_has.set(node); } void visit_edges(GC::Cell::Visitor&); Vector m_qualified_layer_names_in_order; OwnPtr m_selector_insights; Array, to_underlying(PseudoClass::__Count)> m_pseudo_class_rule_cache; OwnPtr m_style_invalidation_data; OwnPtr m_author_rule_cache; OwnPtr m_user_rule_cache; OwnPtr m_user_agent_rule_cache; GC::Ptr m_user_style_sheet; HashTable> m_pending_nodes_for_style_invalidation_due_to_presence_of_has; GC::Ref m_node; }; }