diff --git a/Libraries/LibWeb/CSS/StyleComputer.h b/Libraries/LibWeb/CSS/StyleComputer.h index 78f16c71cd1..c2c62c041d5 100644 --- a/Libraries/LibWeb/CSS/StyleComputer.h +++ b/Libraries/LibWeb/CSS/StyleComputer.h @@ -187,6 +187,8 @@ public: void absolutize_values(ComputedProperties&) const; void compute_font(ComputedProperties&, DOM::Element const*, Optional) const; + [[nodiscard]] bool should_reject_with_ancestor_filter(Selector const&) const; + private: enum class ComputeStyleMode { Normal, @@ -195,8 +197,6 @@ private: struct MatchingFontCandidate; - [[nodiscard]] bool should_reject_with_ancestor_filter(Selector const&) const; - [[nodiscard]] GC::Ptr compute_style_impl(DOM::Element&, Optional, ComputeStyleMode) const; [[nodiscard]] GC::Ref compute_cascaded_values(DOM::Element&, Optional, bool& did_match_any_pseudo_element_rules, bool& did_match_any_hover_rules, ComputeStyleMode) const; static RefPtr find_matching_font_weight_ascending(Vector const& candidates, int target_weight, float font_size_in_pt, bool inclusive); diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index f47384ae4fd..a1e3f545145 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -1667,6 +1667,7 @@ void Document::invalidate_style_for_elements_affected_by_hover_change(Node& old_ auto& root = old_new_hovered_common_ancestor.root(); auto shadow_root = is(root) ? static_cast(&root) : nullptr; + auto& style_computer = this->style_computer(); auto compute_hover_selectors_match_state = [&](Element const& element) { auto state = MUST(AK::Bitmap::create(hover_rules.size(), 0)); for (size_t rule_index = 0; rule_index < hover_rules.size(); ++rule_index) { @@ -1681,6 +1682,8 @@ void Document::invalidate_style_for_elements_affected_by_hover_change(Node& old_ continue; auto const& selector = rule.selector; + if (style_computer.should_reject_with_ancestor_filter(selector)) + continue; SelectorEngine::MatchContext context; bool selector_matched = false; @@ -1703,27 +1706,34 @@ void Document::invalidate_style_for_elements_affected_by_hover_change(Node& old_ return state; }; - root.for_each_in_inclusive_subtree([&](Node& node) { - if (!node.is_element()) - return TraversalDecision::Continue; - auto& element = static_cast(node); - if (!element.affected_by_hover()) - return TraversalDecision::Continue; + Function invalidate_hovered_elements_recursively = [&](Node& node) -> void { + if (node.is_element()) { + auto& element = static_cast(node); + style_computer.push_ancestor(element); + if (element.affected_by_hover()) { + auto selectors_match_state_before = compute_hover_selectors_match_state(element); + TemporaryChange change { m_hovered_node, hovered_node }; + auto selectors_match_state_after = compute_hover_selectors_match_state(element); + if (selectors_match_state_before.view() != selectors_match_state_after.view()) { + element.set_needs_style_update(true); + element.for_each_in_subtree_of_type([](auto& element) { + element.set_needs_inherited_style_update(true); + return TraversalDecision::Continue; + }); + } + } + } - auto selectors_match_state_before = compute_hover_selectors_match_state(element); - TemporaryChange change { m_hovered_node, hovered_node }; - auto selectors_match_state_after = compute_hover_selectors_match_state(element); - if (selectors_match_state_before.view() == selectors_match_state_after.view()) - return TraversalDecision::Continue; - - element.set_needs_style_update(true); - element.for_each_in_subtree_of_type([](auto& element) { - element.set_needs_inherited_style_update(true); - return TraversalDecision::Continue; + node.for_each_child([&](auto& child) { + invalidate_hovered_elements_recursively(child); + return IterationDecision::Continue; }); - return TraversalDecision::Continue; - }); + if (node.is_element()) + style_computer.pop_ancestor(static_cast(node)); + }; + + invalidate_hovered_elements_recursively(root); } void Document::set_hovered_node(Node* node)