mirror of
				https://github.com/RGBCube/serenity
				synced 2025-10-31 21:42:43 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									99acbbe86b
								
							
						
					
					
						commit
						f68ed6d25b
					
				
					 5 changed files with 45 additions and 11 deletions
				
			
		|  | @ -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 | Origin Document::origin() const | ||||||
| { | { | ||||||
|     if (!m_url.is_valid()) |     if (!m_url.is_valid()) | ||||||
|  |  | ||||||
|  | @ -177,9 +177,27 @@ public: | ||||||
|     const String& ready_state() const { return m_ready_state; } |     const String& ready_state() const { return m_ready_state; } | ||||||
|     void set_ready_state(const String&); |     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: | private: | ||||||
|     virtual RefPtr<LayoutNode> create_layout_node(const CSS::StyleProperties* parent_style) override; |     virtual RefPtr<LayoutNode> create_layout_node(const CSS::StyleProperties* parent_style) override; | ||||||
| 
 | 
 | ||||||
|  |     unsigned m_referencing_node_count { 0 }; | ||||||
|  | 
 | ||||||
|     OwnPtr<CSS::StyleResolver> m_style_resolver; |     OwnPtr<CSS::StyleResolver> m_style_resolver; | ||||||
|     RefPtr<CSS::StyleSheetList> m_style_sheets; |     RefPtr<CSS::StyleSheetList> m_style_sheets; | ||||||
|     RefPtr<Node> m_hovered_node; |     RefPtr<Node> m_hovered_node; | ||||||
|  |  | ||||||
|  | @ -206,4 +206,13 @@ Bindings::EventTargetWrapper* Node::create_wrapper(JS::GlobalObject& global_obje | ||||||
|     return wrap(global_object, *this); |     return wrap(global_object, *this); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | void Node::removed_last_ref() | ||||||
|  | { | ||||||
|  |     if (is<Document>(*this)) { | ||||||
|  |         downcast<Document>(*this).removed_last_ref(); | ||||||
|  |         return; | ||||||
|  |     } | ||||||
|  |     delete this; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -65,6 +65,8 @@ public: | ||||||
| 
 | 
 | ||||||
|     virtual ~Node(); |     virtual ~Node(); | ||||||
| 
 | 
 | ||||||
|  |     void removed_last_ref(); | ||||||
|  | 
 | ||||||
|     NodeType type() const { return m_type; } |     NodeType type() const { return m_type; } | ||||||
|     bool is_element() const { return type() == NodeType::ELEMENT_NODE; } |     bool is_element() const { return type() == NodeType::ELEMENT_NODE; } | ||||||
|     bool is_text() const { return type() == NodeType::TEXT_NODE; } |     bool is_text() const { return type() == NodeType::TEXT_NODE; } | ||||||
|  |  | ||||||
|  | @ -30,6 +30,7 @@ | ||||||
| #include <AK/NonnullRefPtr.h> | #include <AK/NonnullRefPtr.h> | ||||||
| #include <AK/TypeCasts.h> | #include <AK/TypeCasts.h> | ||||||
| #include <AK/Weakable.h> | #include <AK/Weakable.h> | ||||||
|  | #include <LibWeb/Forward.h> | ||||||
| 
 | 
 | ||||||
| namespace Web { | namespace Web { | ||||||
| 
 | 
 | ||||||
|  | @ -46,17 +47,11 @@ public: | ||||||
|     { |     { | ||||||
|         ASSERT(m_ref_count); |         ASSERT(m_ref_count); | ||||||
|         if (!--m_ref_count) { |         if (!--m_ref_count) { | ||||||
|             if (m_next_sibling) |             if constexpr (IsBaseOf<DOM::Node, T>::value) | ||||||
|                 m_next_sibling->m_previous_sibling = m_previous_sibling; |                 static_cast<T*>(this)->removed_last_ref(); | ||||||
|             if (m_previous_sibling) |             else | ||||||
|                 m_previous_sibling->m_next_sibling = m_next_sibling; |                 delete static_cast<T*>(this); | ||||||
|             T* next_child; |             return; | ||||||
|             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); |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|     int ref_count() const { return m_ref_count; } |     int ref_count() const { return m_ref_count; } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Andreas Kling
						Andreas Kling