diff --git a/Userland/Libraries/LibWeb/DOM/Node.cpp b/Userland/Libraries/LibWeb/DOM/Node.cpp index 93a07ffa7f5..a8fd88b8eba 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.cpp +++ b/Userland/Libraries/LibWeb/DOM/Node.cpp @@ -405,18 +405,42 @@ void Node::invalidate_style(StyleInvalidationReason reason) return; } - for_each_in_inclusive_subtree([&](Node& node) { - node.m_needs_style_update = true; - if (node.has_children()) - node.m_child_needs_style_update = true; - if (auto shadow_root = node.is_element() ? static_cast(node).shadow_root() : nullptr) { - node.m_child_needs_style_update = true; - shadow_root->m_needs_style_update = true; - if (shadow_root->has_children()) - shadow_root->m_child_needs_style_update = true; + // When invalidating style for a node, we actually invalidate: + // - the node itself + // - all of its descendants + // - all of its preceding siblings and their descendants (only on DOM insert/remove) + // - all of its subsequent siblings and their descendants + // FIXME: This is a lot of invalidation and we should implement more sophisticated invalidation to do less work! + + auto invalidate_entire_subtree = [&](Node& subtree_root) { + subtree_root.for_each_in_inclusive_subtree([&](Node& node) { + node.m_needs_style_update = true; + if (node.has_children()) + node.m_child_needs_style_update = true; + if (auto shadow_root = node.is_element() ? static_cast(node).shadow_root() : nullptr) { + node.m_child_needs_style_update = true; + shadow_root->m_needs_style_update = true; + if (shadow_root->has_children()) + shadow_root->m_child_needs_style_update = true; + } + return TraversalDecision::Continue; + }); + }; + + invalidate_entire_subtree(*this); + + if (reason == StyleInvalidationReason::NodeInsertBefore || reason == StyleInvalidationReason::NodeRemove) { + for (auto* sibling = previous_sibling(); sibling; sibling = sibling->previous_sibling()) { + if (sibling->is_element()) + invalidate_entire_subtree(*sibling); } - return TraversalDecision::Continue; - }); + } + + for (auto* sibling = next_sibling(); sibling; sibling = sibling->next_sibling()) { + if (sibling->is_element()) + invalidate_entire_subtree(*sibling); + } + for (auto* ancestor = parent_or_shadow_host(); ancestor; ancestor = ancestor->parent_or_shadow_host()) ancestor->m_child_needs_style_update = true; document().schedule_style_update();