diff --git a/Libraries/LibWeb/CSS/Selector.cpp b/Libraries/LibWeb/CSS/Selector.cpp index e413b7f1c01..e387005b6b4 100644 --- a/Libraries/LibWeb/CSS/Selector.cpp +++ b/Libraries/LibWeb/CSS/Selector.cpp @@ -33,6 +33,50 @@ static bool component_value_contains_nesting_selector(Parser::ComponentValue con return false; } +static bool can_selector_use_fast_matches(CSS::Selector const& selector) +{ + for (auto const& compound_selector : selector.compound_selectors()) { + if (compound_selector.combinator != CSS::Selector::Combinator::None + && compound_selector.combinator != CSS::Selector::Combinator::Descendant + && compound_selector.combinator != CSS::Selector::Combinator::ImmediateChild) { + return false; + } + + for (auto const& simple_selector : compound_selector.simple_selectors) { + if (simple_selector.type == CSS::Selector::SimpleSelector::Type::PseudoClass) { + auto const pseudo_class = simple_selector.pseudo_class().type; + if (pseudo_class != CSS::PseudoClass::FirstChild + && pseudo_class != CSS::PseudoClass::LastChild + && pseudo_class != CSS::PseudoClass::OnlyChild + && pseudo_class != CSS::PseudoClass::Hover + && pseudo_class != CSS::PseudoClass::Active + && pseudo_class != CSS::PseudoClass::Focus + && pseudo_class != CSS::PseudoClass::FocusVisible + && pseudo_class != CSS::PseudoClass::FocusWithin + && pseudo_class != CSS::PseudoClass::Link + && pseudo_class != CSS::PseudoClass::AnyLink + && pseudo_class != CSS::PseudoClass::Visited + && pseudo_class != CSS::PseudoClass::LocalLink + && pseudo_class != CSS::PseudoClass::Empty + && pseudo_class != CSS::PseudoClass::Root + && pseudo_class != CSS::PseudoClass::Enabled + && pseudo_class != CSS::PseudoClass::Disabled + && pseudo_class != CSS::PseudoClass::Checked) { + return false; + } + } else if (simple_selector.type != CSS::Selector::SimpleSelector::Type::TagName + && simple_selector.type != CSS::Selector::SimpleSelector::Type::Universal + && simple_selector.type != CSS::Selector::SimpleSelector::Type::Class + && simple_selector.type != CSS::Selector::SimpleSelector::Type::Id + && simple_selector.type != CSS::Selector::SimpleSelector::Type::Attribute) { + return false; + } + } + } + + return true; +} + Selector::Selector(Vector&& compound_selectors) : m_compound_selectors(move(compound_selectors)) { @@ -88,6 +132,8 @@ Selector::Selector(Vector&& compound_selectors) } collect_ancestor_hashes(); + + m_can_use_fast_matches = can_selector_use_fast_matches(*this); } void Selector::collect_ancestor_hashes() diff --git a/Libraries/LibWeb/CSS/Selector.h b/Libraries/LibWeb/CSS/Selector.h index 4b61ea69d10..d8f4679b0fa 100644 --- a/Libraries/LibWeb/CSS/Selector.h +++ b/Libraries/LibWeb/CSS/Selector.h @@ -268,12 +268,15 @@ public: auto const& ancestor_hashes() const { return m_ancestor_hashes; } + bool can_use_fast_matches() const { return m_can_use_fast_matches; } + private: explicit Selector(Vector&&); Vector m_compound_selectors; mutable Optional m_specificity; Optional m_pseudo_element; + bool m_can_use_fast_matches { false }; bool m_contains_the_nesting_selector { false }; bool m_contains_hover_pseudo_class { false }; diff --git a/Libraries/LibWeb/CSS/SelectorEngine.cpp b/Libraries/LibWeb/CSS/SelectorEngine.cpp index 1baff8bc2f6..6fee18ac11e 100644 --- a/Libraries/LibWeb/CSS/SelectorEngine.cpp +++ b/Libraries/LibWeb/CSS/SelectorEngine.cpp @@ -157,7 +157,7 @@ static inline bool matches_link_pseudo_class(DOM::Element const& element) return element.has_attribute(HTML::AttributeNames::href); } -bool matches_hover_pseudo_class(DOM::Element const& element) +static bool matches_hover_pseudo_class(DOM::Element const& element) { auto* hovered_node = element.document().hovered_node(); if (!hovered_node) @@ -899,8 +899,13 @@ bool matches(CSS::Selector const& selector, int component_list_index, DOM::Eleme VERIFY_NOT_REACHED(); } +bool fast_matches(CSS::Selector const& selector, DOM::Element const& element_to_match, GC::Ptr shadow_host, MatchContext& context); + bool matches(CSS::Selector const& selector, DOM::Element const& element, GC::Ptr shadow_host, MatchContext& context, Optional pseudo_element, GC::Ptr scope, SelectorKind selector_kind, GC::Ptr anchor) { + if (selector_kind == SelectorKind::Normal && selector.can_use_fast_matches()) { + return fast_matches(selector, element, shadow_host, context); + } VERIFY(!selector.compound_selectors().is_empty()); if (pseudo_element.has_value() && selector.pseudo_element().has_value() && selector.pseudo_element().value().type() != pseudo_element) return false; @@ -1011,48 +1016,4 @@ bool fast_matches(CSS::Selector const& selector, DOM::Element const& element_to_ } } -bool can_use_fast_matches(CSS::Selector const& selector) -{ - for (auto const& compound_selector : selector.compound_selectors()) { - if (compound_selector.combinator != CSS::Selector::Combinator::None - && compound_selector.combinator != CSS::Selector::Combinator::Descendant - && compound_selector.combinator != CSS::Selector::Combinator::ImmediateChild) { - return false; - } - - for (auto const& simple_selector : compound_selector.simple_selectors) { - if (simple_selector.type == CSS::Selector::SimpleSelector::Type::PseudoClass) { - auto const pseudo_class = simple_selector.pseudo_class().type; - if (pseudo_class != CSS::PseudoClass::FirstChild - && pseudo_class != CSS::PseudoClass::LastChild - && pseudo_class != CSS::PseudoClass::OnlyChild - && pseudo_class != CSS::PseudoClass::Hover - && pseudo_class != CSS::PseudoClass::Active - && pseudo_class != CSS::PseudoClass::Focus - && pseudo_class != CSS::PseudoClass::FocusVisible - && pseudo_class != CSS::PseudoClass::FocusWithin - && pseudo_class != CSS::PseudoClass::Link - && pseudo_class != CSS::PseudoClass::AnyLink - && pseudo_class != CSS::PseudoClass::Visited - && pseudo_class != CSS::PseudoClass::LocalLink - && pseudo_class != CSS::PseudoClass::Empty - && pseudo_class != CSS::PseudoClass::Root - && pseudo_class != CSS::PseudoClass::Enabled - && pseudo_class != CSS::PseudoClass::Disabled - && pseudo_class != CSS::PseudoClass::Checked) { - return false; - } - } else if (simple_selector.type != CSS::Selector::SimpleSelector::Type::TagName - && simple_selector.type != CSS::Selector::SimpleSelector::Type::Universal - && simple_selector.type != CSS::Selector::SimpleSelector::Type::Class - && simple_selector.type != CSS::Selector::SimpleSelector::Type::Id - && simple_selector.type != CSS::Selector::SimpleSelector::Type::Attribute) { - return false; - } - } - } - - return true; -} - } diff --git a/Libraries/LibWeb/CSS/SelectorEngine.h b/Libraries/LibWeb/CSS/SelectorEngine.h index 37430aa414f..e62c0a298e9 100644 --- a/Libraries/LibWeb/CSS/SelectorEngine.h +++ b/Libraries/LibWeb/CSS/SelectorEngine.h @@ -25,9 +25,4 @@ struct MatchContext { bool matches(CSS::Selector const&, DOM::Element const&, GC::Ptr shadow_host, MatchContext& context, Optional = {}, GC::Ptr scope = {}, SelectorKind selector_kind = SelectorKind::Normal, GC::Ptr anchor = nullptr); -[[nodiscard]] bool fast_matches(CSS::Selector const&, DOM::Element const&, GC::Ptr shadow_host, MatchContext& context); -[[nodiscard]] bool can_use_fast_matches(CSS::Selector const&); - -[[nodiscard]] bool matches_hover_pseudo_class(DOM::Element const&); - } diff --git a/Libraries/LibWeb/CSS/StyleComputer.cpp b/Libraries/LibWeb/CSS/StyleComputer.cpp index cfc3816ee1d..9836dc78e17 100644 --- a/Libraries/LibWeb/CSS/StyleComputer.cpp +++ b/Libraries/LibWeb/CSS/StyleComputer.cpp @@ -595,13 +595,8 @@ Vector StyleComputer::collect_matching_rules(DOM::Element c if (context.did_match_any_hover_rules) did_match_any_hover_rules = true; }; - if (rule_to_run.can_use_fast_matches) { - if (!SelectorEngine::fast_matches(selector, element, shadow_host_to_use, context)) - continue; - } else { - if (!SelectorEngine::matches(selector, element, shadow_host_to_use, context, pseudo_element)) - continue; - } + if (!SelectorEngine::matches(selector, element, shadow_host_to_use, context, pseudo_element)) + continue; matching_rules.append(&rule_to_run); } @@ -2686,7 +2681,6 @@ void StyleComputer::make_rule_cache_for_cascade_origin(CascadeOrigin cascade_ori selector.specificity(), cascade_origin, false, - SelectorEngine::can_use_fast_matches(selector), false, }; diff --git a/Libraries/LibWeb/CSS/StyleComputer.h b/Libraries/LibWeb/CSS/StyleComputer.h index c2c62c041d5..07631eb4b68 100644 --- a/Libraries/LibWeb/CSS/StyleComputer.h +++ b/Libraries/LibWeb/CSS/StyleComputer.h @@ -86,7 +86,6 @@ struct MatchingRule { u32 specificity { 0 }; CascadeOrigin cascade_origin; bool contains_pseudo_element { false }; - bool can_use_fast_matches { false }; bool must_be_hovered { false }; // Helpers to deal with the fact that `rule` might be a CSSStyleRule or a CSSNestedDeclarations diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index fe739d8098a..2e4df27997c 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -1728,13 +1728,8 @@ void Document::invalidate_style_for_elements_affected_by_hover_change(Node& old_ SelectorEngine::MatchContext context; bool selector_matched = false; - if (rule.can_use_fast_matches) { - if (SelectorEngine::fast_matches(selector, element, {}, context)) - selector_matched = true; - } else { - if (SelectorEngine::matches(selector, element, {}, context, {})) - selector_matched = true; - } + if (SelectorEngine::matches(selector, element, {}, context, {})) + selector_matched = true; if (element.has_pseudo_elements()) { if (SelectorEngine::matches(selector, element, {}, context, CSS::Selector::PseudoElement::Type::Before)) selector_matched = true;