mirror of
https://github.com/RGBCube/serenity
synced 2025-05-31 01:58:12 +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