Browse Source

LibWeb: Limit style update tree traversal to dirty subtrees

This patch adds a second style dirty bit that tracks whether a DOM node
has one or more children with dirty style. This allows the style update
to skip over entire subtrees where all nodes are clean.
Andreas Kling 4 years ago
parent
commit
6809be436b
3 changed files with 32 additions and 7 deletions
  1. 16 4
      Libraries/LibWeb/DOM/Document.cpp
  2. 10 1
      Libraries/LibWeb/DOM/Node.cpp
  3. 6 2
      Libraries/LibWeb/DOM/Node.h

+ 16 - 4
Libraries/LibWeb/DOM/Document.cpp

@@ -400,13 +400,25 @@ void Document::update_layout()
     }
 }
 
-void Document::update_style()
+static void update_style_recursively(DOM::Node& node)
 {
-    for_each_in_subtree_of_type<Element>([&](auto& element) {
-        if (element.needs_style_update())
-            element.recompute_style();
+    node.for_each_child([&](auto& child) {
+        if (child.needs_style_update()) {
+            if (is<Element>(child))
+                downcast<Element>(child).recompute_style();
+            child.set_needs_style_update(false);
+        }
+        if (child.child_needs_style_update()) {
+            update_style_recursively(child);
+            child.set_child_needs_style_update(false);
+        }
         return IterationDecision::Continue;
     });
+}
+
+void Document::update_style()
+{
+    update_style_recursively(*this);
     update_layout();
 }
 

+ 10 - 1
Libraries/LibWeb/DOM/Node.cpp

@@ -254,8 +254,17 @@ void Node::set_needs_style_update(bool value)
     if (m_needs_style_update == value)
         return;
     m_needs_style_update = value;
-    if (m_needs_style_update)
+
+    if (m_needs_style_update) {
+        for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent())
+            ancestor->m_child_needs_style_update = true;
         document().schedule_style_update();
+    }
+}
+
+void Node::inserted_into(Node&)
+{
+    set_needs_style_update(true);
 }
 
 }

+ 6 - 2
Libraries/LibWeb/DOM/Node.h

@@ -126,7 +126,7 @@ public:
     Element* parent_element();
     const Element* parent_element() const;
 
-    virtual void inserted_into(Node&) { }
+    virtual void inserted_into(Node&);
     virtual void removed_from(Node&) { }
     virtual void children_changed() { }
 
@@ -140,6 +140,9 @@ public:
     bool needs_style_update() const { return m_needs_style_update; }
     void set_needs_style_update(bool);
 
+    bool child_needs_style_update() const { return m_child_needs_style_update; }
+    void set_child_needs_style_update(bool b) { m_child_needs_style_update = b; }
+
     void invalidate_style();
 
     bool is_link() const;
@@ -157,7 +160,8 @@ protected:
     Document* m_document { nullptr };
     mutable WeakPtr<Layout::Node> m_layout_node;
     NodeType m_type { NodeType::INVALID };
-    bool m_needs_style_update { true };
+    bool m_needs_style_update { false };
+    bool m_child_needs_style_update { false };
 };
 
 }