Procházet zdrojové kódy

LibWeb: Make DOM Nodes keep their Document alive

In addition to being reference-counted, all nodes that are part of a
document must also keep the document alive.

This is achieved by adding a second ref-count to the Document object
and incrementing/decrementing it whenever a node is created/destroyed
in that document.

This brings us much closer to a proper DOM lifetime model, although
the JS bindings still need more work.
Andreas Kling před 4 roky
rodič
revize
f68ed6d25b

+ 10 - 0
Libraries/LibWeb/DOM/Document.cpp

@@ -77,6 +77,16 @@ Document::~Document()
 {
 }
 
+void Document::removed_last_ref()
+{
+    ASSERT(!ref_count());
+
+    if (m_referencing_node_count)
+        return;
+
+    delete this;
+}
+
 Origin Document::origin() const
 {
     if (!m_url.is_valid())

+ 18 - 0
Libraries/LibWeb/DOM/Document.h

@@ -177,9 +177,27 @@ public:
     const String& ready_state() const { return m_ready_state; }
     void set_ready_state(const String&);
 
+    void ref_from_node(Badge<Node>)
+    {
+        ++m_referencing_node_count;
+    }
+
+    void unref_from_node(Badge<Node>)
+    {
+        ASSERT(m_referencing_node_count);
+        --m_referencing_node_count;
+        if (!m_referencing_node_count && !ref_count()) {
+            removed_last_ref();
+        }
+    }
+
+    void removed_last_ref();
+
 private:
     virtual RefPtr<LayoutNode> create_layout_node(const CSS::StyleProperties* parent_style) override;
 
+    unsigned m_referencing_node_count { 0 };
+
     OwnPtr<CSS::StyleResolver> m_style_resolver;
     RefPtr<CSS::StyleSheetList> m_style_sheets;
     RefPtr<Node> m_hovered_node;

+ 9 - 0
Libraries/LibWeb/DOM/Node.cpp

@@ -206,4 +206,13 @@ Bindings::EventTargetWrapper* Node::create_wrapper(JS::GlobalObject& global_obje
     return wrap(global_object, *this);
 }
 
+void Node::removed_last_ref()
+{
+    if (is<Document>(*this)) {
+        downcast<Document>(*this).removed_last_ref();
+        return;
+    }
+    delete this;
+}
+
 }

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

@@ -65,6 +65,8 @@ public:
 
     virtual ~Node();
 
+    void removed_last_ref();
+
     NodeType type() const { return m_type; }
     bool is_element() const { return type() == NodeType::ELEMENT_NODE; }
     bool is_text() const { return type() == NodeType::TEXT_NODE; }

+ 6 - 11
Libraries/LibWeb/TreeNode.h

@@ -30,6 +30,7 @@
 #include <AK/NonnullRefPtr.h>
 #include <AK/TypeCasts.h>
 #include <AK/Weakable.h>
+#include <LibWeb/Forward.h>
 
 namespace Web {
 
@@ -46,17 +47,11 @@ public:
     {
         ASSERT(m_ref_count);
         if (!--m_ref_count) {
-            if (m_next_sibling)
-                m_next_sibling->m_previous_sibling = m_previous_sibling;
-            if (m_previous_sibling)
-                m_previous_sibling->m_next_sibling = m_next_sibling;
-            T* next_child;
-            for (auto* child = m_first_child; child; child = next_child) {
-                next_child = child->m_next_sibling;
-                child->m_parent = nullptr;
-                child->unref();
-            }
-            delete static_cast<T*>(this);
+            if constexpr (IsBaseOf<DOM::Node, T>::value)
+                static_cast<T*>(this)->removed_last_ref();
+            else
+                delete static_cast<T*>(this);
+            return;
         }
     }
     int ref_count() const { return m_ref_count; }