LibWeb/CSS: Take AbstractElement in MatchingRule collection

This commit is contained in:
Sam Atkins 2025-09-09 14:01:23 +01:00 committed by Alexander Kalenik
commit acb211174d
Notes: github-actions[bot] 2025-09-11 16:47:48 +00:00
2 changed files with 23 additions and 23 deletions

View file

@ -505,16 +505,16 @@ bool StyleComputer::invalidation_property_used_in_has_selector(InvalidationSet::
return false; return false;
} }
Vector<MatchingRule const*> StyleComputer::collect_matching_rules(DOM::Element const& element, CascadeOrigin cascade_origin, Optional<CSS::PseudoElement> pseudo_element, PseudoClassBitmap& attempted_pseudo_class_matches, Optional<FlyString const> qualified_layer_name) const Vector<MatchingRule const*> StyleComputer::collect_matching_rules(DOM::AbstractElement abstract_element, CascadeOrigin cascade_origin, PseudoClassBitmap& attempted_pseudo_class_matches, Optional<FlyString const> qualified_layer_name) const
{ {
auto const& root_node = element.root(); auto const& root_node = abstract_element.element().root();
auto shadow_root = as_if<DOM::ShadowRoot>(root_node); auto shadow_root = as_if<DOM::ShadowRoot>(root_node);
auto element_shadow_root = element.shadow_root(); auto element_shadow_root = abstract_element.element().shadow_root();
auto const& element_namespace_uri = element.namespace_uri(); auto const& element_namespace_uri = abstract_element.element().namespace_uri();
GC::Ptr<DOM::Element const> shadow_host; GC::Ptr<DOM::Element const> shadow_host;
if (element_shadow_root) if (element_shadow_root)
shadow_host = element; shadow_host = abstract_element.element();
else if (shadow_root) else if (shadow_root)
shadow_host = shadow_root->host(); shadow_host = shadow_root->host();
@ -550,7 +550,7 @@ Vector<MatchingRule const*> StyleComputer::collect_matching_rules(DOM::Element c
auto add_rules_to_run = [&](Vector<MatchingRule> const& rules) { auto add_rules_to_run = [&](Vector<MatchingRule> const& rules) {
rules_to_run.grow_capacity(rules_to_run.size() + rules.size()); rules_to_run.grow_capacity(rules_to_run.size() + rules.size());
if (pseudo_element.has_value()) { if (abstract_element.pseudo_element().has_value()) {
for (auto const& rule : rules) { for (auto const& rule : rules) {
if (rule.contains_pseudo_element && filter_namespace_rule(element_namespace_uri, rule)) if (rule.contains_pseudo_element && filter_namespace_rule(element_namespace_uri, rule))
add_rule_to_run(rule); add_rule_to_run(rule);
@ -564,7 +564,7 @@ Vector<MatchingRule const*> StyleComputer::collect_matching_rules(DOM::Element c
}; };
auto add_rules_from_cache = [&](RuleCache const& rule_cache) { auto add_rules_from_cache = [&](RuleCache const& rule_cache) {
rule_cache.for_each_matching_rules(element, pseudo_element, [&](auto const& matching_rules) { rule_cache.for_each_matching_rules(abstract_element.element(), abstract_element.pseudo_element(), [&](auto const& matching_rules) {
add_rules_to_run(matching_rules); add_rules_to_run(matching_rules);
return IterationDecision::Continue; return IterationDecision::Continue;
}); });
@ -583,7 +583,7 @@ Vector<MatchingRule const*> StyleComputer::collect_matching_rules(DOM::Element c
add_rules_from_cache(*rule_cache); add_rules_from_cache(*rule_cache);
} }
if (auto assigned_slot = element.assigned_slot_internal()) { if (auto assigned_slot = abstract_element.element().assigned_slot_internal()) {
if (auto const* slot_shadow_root = as_if<DOM::ShadowRoot>(assigned_slot->root())) { if (auto const* slot_shadow_root = as_if<DOM::ShadowRoot>(assigned_slot->root())) {
if (auto const* rule_cache = rule_cache_for_cascade_origin(cascade_origin, qualified_layer_name, slot_shadow_root)) { if (auto const* rule_cache = rule_cache_for_cascade_origin(cascade_origin, qualified_layer_name, slot_shadow_root)) {
add_rules_to_run(rule_cache->slotted_rules); add_rules_to_run(rule_cache->slotted_rules);
@ -600,32 +600,32 @@ Vector<MatchingRule const*> StyleComputer::collect_matching_rules(DOM::Element c
// be confined to the element itself (since it refuses to cross the shadow boundary). // be confined to the element itself (since it refuses to cross the shadow boundary).
auto rule_root = rule_to_run.shadow_root; auto rule_root = rule_to_run.shadow_root;
auto shadow_host_to_use = shadow_host; auto shadow_host_to_use = shadow_host;
if (element.is_shadow_host() && rule_root != element.shadow_root()) if (abstract_element.element().is_shadow_host() && rule_root != abstract_element.element().shadow_root())
shadow_host_to_use = nullptr; shadow_host_to_use = nullptr;
auto const& selector = rule_to_run.selector; auto const& selector = rule_to_run.selector;
SelectorEngine::MatchContext context { SelectorEngine::MatchContext context {
.style_sheet_for_rule = *rule_to_run.sheet, .style_sheet_for_rule = *rule_to_run.sheet,
.subject = element, .subject = abstract_element.element(),
.collect_per_element_selector_involvement_metadata = true, .collect_per_element_selector_involvement_metadata = true,
}; };
ScopeGuard guard = [&] { ScopeGuard guard = [&] {
attempted_pseudo_class_matches |= context.attempted_pseudo_class_matches; attempted_pseudo_class_matches |= context.attempted_pseudo_class_matches;
}; };
if (selector.is_slotted()) { if (selector.is_slotted()) {
if (!element.assigned_slot_internal()) if (!abstract_element.element().assigned_slot_internal())
continue; continue;
// We're collecting rules for element, which is assigned to a slot. // We're collecting rules for element, which is assigned to a slot.
// For ::slotted() matching, slot should be used as a subject instead of element, // For ::slotted() matching, slot should be used as a subject instead of element,
// while element itself is saved in matching context, so selector engine could // while element itself is saved in matching context, so selector engine could
// switch back to it when matching inside ::slotted() argument. // switch back to it when matching inside ::slotted() argument.
auto const& slot = *element.assigned_slot_internal(); auto const& slot = *abstract_element.element().assigned_slot_internal();
context.slotted_element = &element; context.slotted_element = &abstract_element.element();
context.subject = &slot; context.subject = &slot;
if (!SelectorEngine::matches(selector, slot, shadow_host_to_use, context, PseudoElement::Slotted)) if (!SelectorEngine::matches(selector, slot, shadow_host_to_use, context, PseudoElement::Slotted))
continue; continue;
} else if (!SelectorEngine::matches(selector, element, shadow_host_to_use, context, pseudo_element)) } else if (!SelectorEngine::matches(selector, abstract_element.element(), shadow_host_to_use, context, abstract_element.pseudo_element()))
continue; continue;
matching_rules.append(&rule_to_run); matching_rules.append(&rule_to_run);
} }
@ -1507,28 +1507,28 @@ void StyleComputer::start_needed_transitions(ComputedProperties const& previous_
} }
} }
StyleComputer::MatchingRuleSet StyleComputer::build_matching_rule_set(DOM::Element const& element, Optional<PseudoElement> pseudo_element, PseudoClassBitmap& attempted_pseudo_class_matches, bool& did_match_any_pseudo_element_rules, ComputeStyleMode mode) const StyleComputer::MatchingRuleSet StyleComputer::build_matching_rule_set(DOM::AbstractElement abstract_element, PseudoClassBitmap& attempted_pseudo_class_matches, bool& did_match_any_pseudo_element_rules, ComputeStyleMode mode) const
{ {
// First, we collect all the CSS rules whose selectors match `element`: // First, we collect all the CSS rules whose selectors match `element`:
MatchingRuleSet matching_rule_set; MatchingRuleSet matching_rule_set;
matching_rule_set.user_agent_rules = collect_matching_rules(element, CascadeOrigin::UserAgent, pseudo_element, attempted_pseudo_class_matches); matching_rule_set.user_agent_rules = collect_matching_rules(abstract_element, CascadeOrigin::UserAgent, attempted_pseudo_class_matches);
sort_matching_rules(matching_rule_set.user_agent_rules); sort_matching_rules(matching_rule_set.user_agent_rules);
matching_rule_set.user_rules = collect_matching_rules(element, CascadeOrigin::User, pseudo_element, attempted_pseudo_class_matches); matching_rule_set.user_rules = collect_matching_rules(abstract_element, CascadeOrigin::User, attempted_pseudo_class_matches);
sort_matching_rules(matching_rule_set.user_rules); sort_matching_rules(matching_rule_set.user_rules);
// @layer-ed author rules // @layer-ed author rules
for (auto const& layer_name : m_qualified_layer_names_in_order) { for (auto const& layer_name : m_qualified_layer_names_in_order) {
auto layer_rules = collect_matching_rules(element, CascadeOrigin::Author, pseudo_element, attempted_pseudo_class_matches, layer_name); auto layer_rules = collect_matching_rules(abstract_element, CascadeOrigin::Author, attempted_pseudo_class_matches, layer_name);
sort_matching_rules(layer_rules); sort_matching_rules(layer_rules);
matching_rule_set.author_rules.append({ layer_name, layer_rules }); matching_rule_set.author_rules.append({ layer_name, layer_rules });
} }
// Un-@layer-ed author rules // Un-@layer-ed author rules
auto unlayered_author_rules = collect_matching_rules(element, CascadeOrigin::Author, pseudo_element, attempted_pseudo_class_matches); auto unlayered_author_rules = collect_matching_rules(abstract_element, CascadeOrigin::Author, attempted_pseudo_class_matches);
sort_matching_rules(unlayered_author_rules); sort_matching_rules(unlayered_author_rules);
matching_rule_set.author_rules.append({ {}, unlayered_author_rules }); matching_rule_set.author_rules.append({ {}, unlayered_author_rules });
if (mode == ComputeStyleMode::CreatePseudoElementStyleIfNeeded) { if (mode == ComputeStyleMode::CreatePseudoElementStyleIfNeeded) {
VERIFY(pseudo_element.has_value()); VERIFY(abstract_element.pseudo_element().has_value());
did_match_any_pseudo_element_rules = !matching_rule_set.author_rules.is_empty() did_match_any_pseudo_element_rules = !matching_rule_set.author_rules.is_empty()
|| !matching_rule_set.user_rules.is_empty() || !matching_rule_set.user_rules.is_empty()
|| !matching_rule_set.user_agent_rules.is_empty(); || !matching_rule_set.user_agent_rules.is_empty();
@ -2364,7 +2364,7 @@ GC::Ptr<ComputedProperties> StyleComputer::compute_style_impl(DOM::AbstractEleme
// 1. Perform the cascade. This produces the "specified style" // 1. Perform the cascade. This produces the "specified style"
bool did_match_any_pseudo_element_rules = false; bool did_match_any_pseudo_element_rules = false;
PseudoClassBitmap attempted_pseudo_class_matches; PseudoClassBitmap attempted_pseudo_class_matches;
auto matching_rule_set = build_matching_rule_set(abstract_element.element(), abstract_element.pseudo_element(), attempted_pseudo_class_matches, did_match_any_pseudo_element_rules, mode); auto matching_rule_set = build_matching_rule_set(abstract_element, attempted_pseudo_class_matches, did_match_any_pseudo_element_rules, mode);
auto old_custom_properties = abstract_element.custom_properties(); auto old_custom_properties = abstract_element.custom_properties();

View file

@ -157,7 +157,7 @@ public:
[[nodiscard]] RuleCache const& get_pseudo_class_rule_cache(PseudoClass) const; [[nodiscard]] RuleCache const& get_pseudo_class_rule_cache(PseudoClass) const;
[[nodiscard]] Vector<MatchingRule const*> collect_matching_rules(DOM::Element const&, CascadeOrigin, Optional<CSS::PseudoElement>, PseudoClassBitmap& attempted_pseudo_class_matches, Optional<FlyString const> qualified_layer_name = {}) const; [[nodiscard]] Vector<MatchingRule const*> collect_matching_rules(DOM::AbstractElement, CascadeOrigin, PseudoClassBitmap& attempted_pseudo_class_matches, Optional<FlyString const> qualified_layer_name = {}) const;
InvalidationSet invalidation_set_for_properties(Vector<InvalidationSet::Property> const&) const; InvalidationSet invalidation_set_for_properties(Vector<InvalidationSet::Property> const&) const;
bool invalidation_property_used_in_has_selector(InvalidationSet::Property const&) const; bool invalidation_property_used_in_has_selector(InvalidationSet::Property const&) const;
@ -227,7 +227,7 @@ private:
Vector<LayerMatchingRules> author_rules; Vector<LayerMatchingRules> author_rules;
}; };
[[nodiscard]] MatchingRuleSet build_matching_rule_set(DOM::Element const&, Optional<PseudoElement>, PseudoClassBitmap& attempted_pseudo_class_matches, bool& did_match_any_pseudo_element_rules, ComputeStyleMode) const; [[nodiscard]] MatchingRuleSet build_matching_rule_set(DOM::AbstractElement, PseudoClassBitmap& attempted_pseudo_class_matches, bool& did_match_any_pseudo_element_rules, ComputeStyleMode) const;
LogicalAliasMappingContext compute_logical_alias_mapping_context(DOM::Element&, Optional<CSS::PseudoElement>, ComputeStyleMode, MatchingRuleSet const&) const; LogicalAliasMappingContext compute_logical_alias_mapping_context(DOM::Element&, Optional<CSS::PseudoElement>, ComputeStyleMode, MatchingRuleSet const&) const;
[[nodiscard]] GC::Ptr<ComputedProperties> compute_style_impl(DOM::AbstractElement, ComputeStyleMode, Optional<bool&> did_change_custom_properties) const; [[nodiscard]] GC::Ptr<ComputedProperties> compute_style_impl(DOM::AbstractElement, ComputeStyleMode, Optional<bool&> did_change_custom_properties) const;