From 1843a54df77f1b118bed07d92cafad4fef616f09 Mon Sep 17 00:00:00 2001 From: Aliaksandr Kalenik Date: Thu, 20 Feb 2025 16:25:29 +0100 Subject: [PATCH] LibWeb: Skip quick selector rejection using ancestor filter if possible If selector does not have any descendant combinators then we know for sure it won't be filtered out by ancestor filter, which means there is no need to check for it. This change makes hover style invalidation go faster on Discord where with this change we spend 4-5% in `should_reject_with_ancestor_filter()` instead of 20%. --- Libraries/LibWeb/CSS/Selector.cpp | 1 + Libraries/LibWeb/CSS/Selector.h | 2 ++ Libraries/LibWeb/CSS/StyleComputer.cpp | 3 ++- Libraries/LibWeb/DOM/Document.cpp | 2 +- 4 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Libraries/LibWeb/CSS/Selector.cpp b/Libraries/LibWeb/CSS/Selector.cpp index e387005b6b4..f8fc177db9b 100644 --- a/Libraries/LibWeb/CSS/Selector.cpp +++ b/Libraries/LibWeb/CSS/Selector.cpp @@ -154,6 +154,7 @@ void Selector::collect_ancestor_hashes() for (ssize_t compound_selector_index = static_cast(m_compound_selectors.size()) - 2; compound_selector_index >= 0; --compound_selector_index) { auto const& compound_selector = m_compound_selectors[compound_selector_index]; if (last_combinator == Combinator::Descendant || last_combinator == Combinator::ImmediateChild) { + m_can_use_ancestor_filter = true; for (auto const& simple_selector : compound_selector.simple_selectors) { switch (simple_selector.type) { case SimpleSelector::Type::Id: diff --git a/Libraries/LibWeb/CSS/Selector.h b/Libraries/LibWeb/CSS/Selector.h index d8f4679b0fa..a0b9bbd509f 100644 --- a/Libraries/LibWeb/CSS/Selector.h +++ b/Libraries/LibWeb/CSS/Selector.h @@ -269,6 +269,7 @@ public: auto const& ancestor_hashes() const { return m_ancestor_hashes; } bool can_use_fast_matches() const { return m_can_use_fast_matches; } + bool can_use_ancestor_filter() const { return m_can_use_ancestor_filter; } private: explicit Selector(Vector&&); @@ -277,6 +278,7 @@ private: mutable Optional m_specificity; Optional m_pseudo_element; bool m_can_use_fast_matches { false }; + bool m_can_use_ancestor_filter { false }; bool m_contains_the_nesting_selector { false }; bool m_contains_hover_pseudo_class { false }; diff --git a/Libraries/LibWeb/CSS/StyleComputer.cpp b/Libraries/LibWeb/CSS/StyleComputer.cpp index 0f1a996b283..a60e5b4fefe 100644 --- a/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -503,7 +503,8 @@ Vector StyleComputer::collect_matching_rules(DOM::Element c if (!rule_is_relevant_for_current_scope) return; - if (should_reject_with_ancestor_filter(rule_to_run.selector)) + auto const& selector = rule_to_run.selector; + if (selector.can_use_ancestor_filter() && should_reject_with_ancestor_filter(selector)) return; rules_to_run.unchecked_append(rule_to_run); diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index 0ecc1913c4e..b56c73edefb 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -1741,7 +1741,7 @@ void Document::invalidate_style_for_elements_affected_by_hover_change(Node& old_ return false; auto const& selector = rule.selector; - if (style_computer.should_reject_with_ancestor_filter(selector)) + if (selector.can_use_ancestor_filter() && style_computer.should_reject_with_ancestor_filter(selector)) return false; SelectorEngine::MatchContext context;