From f35152cf61dd58a8a95e80ac5f4a15e0ae87f1af Mon Sep 17 00:00:00 2001 From: Andreas Kling Date: Sun, 26 Jan 2025 19:00:51 +0100 Subject: [PATCH] LibWeb: Defer entire-subtree style invalidations Instead of traversing the entire DOM subtrees and marking nodes for style update, this patch adds a new mechanism where we can mark a subtree root as "entire subtree needs style update". A new pass in Document::update_style() then takes care of coalescing all these invalidations in a single traversal of the DOM. This shaves *minutes* of loading time off of https://wpt.fyi/ subpages. --- Libraries/LibWeb/DOM/Document.cpp | 30 ++++++++++++++++++++++++++++++ Libraries/LibWeb/DOM/Node.cpp | 28 ++++++++++------------------ Libraries/LibWeb/DOM/Node.h | 5 +++++ 3 files changed, 45 insertions(+), 18 deletions(-) diff --git a/Libraries/LibWeb/DOM/Document.cpp b/Libraries/LibWeb/DOM/Document.cpp index c3a005d85c6..4e8c8e4e738 100644 --- a/Libraries/LibWeb/DOM/Document.cpp +++ b/Libraries/LibWeb/DOM/Document.cpp @@ -1382,6 +1382,34 @@ void Document::update_layout() return invalidation; } +// This function makes a full pass over the entire DOM and converts "entire subtree needs style update" +// into "needs style update" for each inclusive descendant where it's found. +static void perform_pending_style_invalidations(Node& node, bool invalidate_entire_subtree) +{ + invalidate_entire_subtree |= node.entire_subtree_needs_style_update(); + + if (invalidate_entire_subtree) { + node.set_needs_style_update_internal(true); + if (node.has_child_nodes()) + node.set_child_needs_style_update(true); + } + + for (auto* child = node.first_child(); child; child = child->next_sibling()) { + perform_pending_style_invalidations(*child, invalidate_entire_subtree); + } + + if (node.is_element()) { + auto& element = static_cast(node); + if (auto shadow_root = element.shadow_root()) { + perform_pending_style_invalidations(*shadow_root, invalidate_entire_subtree); + if (invalidate_entire_subtree) + node.set_child_needs_style_update(true); + } + } + + node.set_entire_subtree_needs_style_update(false); +} + void Document::update_style() { if (!browsing_context()) @@ -1396,6 +1424,8 @@ void Document::update_style() if (!needs_full_style_update() && !needs_style_update() && !child_needs_style_update()) return; + perform_pending_style_invalidations(*this, false); + // NOTE: If this is a document hosting