From d7485df92859490a46a0f91cf043f9d11df851e0 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Mon, 30 Aug 2021 15:52:08 +0100 Subject: [PATCH] LibWeb: Give each Node a unique ID We maintain a directory of ID -> Node. Nodes add themselves to this directory when they are created, receiving a random ID. When a Node is destroyed, it removes itself from this directory. Anyone can request a Node from the directory by its ID using `Node::from_id()`. We reserve the `0` ID to mean "none". These IDs allow different processes to communicate about a given Node over IPC, for example the DOM Inspector. --- Userland/Libraries/LibWeb/DOM/Document.h | 1 + Userland/Libraries/LibWeb/DOM/Node.cpp | 27 ++++++++++++++++++++++++ Userland/Libraries/LibWeb/DOM/Node.h | 5 +++++ 3 files changed, 33 insertions(+) diff --git a/Userland/Libraries/LibWeb/DOM/Document.h b/Userland/Libraries/LibWeb/DOM/Document.h index 4225636f73e..e3cef337dd2 100644 --- a/Userland/Libraries/LibWeb/DOM/Document.h +++ b/Userland/Libraries/LibWeb/DOM/Document.h @@ -8,6 +8,7 @@ #include #include +#include #include #include #include diff --git a/Userland/Libraries/LibWeb/DOM/Node.cpp b/Userland/Libraries/LibWeb/DOM/Node.cpp index 0490d079a25..29c9647d597 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.cpp +++ b/Userland/Libraries/LibWeb/DOM/Node.cpp @@ -6,6 +6,7 @@ * SPDX-License-Identifier: BSD-2-Clause */ +#include #include #include #include @@ -30,10 +31,33 @@ namespace Web::DOM { +static IDAllocator s_node_id_allocator; +static HashMap s_node_directory; + +static i32 allocate_node_id(Node* node) +{ + i32 id = s_node_id_allocator.allocate(); + s_node_directory.set(id, node); + return id; +} + +static void deallocate_node_id(i32 node_id) +{ + if (!s_node_directory.remove(node_id)) + VERIFY_NOT_REACHED(); + s_node_id_allocator.deallocate(node_id); +} + +Node* Node::from_id(i32 node_id) +{ + return s_node_directory.get(node_id).value_or(nullptr); +} + Node::Node(Document& document, NodeType type) : EventTarget(static_cast(document)) , m_document(&document) , m_type(type) + , m_id(allocate_node_id(this)) { if (!is_document()) m_document->ref_from_node({}); @@ -47,6 +71,8 @@ Node::~Node() if (!is_document()) m_document->unref_from_node({}); + + deallocate_node_id(m_id); } const HTML::HTMLAnchorElement* Node::enclosing_link_element() const @@ -477,6 +503,7 @@ void Node::set_document(Badge, Document& document) { if (m_document == &document) return; + document.ref_from_node({}); m_document->unref_from_node({}); m_document = &document; diff --git a/Userland/Libraries/LibWeb/DOM/Node.h b/Userland/Libraries/LibWeb/DOM/Node.h index 5907e061b7c..81a389401ff 100644 --- a/Userland/Libraries/LibWeb/DOM/Node.h +++ b/Userland/Libraries/LibWeb/DOM/Node.h @@ -179,6 +179,9 @@ public: bool is_shadow_including_ancestor_of(Node const&) const; bool is_shadow_including_inclusive_ancestor_of(Node const&) const; + i32 id() const { return m_id; } + static Node* from_id(i32 node_id); + protected: Node(Document&, NodeType); @@ -187,6 +190,8 @@ protected: NodeType m_type { NodeType::INVALID }; bool m_needs_style_update { false }; bool m_child_needs_style_update { false }; + + i32 m_id; }; }