diff --git a/Libraries/LibHTML/DOM/Node.h b/Libraries/LibHTML/DOM/Node.h index a49220d84c7..2e53fe937ae 100644 --- a/Libraries/LibHTML/DOM/Node.h +++ b/Libraries/LibHTML/DOM/Node.h @@ -55,6 +55,9 @@ public: return nullptr; } + virtual void inserted_into(Node&) {} + virtual void removed_from(Node&) {} + protected: Node(Document&, NodeType); diff --git a/Libraries/LibHTML/Layout/LayoutNode.h b/Libraries/LibHTML/Layout/LayoutNode.h index 04e0205be22..ed31dd424dc 100644 --- a/Libraries/LibHTML/Layout/LayoutNode.h +++ b/Libraries/LibHTML/Layout/LayoutNode.h @@ -64,6 +64,9 @@ public: const StyleProperties& style_properties() const { return m_style_properties; } + void inserted_into(LayoutNode&) {} + void removed_from(LayoutNode&) {} + protected: explicit LayoutNode(const Node*, StyleProperties&&); diff --git a/Libraries/LibHTML/Parser/HTMLParser.cpp b/Libraries/LibHTML/Parser/HTMLParser.cpp index 940726c5653..b8d5d2ed6f6 100644 --- a/Libraries/LibHTML/Parser/HTMLParser.cpp +++ b/Libraries/LibHTML/Parser/HTMLParser.cpp @@ -1,3 +1,4 @@ +#include #include #include #include @@ -99,7 +100,7 @@ NonnullRefPtr parse_html(const String& html) attribute_value_buffer.clear(); if (state == State::Free && !text_buffer.string_view().is_empty()) { auto text_node = adopt(*new Text(document, text_buffer.to_string())); - node_stack.last().append_child(text_node); + node_stack.last().append_child(text_node, false); } state = new_state; text_buffer.clear(); @@ -116,7 +117,7 @@ NonnullRefPtr parse_html(const String& html) new_element->set_attributes(move(attributes)); node_stack.append(new_element); if (node_stack.size() != 1) - node_stack[node_stack.size() - 2].append_child(new_element); + node_stack[node_stack.size() - 2].append_child(new_element, false); if (is_self_closing_tag(new_element->tag_name())) close_tag(); @@ -278,5 +279,16 @@ NonnullRefPtr parse_html(const String& html) ASSERT_NOT_REACHED(); } } + + Function fire_insertion_callbacks = [&](Node& node) { + for (auto* child = node.first_child(); child; child = child->next_sibling()) { + fire_insertion_callbacks(*child); + } + if (node.parent()) + node.inserted_into(*node.parent()); + }; + + fire_insertion_callbacks(*document); + return document; } diff --git a/Libraries/LibHTML/TreeNode.h b/Libraries/LibHTML/TreeNode.h index a4da2f1f9ba..36459c5c775 100644 --- a/Libraries/LibHTML/TreeNode.h +++ b/Libraries/LibHTML/TreeNode.h @@ -33,7 +33,7 @@ public: const T* first_child() const { return m_first_child; } const T* last_child() const { return m_last_child; } - void append_child(NonnullRefPtr node); + void append_child(NonnullRefPtr node, bool call_inserted_into = true); void donate_all_children_to(T& node); protected: @@ -49,16 +49,19 @@ private: }; template -inline void TreeNode::append_child(NonnullRefPtr node) +inline void TreeNode::append_child(NonnullRefPtr node, bool call_inserted_into) { ASSERT(!node->m_parent); if (m_last_child) m_last_child->m_next_sibling = node.ptr(); node->m_previous_sibling = m_last_child; node->m_parent = static_cast(this); - m_last_child = &node.leak_ref(); + m_last_child = node.ptr(); if (!m_first_child) m_first_child = m_last_child; + if (call_inserted_into) + node->inserted_into(static_cast(*this)); + (void)node.leak_ref(); } template