diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index 355fbc2750d..83cefbb68f2 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -1487,7 +1487,7 @@ static Node* find_common_ancestor(Node* a, Node* b) return nullptr; } -void Document::invalidate_style_for_elements_affected_by_hover_change(GC::Ptr old_new_hovered_common_ancestor, GC::Ptr hovered_node) +void Document::invalidate_style_for_elements_affected_by_hover_change(Node& old_new_hovered_common_ancestor, GC::Ptr hovered_node) { auto const& hover_rules = style_computer().get_hover_rules(); if (hover_rules.is_empty()) @@ -1495,12 +1495,12 @@ void Document::invalidate_style_for_elements_affected_by_hover_change(GC::Ptr Node& { if (style_computer().has_has_selectors()) - return *this; - return old_new_hovered_common_ancestor ? *old_new_hovered_common_ancestor : *this; + return old_new_hovered_common_ancestor; + return old_new_hovered_common_ancestor; }(); Vector elements; - invalidation_root.for_each_shadow_including_inclusive_descendant([&](Node& node) { + invalidation_root.for_each_in_inclusive_subtree([&](Node& node) { if (!node.is_element()) return TraversalDecision::Continue; auto& element = static_cast(node); @@ -1509,6 +1509,9 @@ void Document::invalidate_style_for_elements_affected_by_hover_change(GC::Ptr(root) ? static_cast(&root) : nullptr; + auto compute_hover_selectors_match_state = [&] { Vector state; state.resize(elements.size()); @@ -1517,6 +1520,15 @@ void Document::invalidate_style_for_elements_affected_by_hover_change(GC::Ptr old_hovered_node = move(m_hovered_node); auto* common_ancestor = find_common_ancestor(old_hovered_node, node); - invalidate_style_for_elements_affected_by_hover_change(common_ancestor, node); + + GC::Ptr old_hovered_node_root = nullptr; + GC::Ptr new_hovered_node_root = nullptr; + if (old_hovered_node) + old_hovered_node_root = old_hovered_node->root(); + if (node) + new_hovered_node_root = node->root(); + if (old_hovered_node_root != new_hovered_node_root) { + if (old_hovered_node_root) + invalidate_style_for_elements_affected_by_hover_change(*old_hovered_node_root, node); + if (new_hovered_node_root) { + // invalidate_style_for_elements_affected_by_hover_change changes m_hovered_node, so it has to be + // reset back to old node before we do another invalidation pass for different root. + m_hovered_node = old_hovered_node; + invalidate_style_for_elements_affected_by_hover_change(*new_hovered_node_root, node); + } + } else { + invalidate_style_for_elements_affected_by_hover_change(*common_ancestor, node); + } // https://w3c.github.io/uievents/#mouseout if (old_hovered_node && old_hovered_node != m_hovered_node) { diff --git a/Libraries/LibWeb/DOM/Document.h b/Libraries/LibWeb/DOM/Document.h index 18f9894b992..c72ada75d2f 100644 --- a/Libraries/LibWeb/DOM/Document.h +++ b/Libraries/LibWeb/DOM/Document.h @@ -174,7 +174,7 @@ public: virtual FlyString node_name() const override { return "#document"_fly_string; } - void invalidate_style_for_elements_affected_by_hover_change(GC::Ptr old_new_hovered_common_ancestor, GC::Ptr hovered_node); + void invalidate_style_for_elements_affected_by_hover_change(Node& old_new_hovered_common_ancestor, GC::Ptr hovered_node); void set_hovered_node(Node*); Node* hovered_node() { return m_hovered_node.ptr(); } Node const* hovered_node() const { return m_hovered_node.ptr(); }