mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-07 00:29:15 +00:00
LibWeb/DOM: Inherit Node from TreeNode
This allows to delete lots of tree helper functions duplicated between Node and TreeNode.
This commit is contained in:
parent
ec6201806f
commit
dfcee2bbdf
Notes:
github-actions[bot]
2025-02-03 17:38:11 +00:00
Author: https://github.com/kalenikaliaksandr
Commit: dfcee2bbdf
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3434
Reviewed-by: https://github.com/awesomekling
Reviewed-by: https://github.com/gmta ✅
2 changed files with 8 additions and 355 deletions
|
@ -107,12 +107,8 @@ void Node::finalize()
|
||||||
void Node::visit_edges(Cell::Visitor& visitor)
|
void Node::visit_edges(Cell::Visitor& visitor)
|
||||||
{
|
{
|
||||||
Base::visit_edges(visitor);
|
Base::visit_edges(visitor);
|
||||||
|
TreeNode::visit_edges(visitor);
|
||||||
visitor.visit(m_document);
|
visitor.visit(m_document);
|
||||||
visitor.visit(m_parent);
|
|
||||||
visitor.visit(m_first_child);
|
|
||||||
visitor.visit(m_last_child);
|
|
||||||
visitor.visit(m_next_sibling);
|
|
||||||
visitor.visit(m_previous_sibling);
|
|
||||||
visitor.visit(m_child_nodes);
|
visitor.visit(m_child_nodes);
|
||||||
|
|
||||||
visitor.visit(m_layout_node);
|
visitor.visit(m_layout_node);
|
||||||
|
@ -2292,75 +2288,24 @@ void Node::queue_tree_mutation_record(Vector<GC::Root<Node>> added_nodes, Vector
|
||||||
|
|
||||||
void Node::append_child_impl(GC::Ref<Node> node)
|
void Node::append_child_impl(GC::Ref<Node> node)
|
||||||
{
|
{
|
||||||
VERIFY(!node->m_parent);
|
VERIFY(!node->parent());
|
||||||
|
|
||||||
if (!is_child_allowed(*node))
|
if (!is_child_allowed(*node))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (m_last_child)
|
TreeNode::append_child(node);
|
||||||
m_last_child->m_next_sibling = node.ptr();
|
|
||||||
node->m_previous_sibling = m_last_child;
|
|
||||||
node->m_parent = this;
|
|
||||||
m_last_child = node.ptr();
|
|
||||||
if (!m_first_child)
|
|
||||||
m_first_child = m_last_child;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::insert_before_impl(GC::Ref<Node> node, GC::Ptr<Node> child)
|
void Node::insert_before_impl(GC::Ref<Node> node, GC::Ptr<Node> child)
|
||||||
{
|
{
|
||||||
if (!child)
|
if (!child)
|
||||||
return append_child_impl(move(node));
|
return append_child_impl(move(node));
|
||||||
|
TreeNode::insert_before(node, child);
|
||||||
VERIFY(!node->m_parent);
|
|
||||||
VERIFY(child->parent() == this);
|
|
||||||
|
|
||||||
node->m_previous_sibling = child->m_previous_sibling;
|
|
||||||
node->m_next_sibling = child;
|
|
||||||
|
|
||||||
if (child->m_previous_sibling)
|
|
||||||
child->m_previous_sibling->m_next_sibling = node;
|
|
||||||
|
|
||||||
if (m_first_child == child)
|
|
||||||
m_first_child = node;
|
|
||||||
|
|
||||||
child->m_previous_sibling = node;
|
|
||||||
|
|
||||||
node->m_parent = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Node::remove_child_impl(GC::Ref<Node> node)
|
void Node::remove_child_impl(GC::Ref<Node> node)
|
||||||
{
|
{
|
||||||
VERIFY(node->m_parent.ptr() == this);
|
TreeNode::remove_child(node);
|
||||||
|
|
||||||
if (m_first_child == node)
|
|
||||||
m_first_child = node->m_next_sibling;
|
|
||||||
|
|
||||||
if (m_last_child == node)
|
|
||||||
m_last_child = node->m_previous_sibling;
|
|
||||||
|
|
||||||
if (node->m_next_sibling)
|
|
||||||
node->m_next_sibling->m_previous_sibling = node->m_previous_sibling;
|
|
||||||
|
|
||||||
if (node->m_previous_sibling)
|
|
||||||
node->m_previous_sibling->m_next_sibling = node->m_next_sibling;
|
|
||||||
|
|
||||||
node->m_next_sibling = nullptr;
|
|
||||||
node->m_previous_sibling = nullptr;
|
|
||||||
node->m_parent = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Node::is_ancestor_of(Node const& other) const
|
|
||||||
{
|
|
||||||
for (auto* ancestor = other.parent(); ancestor; ancestor = ancestor->parent()) {
|
|
||||||
if (ancestor == this)
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Node::is_inclusive_ancestor_of(Node const& other) const
|
|
||||||
{
|
|
||||||
return &other == this || is_ancestor_of(other);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Node::is_descendant_of(Node const& other) const
|
bool Node::is_descendant_of(Node const& other) const
|
||||||
|
|
|
@ -6,12 +6,10 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <AK/Badge.h>
|
|
||||||
#include <AK/DistinctNumeric.h>
|
#include <AK/DistinctNumeric.h>
|
||||||
#include <AK/FlyString.h>
|
#include <AK/FlyString.h>
|
||||||
#include <AK/GenericShorthands.h>
|
#include <AK/GenericShorthands.h>
|
||||||
#include <AK/JsonObjectSerializer.h>
|
#include <AK/JsonObjectSerializer.h>
|
||||||
#include <AK/RefPtr.h>
|
|
||||||
#include <AK/TypeCasts.h>
|
#include <AK/TypeCasts.h>
|
||||||
#include <AK/Vector.h>
|
#include <AK/Vector.h>
|
||||||
#include <LibWeb/CSS/InvalidationSet.h>
|
#include <LibWeb/CSS/InvalidationSet.h>
|
||||||
|
@ -20,6 +18,7 @@
|
||||||
#include <LibWeb/DOM/Slottable.h>
|
#include <LibWeb/DOM/Slottable.h>
|
||||||
#include <LibWeb/DOMParsing/XMLSerializer.h>
|
#include <LibWeb/DOMParsing/XMLSerializer.h>
|
||||||
#include <LibWeb/TraversalDecision.h>
|
#include <LibWeb/TraversalDecision.h>
|
||||||
|
#include <LibWeb/TreeNode.h>
|
||||||
#include <LibWeb/WebIDL/ExceptionOr.h>
|
#include <LibWeb/WebIDL/ExceptionOr.h>
|
||||||
|
|
||||||
namespace Web::DOM {
|
namespace Web::DOM {
|
||||||
|
@ -104,7 +103,8 @@ enum class StyleInvalidationReason {
|
||||||
#undef __ENUMERATE_STYLE_INVALIDATION_REASON
|
#undef __ENUMERATE_STYLE_INVALIDATION_REASON
|
||||||
};
|
};
|
||||||
|
|
||||||
class Node : public EventTarget {
|
class Node : public EventTarget
|
||||||
|
, public TreeNode<Node> {
|
||||||
WEB_PLATFORM_OBJECT(Node, EventTarget);
|
WEB_PLATFORM_OBJECT(Node, EventTarget);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -381,19 +381,6 @@ public:
|
||||||
|
|
||||||
Slottable as_slottable();
|
Slottable as_slottable();
|
||||||
|
|
||||||
Node* parent() { return m_parent.ptr(); }
|
|
||||||
Node const* parent() const { return m_parent.ptr(); }
|
|
||||||
|
|
||||||
bool has_children() const { return m_first_child; }
|
|
||||||
Node* next_sibling() { return m_next_sibling.ptr(); }
|
|
||||||
Node* previous_sibling() { return m_previous_sibling.ptr(); }
|
|
||||||
Node* first_child() { return m_first_child.ptr(); }
|
|
||||||
Node* last_child() { return m_last_child.ptr(); }
|
|
||||||
Node const* next_sibling() const { return m_next_sibling.ptr(); }
|
|
||||||
Node const* previous_sibling() const { return m_previous_sibling.ptr(); }
|
|
||||||
Node const* first_child() const { return m_first_child.ptr(); }
|
|
||||||
Node const* last_child() const { return m_last_child.ptr(); }
|
|
||||||
|
|
||||||
size_t child_count() const
|
size_t child_count() const
|
||||||
{
|
{
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
|
@ -418,80 +405,11 @@ public:
|
||||||
return const_cast<Node*>(this)->child_at_index(index);
|
return const_cast<Node*>(this)->child_at_index(index);
|
||||||
}
|
}
|
||||||
|
|
||||||
// https://dom.spec.whatwg.org/#concept-tree-index
|
|
||||||
size_t index() const
|
|
||||||
{
|
|
||||||
// The index of an object is its number of preceding siblings, or 0 if it has none.
|
|
||||||
size_t index = 0;
|
|
||||||
for (auto* node = previous_sibling(); node; node = node->previous_sibling())
|
|
||||||
++index;
|
|
||||||
return index;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_ancestor_of(Node const&) const;
|
|
||||||
bool is_inclusive_ancestor_of(Node const&) const;
|
|
||||||
bool is_descendant_of(Node const&) const;
|
bool is_descendant_of(Node const&) const;
|
||||||
bool is_inclusive_descendant_of(Node const&) const;
|
bool is_inclusive_descendant_of(Node const&) const;
|
||||||
|
|
||||||
bool is_following(Node const&) const;
|
bool is_following(Node const&) const;
|
||||||
|
|
||||||
Node* next_in_pre_order()
|
|
||||||
{
|
|
||||||
if (first_child())
|
|
||||||
return first_child();
|
|
||||||
Node* node;
|
|
||||||
if (!(node = next_sibling())) {
|
|
||||||
node = parent();
|
|
||||||
while (node && !node->next_sibling())
|
|
||||||
node = node->parent();
|
|
||||||
if (node)
|
|
||||||
node = node->next_sibling();
|
|
||||||
}
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node* next_in_pre_order(Node const* stay_within)
|
|
||||||
{
|
|
||||||
if (first_child())
|
|
||||||
return first_child();
|
|
||||||
|
|
||||||
Node* node = static_cast<Node*>(this);
|
|
||||||
Node* next = nullptr;
|
|
||||||
while (!(next = node->next_sibling())) {
|
|
||||||
node = node->parent();
|
|
||||||
if (!node || node == stay_within)
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
return next;
|
|
||||||
}
|
|
||||||
|
|
||||||
Node const* next_in_pre_order() const
|
|
||||||
{
|
|
||||||
return const_cast<Node*>(this)->next_in_pre_order();
|
|
||||||
}
|
|
||||||
|
|
||||||
Node const* next_in_pre_order(Node const* stay_within) const
|
|
||||||
{
|
|
||||||
return const_cast<Node*>(this)->next_in_pre_order(stay_within);
|
|
||||||
}
|
|
||||||
|
|
||||||
Node* previous_in_pre_order()
|
|
||||||
{
|
|
||||||
if (auto* node = previous_sibling()) {
|
|
||||||
while (node->last_child())
|
|
||||||
node = node->last_child();
|
|
||||||
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
return parent();
|
|
||||||
}
|
|
||||||
|
|
||||||
Node const* previous_in_pre_order() const
|
|
||||||
{
|
|
||||||
return const_cast<Node*>(this)->previous_in_pre_order();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool is_before(Node const& other) const
|
bool is_before(Node const& other) const
|
||||||
{
|
{
|
||||||
if (this == &other)
|
if (this == &other)
|
||||||
|
@ -525,98 +443,6 @@ public:
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callback>
|
|
||||||
TraversalDecision for_each_in_inclusive_subtree(Callback callback) const
|
|
||||||
{
|
|
||||||
if (auto decision = callback(static_cast<Node const&>(*this)); decision != TraversalDecision::Continue)
|
|
||||||
return decision;
|
|
||||||
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
|
||||||
if (child->for_each_in_inclusive_subtree(callback) == TraversalDecision::Break)
|
|
||||||
return TraversalDecision::Break;
|
|
||||||
}
|
|
||||||
return TraversalDecision::Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Callback>
|
|
||||||
TraversalDecision for_each_in_inclusive_subtree(Callback callback)
|
|
||||||
{
|
|
||||||
if (auto decision = callback(static_cast<Node&>(*this)); decision != TraversalDecision::Continue)
|
|
||||||
return decision;
|
|
||||||
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
|
||||||
if (child->for_each_in_inclusive_subtree(callback) == TraversalDecision::Break)
|
|
||||||
return TraversalDecision::Break;
|
|
||||||
}
|
|
||||||
return TraversalDecision::Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U, typename Callback>
|
|
||||||
TraversalDecision for_each_in_inclusive_subtree_of_type(Callback callback)
|
|
||||||
{
|
|
||||||
if (auto* maybe_node_of_type = as_if<U>(static_cast<Node&>(*this))) {
|
|
||||||
if (auto decision = callback(*maybe_node_of_type); decision != TraversalDecision::Continue)
|
|
||||||
return decision;
|
|
||||||
}
|
|
||||||
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
|
||||||
if (child->template for_each_in_inclusive_subtree_of_type<U>(callback) == TraversalDecision::Break)
|
|
||||||
return TraversalDecision::Break;
|
|
||||||
}
|
|
||||||
return TraversalDecision::Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U, typename Callback>
|
|
||||||
TraversalDecision for_each_in_inclusive_subtree_of_type(Callback callback) const
|
|
||||||
{
|
|
||||||
if (auto* maybe_node_of_type = as_if<U>(static_cast<Node const&>(*this))) {
|
|
||||||
if (auto decision = callback(*maybe_node_of_type); decision != TraversalDecision::Continue)
|
|
||||||
return decision;
|
|
||||||
}
|
|
||||||
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
|
||||||
if (child->template for_each_in_inclusive_subtree_of_type<U>(callback) == TraversalDecision::Break)
|
|
||||||
return TraversalDecision::Break;
|
|
||||||
}
|
|
||||||
return TraversalDecision::Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Callback>
|
|
||||||
TraversalDecision for_each_in_subtree(Callback callback) const
|
|
||||||
{
|
|
||||||
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
|
||||||
if (child->for_each_in_inclusive_subtree(callback) == TraversalDecision::Break)
|
|
||||||
return TraversalDecision::Break;
|
|
||||||
}
|
|
||||||
return TraversalDecision::Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Callback>
|
|
||||||
TraversalDecision for_each_in_subtree(Callback callback)
|
|
||||||
{
|
|
||||||
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
|
||||||
if (child->for_each_in_inclusive_subtree(callback) == TraversalDecision::Break)
|
|
||||||
return TraversalDecision::Break;
|
|
||||||
}
|
|
||||||
return TraversalDecision::Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U, typename Callback>
|
|
||||||
TraversalDecision for_each_in_subtree_of_type(Callback callback)
|
|
||||||
{
|
|
||||||
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
|
||||||
if (child->template for_each_in_inclusive_subtree_of_type<U>(callback) == TraversalDecision::Break)
|
|
||||||
return TraversalDecision::Break;
|
|
||||||
}
|
|
||||||
return TraversalDecision::Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U, typename Callback>
|
|
||||||
TraversalDecision for_each_in_subtree_of_type(Callback callback) const
|
|
||||||
{
|
|
||||||
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
|
||||||
if (child->template for_each_in_inclusive_subtree_of_type<U>(callback) == TraversalDecision::Break)
|
|
||||||
return TraversalDecision::Break;
|
|
||||||
}
|
|
||||||
return TraversalDecision::Continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Callback>
|
template<typename Callback>
|
||||||
void for_each_ancestor(Callback callback) const
|
void for_each_ancestor(Callback callback) const
|
||||||
{
|
{
|
||||||
|
@ -647,38 +473,6 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename Callback>
|
|
||||||
void for_each_child(Callback callback) const
|
|
||||||
{
|
|
||||||
return const_cast<Node*>(this)->for_each_child(move(callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Callback>
|
|
||||||
void for_each_child(Callback callback)
|
|
||||||
{
|
|
||||||
for (auto* node = first_child(); node; node = node->next_sibling()) {
|
|
||||||
if (callback(*node) == IterationDecision::Break)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U, typename Callback>
|
|
||||||
void for_each_child_of_type(Callback callback)
|
|
||||||
{
|
|
||||||
for (auto* node = first_child(); node; node = node->next_sibling()) {
|
|
||||||
if (auto* maybe_child_of_type = as_if<U>(node)) {
|
|
||||||
if (callback(*maybe_child_of_type) == IterationDecision::Break)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U, typename Callback>
|
|
||||||
void for_each_child_of_type(Callback callback) const
|
|
||||||
{
|
|
||||||
return const_cast<Node*>(this)->template for_each_child_of_type<U>(move(callback));
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U, typename Callback>
|
template<typename U, typename Callback>
|
||||||
WebIDL::ExceptionOr<void> for_each_child_of_type_fallible(Callback callback)
|
WebIDL::ExceptionOr<void> for_each_child_of_type_fallible(Callback callback)
|
||||||
{
|
{
|
||||||
|
@ -691,92 +485,12 @@ public:
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
U const* next_sibling_of_type() const
|
|
||||||
{
|
|
||||||
return const_cast<Node*>(this)->template next_sibling_of_type<U>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
inline U* next_sibling_of_type()
|
|
||||||
{
|
|
||||||
for (auto* sibling = next_sibling(); sibling; sibling = sibling->next_sibling()) {
|
|
||||||
if (auto* maybe_sibling_of_type = as_if<U>(*sibling))
|
|
||||||
return maybe_sibling_of_type;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
U const* previous_sibling_of_type() const
|
|
||||||
{
|
|
||||||
return const_cast<Node*>(this)->template previous_sibling_of_type<U>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
U* previous_sibling_of_type()
|
|
||||||
{
|
|
||||||
for (auto* sibling = previous_sibling(); sibling; sibling = sibling->previous_sibling()) {
|
|
||||||
if (auto* maybe_sibling_of_type = as_if<U>(*sibling))
|
|
||||||
return maybe_sibling_of_type;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
U const* first_child_of_type() const
|
|
||||||
{
|
|
||||||
return const_cast<Node*>(this)->template first_child_of_type<U>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
U const* last_child_of_type() const
|
|
||||||
{
|
|
||||||
return const_cast<Node*>(this)->template last_child_of_type<U>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
U* first_child_of_type()
|
|
||||||
{
|
|
||||||
for (auto* child = first_child(); child; child = child->next_sibling()) {
|
|
||||||
if (auto* maybe_child_of_type = as_if<U>(*child))
|
|
||||||
return maybe_child_of_type;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
U* last_child_of_type()
|
|
||||||
{
|
|
||||||
for (auto* child = last_child(); child; child = child->previous_sibling()) {
|
|
||||||
if (auto* maybe_child_of_type = as_if<U>(*child))
|
|
||||||
return maybe_child_of_type;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
bool has_child_of_type() const
|
bool has_child_of_type() const
|
||||||
{
|
{
|
||||||
return first_child_of_type<U>() != nullptr;
|
return first_child_of_type<U>() != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
U const* first_ancestor_of_type() const
|
|
||||||
{
|
|
||||||
return const_cast<Node*>(this)->template first_ancestor_of_type<U>();
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
|
||||||
U* first_ancestor_of_type()
|
|
||||||
{
|
|
||||||
for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) {
|
|
||||||
if (auto* maybe_ancestor_of_type = as_if<U>(*ancestor))
|
|
||||||
return maybe_ancestor_of_type;
|
|
||||||
}
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename U>
|
template<typename U>
|
||||||
U const* shadow_including_first_ancestor_of_type() const
|
U const* shadow_including_first_ancestor_of_type() const
|
||||||
{
|
{
|
||||||
|
@ -843,12 +557,6 @@ private:
|
||||||
|
|
||||||
static Optional<StringView> first_valid_id(StringView, Document const&);
|
static Optional<StringView> first_valid_id(StringView, Document const&);
|
||||||
|
|
||||||
GC::Ptr<Node> m_parent;
|
|
||||||
GC::Ptr<Node> m_first_child;
|
|
||||||
GC::Ptr<Node> m_last_child;
|
|
||||||
GC::Ptr<Node> m_next_sibling;
|
|
||||||
GC::Ptr<Node> m_previous_sibling;
|
|
||||||
|
|
||||||
GC::Ptr<NodeList> m_child_nodes;
|
GC::Ptr<NodeList> m_child_nodes;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue