diff --git a/Libraries/LibWeb/DOM/Node.cpp b/Libraries/LibWeb/DOM/Node.cpp index be20b94fc6c..58e3bbbccca 100644 --- a/Libraries/LibWeb/DOM/Node.cpp +++ b/Libraries/LibWeb/DOM/Node.cpp @@ -575,17 +575,6 @@ String Node::child_text_content() const return MUST(builder.to_string()); } -// https://dom.spec.whatwg.org/#concept-tree-root -Node& Node::root() -{ - // The root of an object is itself, if its parent is null, or else it is the root of its parent. - // The root of a tree is any object participating in that tree whose parent is null. - Node* root = this; - while (root->parent()) - root = root->parent(); - return *root; -} - // https://dom.spec.whatwg.org/#concept-shadow-including-root Node& Node::shadow_including_root() { @@ -1977,13 +1966,6 @@ bool Node::is_scripting_disabled() const return !is_scripting_enabled(); } -// https://dom.spec.whatwg.org/#dom-node-contains -bool Node::contains(GC::Ptr other) const -{ - // The contains(other) method steps are to return true if other is an inclusive descendant of this; otherwise false (including when other is null). - return other && other->is_inclusive_descendant_of(*this); -} - // https://dom.spec.whatwg.org/#concept-shadow-including-descendant bool Node::is_shadow_including_descendant_of(Node const& other) const { @@ -2588,28 +2570,6 @@ void Node::remove_child_impl(GC::Ref node) TreeNode::remove_child(node); } -bool Node::is_descendant_of(Node const& other) const -{ - return other.is_ancestor_of(*this); -} - -bool Node::is_inclusive_descendant_of(Node const& other) const -{ - return other.is_inclusive_ancestor_of(*this); -} - -// https://dom.spec.whatwg.org/#concept-tree-following -bool Node::is_following(Node const& other) const -{ - // An object A is following an object B if A and B are in the same tree and A comes after B in tree order. - for (auto* node = previous_in_pre_order(); node; node = node->previous_in_pre_order()) { - if (node == &other) - return true; - } - - return false; -} - void Node::build_accessibility_tree(AccessibilityTreeNode& parent) { if (is_uninteresting_whitespace_node()) diff --git a/Libraries/LibWeb/DOM/Node.h b/Libraries/LibWeb/DOM/Node.h index 43b0531631c..3a76ac86ad7 100644 --- a/Libraries/LibWeb/DOM/Node.h +++ b/Libraries/LibWeb/DOM/Node.h @@ -280,12 +280,6 @@ public: String child_text_content() const; - Node& root(); - Node const& root() const - { - return const_cast(this)->root(); - } - Node& shadow_including_root(); Node const& shadow_including_root() const { @@ -376,8 +370,6 @@ public: bool is_scripting_enabled() const; bool is_scripting_disabled() const; - bool contains(GC::Ptr) const; - // Used for dumping the DOM Tree void serialize_tree_as_json(JsonObjectSerializer&) const; @@ -424,98 +416,6 @@ public: Slottable as_slottable(); - size_t child_count() const - { - size_t count = 0; - for (auto* child = first_child(); child; child = child->next_sibling()) - ++count; - return count; - } - - Node* child_at_index(int index) - { - int count = 0; - for (auto* child = first_child(); child; child = child->next_sibling()) { - if (count == index) - return child; - ++count; - } - return nullptr; - } - - Node const* child_at_index(int index) const - { - return const_cast(this)->child_at_index(index); - } - - bool is_descendant_of(Node const&) const; - bool is_inclusive_descendant_of(Node const&) const; - - bool is_following(Node const&) const; - - bool is_before(Node const& other) const - { - if (this == &other) - return false; - for (auto* node = this; node; node = node->next_in_pre_order()) { - if (node == &other) - return true; - } - return false; - } - - // https://dom.spec.whatwg.org/#concept-tree-preceding (Object A is 'typename U' and Object B is 'this') - template - bool has_preceding_node_of_type_in_tree_order() const - { - for (auto* node = previous_in_pre_order(); node; node = node->previous_in_pre_order()) { - if (is(node)) - return true; - } - return false; - } - - // https://dom.spec.whatwg.org/#concept-tree-following (Object A is 'typename U' and Object B is 'this') - template - bool has_following_node_of_type_in_tree_order() const - { - for (auto* node = next_in_pre_order(); node; node = node->next_in_pre_order()) { - if (is(node)) - return true; - } - return false; - } - - template - void for_each_ancestor(Callback callback) const - { - return const_cast(this)->for_each_ancestor(move(callback)); - } - - template - void for_each_ancestor(Callback callback) - { - for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) { - if (callback(*ancestor) == IterationDecision::Break) - break; - } - } - - template - void for_each_inclusive_ancestor(Callback callback) const - { - return const_cast(this)->for_each_inclusive_ancestor(move(callback)); - } - - template - void for_each_inclusive_ancestor(Callback callback) - { - for (auto* ancestor = this; ancestor; ancestor = ancestor->parent()) { - if (callback(*ancestor) == IterationDecision::Break) - break; - } - } - template WebIDL::ExceptionOr for_each_child_of_type_fallible(Callback callback) { @@ -527,13 +427,6 @@ public: } return {}; } - - template - bool has_child_of_type() const - { - return first_child_of_type() != nullptr; - } - template U const* shadow_including_first_ancestor_of_type() const { @@ -543,15 +436,6 @@ public: template U* shadow_including_first_ancestor_of_type(); - bool is_parent_of(Node const& other) const - { - for (auto* child = first_child(); child; child = child->next_sibling()) { - if (&other == child) - return true; - } - return false; - } - ErrorOr accessible_name(Document const&, ShouldComputeRole = ShouldComputeRole::Yes) const; ErrorOr accessible_description(Document const&) const; diff --git a/Libraries/LibWeb/TreeNode.h b/Libraries/LibWeb/TreeNode.h index 9407764e4dc..ff7165056b6 100644 --- a/Libraries/LibWeb/TreeNode.h +++ b/Libraries/LibWeb/TreeNode.h @@ -72,8 +72,57 @@ public: return index; } + // // https://dom.spec.whatwg.org/#concept-tree-root + T& root() + { + // The root of an object is itself, if its parent is null, or else it is the root of its parent. + // The root of a tree is any object participating in that tree whose parent is null. + T* root = static_cast(this); + while (root->parent()) + root = root->parent(); + return *root; + } + T const& root() const { return const_cast(this)->root(); } + bool is_ancestor_of(TreeNode const&) const; bool is_inclusive_ancestor_of(TreeNode const&) const; + bool contains(GC::Ptr) const; + bool is_descendant_of(TreeNode const&) const; + bool is_inclusive_descendant_of(TreeNode const&) const; + + bool is_following(TreeNode const&) const; + bool is_before(TreeNode const&) const; + + // https://dom.spec.whatwg.org/#concept-tree-preceding (Object A is 'typename U' and Object B is 'this') + template + bool has_preceding_node_of_type_in_tree_order() const + { + for (auto* node = previous_in_pre_order(); node; node = node->previous_in_pre_order()) { + if (is(node)) + return true; + } + return false; + } + + // https://dom.spec.whatwg.org/#concept-tree-following (Object A is 'typename U' and Object B is 'this') + template + bool has_following_node_of_type_in_tree_order() const + { + for (auto* node = next_in_pre_order(); node; node = node->next_in_pre_order()) { + if (is(node)) + return true; + } + return false; + } + + bool is_parent_of(TreeNode const& other) const + { + for (auto* child = first_child(); child; child = child->next_sibling()) { + if (&other == child) + return true; + } + return false; + } void append_child(GC::Ref node); void prepend_child(GC::Ref node); @@ -87,6 +136,30 @@ public: m_parent->remove_child(*static_cast(this)); } + size_t child_count() const + { + size_t count = 0; + for (auto* child = first_child(); child; child = child->next_sibling()) + ++count; + return count; + } + + T* child_at_index(int index) + { + int count = 0; + for (auto* child = first_child(); child; child = child->next_sibling()) { + if (count == index) + return child; + ++count; + } + return nullptr; + } + + T const* child_at_index(int index) const + { + return const_cast(this)->child_at_index(index); + } + T* next_in_pre_order() { if (first_child()) @@ -280,6 +353,12 @@ public: return nullptr; } + template + bool has_child_of_type() const + { + return first_child_of_type() != nullptr; + } + template U const* first_child_of_type() const { @@ -328,6 +407,36 @@ public: return nullptr; } + template + void for_each_ancestor(Callback callback) const + { + return const_cast(this)->for_each_ancestor(move(callback)); + } + + template + void for_each_ancestor(Callback callback) + { + for (auto* ancestor = parent(); ancestor; ancestor = ancestor->parent()) { + if (callback(static_cast(*ancestor)) == IterationDecision::Break) + break; + } + } + + template + void for_each_inclusive_ancestor(Callback callback) const + { + return const_cast(this)->for_each_inclusive_ancestor(move(callback)); + } + + template + void for_each_inclusive_ancestor(Callback callback) + { + for (auto* ancestor = this; ancestor; ancestor = ancestor->parent()) { + if (callback(static_cast(*ancestor)) == IterationDecision::Break) + break; + } + } + ~TreeNode() = default; protected: @@ -464,4 +573,49 @@ inline bool TreeNode::is_inclusive_ancestor_of(TreeNode const& other) cons return &other == this || is_ancestor_of(other); } +// https://dom.spec.whatwg.org/#dom-node-contains +template +inline bool TreeNode::contains(GC::Ptr other) const +{ + // The contains(other) method steps are to return true if other is an inclusive descendant of this; otherwise false (including when other is null). + return other && other->is_inclusive_descendant_of(*this); +} + +template +inline bool TreeNode::is_descendant_of(TreeNode const& other) const +{ + return other.is_ancestor_of(*this); +} + +template +inline bool TreeNode::is_inclusive_descendant_of(TreeNode const& other) const +{ + return other.is_inclusive_ancestor_of(*this); +} + +// https://dom.spec.whatwg.org/#concept-tree-following +template +inline bool TreeNode::is_following(TreeNode const& other) const +{ + // An object A is following an object B if A and B are in the same tree and A comes after B in tree order. + for (auto* node = previous_in_pre_order(); node; node = node->previous_in_pre_order()) { + if (node == &other) + return true; + } + + return false; +} + +template +inline bool TreeNode::is_before(TreeNode const& other) const +{ + if (this == &other) + return false; + for (auto* node = this; node; node = node->next_in_pre_order()) { + if (node == &other) + return true; + } + return false; +} + }