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.
This commit is contained in:
Andreas Kling
2025-01-26 19:00:51 +01:00
committed by Andreas Kling
parent 84c4702b10
commit f35152cf61
3 changed files with 45 additions and 18 deletions

View File

@@ -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<Element&>(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 <template> contents, style update is unnecessary.
if (m_created_for_appropriate_template_contents)
return;