ソースを参照

LibWeb: Make LiveNodeList faster when it only cares about children

Same optimization as HTMLCollection, ported to LiveNodeList.
Andreas Kling 2 年 前
コミット
fa25f70086

+ 17 - 9
Userland/Libraries/LibWeb/DOM/LiveNodeList.cpp

@@ -10,15 +10,16 @@
 
 namespace Web::DOM {
 
-WebIDL::ExceptionOr<JS::NonnullGCPtr<NodeList>> LiveNodeList::create(JS::Realm& realm, Node& root, Function<bool(Node const&)> filter)
+WebIDL::ExceptionOr<JS::NonnullGCPtr<NodeList>> LiveNodeList::create(JS::Realm& realm, Node& root, Scope scope, Function<bool(Node const&)> filter)
 {
-    return MUST_OR_THROW_OOM(realm.heap().allocate<LiveNodeList>(realm, realm, root, move(filter)));
+    return MUST_OR_THROW_OOM(realm.heap().allocate<LiveNodeList>(realm, realm, root, scope, move(filter)));
 }
 
-LiveNodeList::LiveNodeList(JS::Realm& realm, Node& root, Function<bool(Node const&)> filter)
+LiveNodeList::LiveNodeList(JS::Realm& realm, Node& root, Scope scope, Function<bool(Node const&)> filter)
     : NodeList(realm)
     , m_root(root)
     , m_filter(move(filter))
+    , m_scope(scope)
 {
 }
 
@@ -33,12 +34,19 @@ void LiveNodeList::visit_edges(Cell::Visitor& visitor)
 JS::MarkedVector<Node*> LiveNodeList::collection() const
 {
     JS::MarkedVector<Node*> nodes(heap());
-    m_root->for_each_in_inclusive_subtree([&](auto& node) {
-        if (m_filter(node))
-            nodes.append(const_cast<Node*>(&node));
-
-        return IterationDecision::Continue;
-    });
+    if (m_scope == Scope::Descendants) {
+        m_root->for_each_in_subtree([&](auto& node) {
+            if (m_filter(node))
+                nodes.append(const_cast<Node*>(&node));
+            return IterationDecision::Continue;
+        });
+    } else {
+        m_root->for_each_child([&](auto& node) {
+            if (m_filter(node))
+                nodes.append(const_cast<Node*>(&node));
+            return IterationDecision::Continue;
+        });
+    }
     return nodes;
 }
 

+ 8 - 2
Userland/Libraries/LibWeb/DOM/LiveNodeList.h

@@ -18,7 +18,12 @@ class LiveNodeList final : public NodeList {
     WEB_PLATFORM_OBJECT(LiveNodeList, NodeList);
 
 public:
-    static WebIDL::ExceptionOr<JS::NonnullGCPtr<NodeList>> create(JS::Realm&, Node& root, Function<bool(Node const&)> filter);
+    enum class Scope {
+        Children,
+        Descendants,
+    };
+
+    static WebIDL::ExceptionOr<JS::NonnullGCPtr<NodeList>> create(JS::Realm&, Node& root, Scope, Function<bool(Node const&)> filter);
     virtual ~LiveNodeList() override;
 
     virtual u32 length() const override;
@@ -27,7 +32,7 @@ public:
     virtual bool is_supported_property_index(u32) const override;
 
 private:
-    LiveNodeList(JS::Realm&, Node& root, Function<bool(Node const&)> filter);
+    LiveNodeList(JS::Realm&, Node& root, Scope, Function<bool(Node const&)> filter);
 
     virtual void visit_edges(Cell::Visitor&) override;
 
@@ -35,6 +40,7 @@ private:
 
     JS::NonnullGCPtr<Node> m_root;
     Function<bool(Node const&)> m_filter;
+    Scope m_scope { Scope::Descendants };
 };
 
 }

+ 2 - 2
Userland/Libraries/LibWeb/DOM/Node.cpp

@@ -932,8 +932,8 @@ Element* Node::parent_or_shadow_host_element()
 JS::NonnullGCPtr<NodeList> Node::child_nodes()
 {
     if (!m_child_nodes) {
-        m_child_nodes = LiveNodeList::create(realm(), *this, [this](auto& node) {
-            return is_parent_of(node);
+        m_child_nodes = LiveNodeList::create(realm(), *this, LiveNodeList::Scope::Children, [](auto&) {
+            return true;
         }).release_value_but_fixme_should_propagate_errors();
     }
     return *m_child_nodes;