Browse Source

LibWeb: Make document-level style invalidation fast

Add a flag to DOM::Document that means the whole document needs a style
update. This saves us the trouble of traversing the entire DOM to mark
all nodes as needing a style update.
Andreas Kling 3 năm trước cách đây
mục cha
commit
0b861e0c9d

+ 6 - 4
Userland/Libraries/LibWeb/DOM/Document.cpp

@@ -595,6 +595,7 @@ void Document::update_layout()
 
 
 [[nodiscard]] static bool update_style_recursively(DOM::Node& node)
 [[nodiscard]] static bool update_style_recursively(DOM::Node& node)
 {
 {
+    bool const needs_full_style_update = node.document().needs_full_style_update();
     bool needs_relayout = false;
     bool needs_relayout = false;
 
 
     if (is<Element>(node)) {
     if (is<Element>(node)) {
@@ -602,15 +603,15 @@ void Document::update_layout()
     }
     }
     node.set_needs_style_update(false);
     node.set_needs_style_update(false);
 
 
-    if (node.child_needs_style_update()) {
+    if (needs_full_style_update || node.child_needs_style_update()) {
         if (node.is_element()) {
         if (node.is_element()) {
             if (auto* shadow_root = static_cast<DOM::Element&>(node).shadow_root()) {
             if (auto* shadow_root = static_cast<DOM::Element&>(node).shadow_root()) {
-                if (shadow_root->needs_style_update() || shadow_root->child_needs_style_update())
+                if (needs_full_style_update || shadow_root->needs_style_update() || shadow_root->child_needs_style_update())
                     needs_relayout |= update_style_recursively(*shadow_root);
                     needs_relayout |= update_style_recursively(*shadow_root);
             }
             }
         }
         }
         node.for_each_child([&](auto& child) {
         node.for_each_child([&](auto& child) {
-            if (child.needs_style_update() || child.child_needs_style_update())
+            if (needs_full_style_update || child.needs_style_update() || child.child_needs_style_update())
                 needs_relayout |= update_style_recursively(child);
                 needs_relayout |= update_style_recursively(child);
             return IterationDecision::Continue;
             return IterationDecision::Continue;
         });
         });
@@ -624,10 +625,11 @@ void Document::update_style()
 {
 {
     if (!browsing_context())
     if (!browsing_context())
         return;
         return;
-    if (!needs_style_update() && !child_needs_style_update())
+    if (!needs_full_style_update() && !needs_style_update() && !child_needs_style_update())
         return;
         return;
     if (update_style_recursively(*this))
     if (update_style_recursively(*this))
         invalidate_layout();
         invalidate_layout();
+    m_needs_full_style_update = false;
     m_style_update_timer->stop();
     m_style_update_timer->stop();
 }
 }
 
 

+ 5 - 0
Userland/Libraries/LibWeb/DOM/Document.h

@@ -334,6 +334,9 @@ public:
             callback(*node_iterator);
             callback(*node_iterator);
     }
     }
 
 
+    bool needs_full_style_update() const { return m_needs_full_style_update; }
+    void set_needs_full_style_update(bool b) { m_needs_full_style_update = b; }
+
 private:
 private:
     explicit Document(const AK::URL&);
     explicit Document(const AK::URL&);
 
 
@@ -438,6 +441,8 @@ private:
 
 
     bool m_needs_layout { false };
     bool m_needs_layout { false };
 
 
+    bool m_needs_full_style_update { false };
+
     HashTable<NodeIterator*> m_node_iterators;
     HashTable<NodeIterator*> m_node_iterators;
 };
 };
 
 

+ 7 - 0
Userland/Libraries/LibWeb/DOM/Node.cpp

@@ -176,6 +176,13 @@ void Node::set_node_value(const String& value)
 
 
 void Node::invalidate_style()
 void Node::invalidate_style()
 {
 {
+    if (is_document()) {
+        auto& document = static_cast<DOM::Document&>(*this);
+        document.set_needs_full_style_update(true);
+        document.schedule_style_update();
+        return;
+    }
+
     for_each_in_inclusive_subtree([&](Node& node) {
     for_each_in_inclusive_subtree([&](Node& node) {
         node.m_needs_style_update = true;
         node.m_needs_style_update = true;
         if (node.has_children())
         if (node.has_children())