mirror of
https://github.com/lightpanda-io/browser.git
synced 2026-07-30 17:25:58 -04:00
webapi: TreeWalker sibling traversal follows the spec algorithm
Fixes WPT /dom/traversal/TreeWalker-previousSiblingLastChildSkip.html and 59 subtests of TreeWalker.html (701/761 -> 760/761): TreeWalker.previousSibling()/nextSibling() only scanned the current node's direct siblings, but the spec's "traverse siblings" algorithm also: - descends into a skipped (FILTER_SKIP) sibling's children - only a rejected sibling excludes its whole subtree - so from B2 with B1 skipped, previousSibling() must return B1's last child; - climbs to the parent when the siblings are exhausted and continues from the parent's siblings, stopping at the root or at an accepted parent. Both directions now share the spec's traverseSiblings implementation. Coverage: - /dom/traversal/TreeWalker-previousSiblingLastChildSkip.html 0/1 -> 1/1 (fully green) - /dom/traversal/TreeWalker.html 701/761 -> 760/761 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
committed by
Karl Seguin
parent
df94585d0a
commit
ee97f3b888
@@ -174,27 +174,52 @@ pub fn lastChild(self: *DOMTreeWalker, frame: *Frame) !?*Node {
|
||||
}
|
||||
|
||||
pub fn previousSibling(self: *DOMTreeWalker, frame: *Frame) !?*Node {
|
||||
var node = self.previousSiblingOrNull(self._current);
|
||||
while (node) |n| {
|
||||
if (try self.acceptNode(n, frame) == NodeFilter.FILTER_ACCEPT) {
|
||||
self._current = n;
|
||||
return n;
|
||||
}
|
||||
node = self.previousSiblingOrNull(n);
|
||||
}
|
||||
return null;
|
||||
return self.traverseSiblings(.previous, frame);
|
||||
}
|
||||
|
||||
pub fn nextSibling(self: *DOMTreeWalker, frame: *Frame) !?*Node {
|
||||
var node = self.nextSiblingOrNull(self._current);
|
||||
while (node) |n| {
|
||||
if (try self.acceptNode(n, frame) == NodeFilter.FILTER_ACCEPT) {
|
||||
self._current = n;
|
||||
return n;
|
||||
return self.traverseSiblings(.next, frame);
|
||||
}
|
||||
|
||||
// The spec's "traverse siblings" algorithm: a skipped (but not rejected)
|
||||
// sibling's children are still candidates, and when the siblings run out the
|
||||
// walk climbs to the parent and continues from its siblings, stopping at the
|
||||
// root or at an accepted parent.
|
||||
fn traverseSiblings(self: *DOMTreeWalker, comptime direction: enum { next, previous }, frame: *Frame) !?*Node {
|
||||
var node = self._current;
|
||||
if (node == self._root) return null;
|
||||
|
||||
while (true) {
|
||||
var sibling: ?*Node = if (direction == .next)
|
||||
self.nextSiblingOrNull(node)
|
||||
else
|
||||
self.previousSiblingOrNull(node);
|
||||
|
||||
while (sibling) |sib| {
|
||||
node = sib;
|
||||
const result = try self.acceptNode(node, frame);
|
||||
if (result == NodeFilter.FILTER_ACCEPT) {
|
||||
self._current = node;
|
||||
return node;
|
||||
}
|
||||
sibling = if (direction == .next)
|
||||
self.firstChildOrNull(node)
|
||||
else
|
||||
self.lastChildOrNull(node);
|
||||
if (result == NodeFilter.FILTER_REJECT or sibling == null) {
|
||||
sibling = if (direction == .next)
|
||||
self.nextSiblingOrNull(node)
|
||||
else
|
||||
self.previousSiblingOrNull(node);
|
||||
}
|
||||
}
|
||||
|
||||
node = node.parentNode() orelse return null;
|
||||
if (node == self._root) return null;
|
||||
if (try self.acceptNode(node, frame) == NodeFilter.FILTER_ACCEPT) {
|
||||
return null;
|
||||
}
|
||||
node = self.nextSiblingOrNull(n);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
pub fn previousNode(self: *DOMTreeWalker, frame: *Frame) !?*Node {
|
||||
|
||||
Reference in New Issue
Block a user