From 6df4e5f5e75d7d6d439d1365ed7bed4fd2a8a1da Mon Sep 17 00:00:00 2001 From: Luke Wilde Date: Tue, 12 Nov 2024 18:08:49 +0000 Subject: [PATCH] LibWeb: Actually traverse the shadow root of the inclusive descendant Previously, the inclusive descendant, which is the node that for_each_shadow_including_inclusive_descendant was called on, would not have it's shadow root traversed if it had one. This is because the shadow root traversal was in the `for` loop, which begins with the node's first child. The fix here is to move the shadow root traversal outside of the loop, and check if the current node is an element instead. --- Libraries/LibWeb/DOM/ShadowRoot.h | 34 ++++++++++++------- ...boundary-of-inserted-node-is-traversed.txt | 1 + ...oundary-of-inserted-node-is-traversed.html | 14 ++++++++ 3 files changed, 37 insertions(+), 12 deletions(-) create mode 100644 Tests/LibWeb/Text/expected/DOM/shadow-root-boundary-of-inserted-node-is-traversed.txt create mode 100644 Tests/LibWeb/Text/input/DOM/shadow-root-boundary-of-inserted-node-is-traversed.html diff --git a/Libraries/LibWeb/DOM/ShadowRoot.h b/Libraries/LibWeb/DOM/ShadowRoot.h index f1c5fa92fe0..dd73fef68f6 100644 --- a/Libraries/LibWeb/DOM/ShadowRoot.h +++ b/Libraries/LibWeb/DOM/ShadowRoot.h @@ -97,21 +97,37 @@ private: template<> inline bool Node::fast_is() const { return node_type() == to_underlying(NodeType::DOCUMENT_FRAGMENT_NODE) && is_shadow_root(); } +// https://dom.spec.whatwg.org/#concept-shadow-including-tree-order +// In shadow-including tree order is shadow-including preorder, depth-first traversal of a node tree. +// Shadow-including preorder, depth-first traversal of a node tree tree is preorder, depth-first traversal +// of tree, with for each shadow host encountered in tree, shadow-including preorder, depth-first traversal +// of that element’s shadow root’s node tree just after it is encountered. + +// https://dom.spec.whatwg.org/#concept-shadow-including-descendant +// An object A is a shadow-including descendant of an object B, if A is a descendant of B, or A’s root is a +// shadow root and A’s root’s host is a shadow-including inclusive descendant of B. + +// https://dom.spec.whatwg.org/#concept-shadow-including-inclusive-descendant +// A shadow-including inclusive descendant is an object or one of its shadow-including descendants. + template inline TraversalDecision Node::for_each_shadow_including_inclusive_descendant(Callback callback) { if (callback(*this) == TraversalDecision::Break) return TraversalDecision::Break; - for (auto* child = first_child(); child; child = child->next_sibling()) { - if (child->is_element()) { - if (auto shadow_root = static_cast(child)->shadow_root()) { - if (shadow_root->for_each_shadow_including_inclusive_descendant(callback) == TraversalDecision::Break) - return TraversalDecision::Break; - } + + if (is_element()) { + if (auto shadow_root = static_cast(this)->shadow_root()) { + if (shadow_root->for_each_shadow_including_inclusive_descendant(callback) == TraversalDecision::Break) + return TraversalDecision::Break; } + } + + for (auto* child = first_child(); child; child = child->next_sibling()) { if (child->for_each_shadow_including_inclusive_descendant(callback) == TraversalDecision::Break) return TraversalDecision::Break; } + return TraversalDecision::Continue; } @@ -119,12 +135,6 @@ template inline TraversalDecision Node::for_each_shadow_including_descendant(Callback callback) { for (auto* child = first_child(); child; child = child->next_sibling()) { - if (child->is_element()) { - if (JS::GCPtr shadow_root = static_cast(child)->shadow_root()) { - if (shadow_root->for_each_shadow_including_inclusive_descendant(callback) == TraversalDecision::Break) - return TraversalDecision::Break; - } - } if (child->for_each_shadow_including_inclusive_descendant(callback) == TraversalDecision::Break) return TraversalDecision::Break; } diff --git a/Tests/LibWeb/Text/expected/DOM/shadow-root-boundary-of-inserted-node-is-traversed.txt b/Tests/LibWeb/Text/expected/DOM/shadow-root-boundary-of-inserted-node-is-traversed.txt new file mode 100644 index 00000000000..2bfbd60d9c4 --- /dev/null +++ b/Tests/LibWeb/Text/expected/DOM/shadow-root-boundary-of-inserted-node-is-traversed.txt @@ -0,0 +1 @@ +Hello from script in the shadow root of the just inserted div! diff --git a/Tests/LibWeb/Text/input/DOM/shadow-root-boundary-of-inserted-node-is-traversed.html b/Tests/LibWeb/Text/input/DOM/shadow-root-boundary-of-inserted-node-is-traversed.html new file mode 100644 index 00000000000..b545db3d620 --- /dev/null +++ b/Tests/LibWeb/Text/input/DOM/shadow-root-boundary-of-inserted-node-is-traversed.html @@ -0,0 +1,14 @@ + + +