From 0e8b538e0afe13d9109721c8cec4a2ee5c8456bf Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Wed, 16 Mar 2022 17:51:37 +0100 Subject: [PATCH] LibWeb: Invalidate less style when moving between hovered nodes Instead of invalidating style for the entire document, we now locate the nearest common ancestor between the old and new innermost hovered node, and only invalidate that ancestor and its descendants. This drastically reduces the amount of style update work when mousing around on GitHub (and any other pages, really.) It's actually really really snappy now. Very cool! :^) --- Userland/Libraries/LibWeb/DOM/Document.cpp | 25 +++++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibWeb/DOM/Document.cpp b/Userland/Libraries/LibWeb/DOM/Document.cpp index 42c8397462..9bf17e9bbf 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.cpp +++ b/Userland/Libraries/LibWeb/DOM/Document.cpp @@ -672,6 +672,26 @@ void Document::set_inspected_node(Node* node) m_inspected_node->layout_node()->set_needs_display(); } +static Node* find_common_ancestor(Node* a, Node* b) +{ + if (!a || !b) + return nullptr; + + if (a == b) + return a; + + HashTable ancestors; + for (auto* node = a; node; node = node->parent_or_shadow_host()) + ancestors.set(node); + + for (auto* node = b; node; node = node->parent_or_shadow_host()) { + if (ancestors.contains(node)) + return node; + } + + return nullptr; +} + void Document::set_hovered_node(Node* node) { if (m_hovered_node == node) @@ -680,7 +700,10 @@ void Document::set_hovered_node(Node* node) RefPtr old_hovered_node = move(m_hovered_node); m_hovered_node = node; - invalidate_style(); + if (auto* common_ancestor = find_common_ancestor(old_hovered_node, m_hovered_node)) + common_ancestor->invalidate_style(); + else + invalidate_style(); } NonnullRefPtr Document::get_elements_by_name(String const& name)