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 @@ + + +