PASS document.createTreeWalker(document, 0xFFFFFFFF, null)
PASS document.createTreeWalker(document, 0xFFFFFFFF, (function(node) { return true }))
PASS document.createTreeWalker(document, 0xFFFFFFFF, (function(node) { return false }))
-FAIL document.createTreeWalker(document, 0xFFFFFFFF, (function(node) { return node.nodeName[0] == '#' })) assert_equals: .nextSibling() expected Text node "TreeWalker tests" but got null
+PASS document.createTreeWalker(document, 0xFFFFFFFF, (function(node) { return node.nodeName[0] == '#' }))
PASS document.createTreeWalker(document, NodeFilter.SHOW_ELEMENT, null)
PASS document.createTreeWalker(document, NodeFilter.SHOW_ELEMENT, (function(node) { return true }))
PASS document.createTreeWalker(document, NodeFilter.SHOW_ELEMENT, (function(node) { return false }))
PASS document.createTreeWalker(detachedDiv, 0xFFFFFFFF, null)
PASS document.createTreeWalker(detachedDiv, 0xFFFFFFFF, (function(node) { return true }))
PASS document.createTreeWalker(detachedDiv, 0xFFFFFFFF, (function(node) { return false }))
-FAIL document.createTreeWalker(detachedDiv, 0xFFFFFFFF, (function(node) { return node.nodeName[0] == '#' })) assert_equals: .nextSibling() expected Text node "Wxyzabcd" but got null
+PASS document.createTreeWalker(detachedDiv, 0xFFFFFFFF, (function(node) { return node.nodeName[0] == '#' }))
PASS document.createTreeWalker(detachedDiv, NodeFilter.SHOW_ELEMENT, null)
PASS document.createTreeWalker(detachedDiv, NodeFilter.SHOW_ELEMENT, (function(node) { return true }))
PASS document.createTreeWalker(detachedDiv, NodeFilter.SHOW_ELEMENT, (function(node) { return false }))
PASS document.createTreeWalker(foreignDoc, 0xFFFFFFFF, null)
PASS document.createTreeWalker(foreignDoc, 0xFFFFFFFF, (function(node) { return true }))
PASS document.createTreeWalker(foreignDoc, 0xFFFFFFFF, (function(node) { return false }))
-FAIL document.createTreeWalker(foreignDoc, 0xFFFFFFFF, (function(node) { return node.nodeName[0] == '#' })) assert_equals: .nextSibling() expected Text node "Efghijkl" but got Comment node <!--"Commenter" and "commentator" mean different things. I'v...-->
+PASS document.createTreeWalker(foreignDoc, 0xFFFFFFFF, (function(node) { return node.nodeName[0] == '#' }))
PASS document.createTreeWalker(foreignDoc, NodeFilter.SHOW_ELEMENT, null)
PASS document.createTreeWalker(foreignDoc, NodeFilter.SHOW_ELEMENT, (function(node) { return true }))
PASS document.createTreeWalker(foreignDoc, NodeFilter.SHOW_ELEMENT, (function(node) { return false }))
PASS document.createTreeWalker(xmlDoc, 0xFFFFFFFF, null)
PASS document.createTreeWalker(xmlDoc, 0xFFFFFFFF, (function(node) { return true }))
PASS document.createTreeWalker(xmlDoc, 0xFFFFFFFF, (function(node) { return false }))
-FAIL document.createTreeWalker(xmlDoc, 0xFFFFFFFF, (function(node) { return node.nodeName[0] == '#' })) assert_equals: .nextSibling() expected Text node "do re mi fa so la ti" but got Comment node <!--I maliciously created a comment that will break incautiou...-->
+PASS document.createTreeWalker(xmlDoc, 0xFFFFFFFF, (function(node) { return node.nodeName[0] == '#' }))
PASS document.createTreeWalker(xmlDoc, NodeFilter.SHOW_ELEMENT, null)
PASS document.createTreeWalker(xmlDoc, NodeFilter.SHOW_ELEMENT, (function(node) { return true }))
PASS document.createTreeWalker(xmlDoc, NodeFilter.SHOW_ELEMENT, (function(node) { return false }))
PASS document.createTreeWalker(testDiv, 0xFFFFFFFF, null)
PASS document.createTreeWalker(testDiv, 0xFFFFFFFF, (function(node) { return true }))
PASS document.createTreeWalker(testDiv, 0xFFFFFFFF, (function(node) { return false }))
-FAIL document.createTreeWalker(testDiv, 0xFFFFFFFF, (function(node) { return node.nodeName[0] == '#' })) assert_equals: .nextSibling() expected Text node "Ijklmnop
-" but got Comment node <!--Alphabet soup?-->
+PASS document.createTreeWalker(testDiv, 0xFFFFFFFF, (function(node) { return node.nodeName[0] == '#' }))
PASS document.createTreeWalker(testDiv, NodeFilter.SHOW_ELEMENT, null)
PASS document.createTreeWalker(testDiv, NodeFilter.SHOW_ELEMENT, (function(node) { return true }))
PASS document.createTreeWalker(testDiv, NodeFilter.SHOW_ELEMENT, (function(node) { return false }))
+2015-09-23 Chris Dumez <cdumez@apple.com>
+
+ TreeWalker.previousSibling() / nextSibling() does not behave according to the specification
+ https://bugs.webkit.org/show_bug.cgi?id=149493
+
+ Reviewed by Darin Adler.
+
+ TreeWalker.previousSibling() / nextSibling() does not behave according
+ to the specification:
+ - https://dom.spec.whatwg.org/#dom-treewalker-nextsibling
+ - https://dom.spec.whatwg.org/#dom-treewalker-previoussibling
+ - https://dom.spec.whatwg.org/#concept-traverse-siblings
+
+ In particular, the previous code would fail to update 'node' variable
+ in the case acceptNode() returned FILTER_REJECT. This patch fixes this
+ and refactors the function to match more closely the text of the spec
+ and avoid code duplication.
+
+ No new tests, already covered by existing test.
+
+ * dom/TreeWalker.cpp:
+ (WebCore::TreeWalker::traverseSiblings):
+ (WebCore::TreeWalker::previousSibling):
+ (WebCore::TreeWalker::nextSibling):
+ (WebCore::TreeWalker::previousNode): Deleted.
+ * dom/TreeWalker.h:
+
2015-09-23 Alex Christensen <achristensen@webkit.org>
Fix CMake build.
return nullptr;
}
-Node* TreeWalker::previousSibling()
+template<TreeWalker::SiblingTraversalType type> Node* TreeWalker::traverseSiblings()
{
RefPtr<Node> node = m_current;
if (node == root())
return nullptr;
- while (1) {
- for (RefPtr<Node> sibling = node->previousSibling(); sibling; ) {
+
+ auto isNext = type == SiblingTraversalType::Next;
+ while (true) {
+ for (RefPtr<Node> sibling = isNext ? node->nextSibling() : node->previousSibling(); sibling; ) {
short acceptNodeResult = acceptNode(sibling.get());
- switch (acceptNodeResult) {
- case NodeFilter::FILTER_ACCEPT:
- m_current = sibling.release();
- return m_current.get();
- case NodeFilter::FILTER_SKIP:
- if (sibling->lastChild()) {
- sibling = sibling->lastChild();
- node = sibling;
- continue;
- }
- break;
- case NodeFilter::FILTER_REJECT:
- break;
+ if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) {
+ m_current = WTF::move(sibling);
+ return m_current.get();
}
- sibling = sibling->previousSibling();
+ node = sibling;
+ sibling = isNext ? sibling->firstChild() : sibling->lastChild();
+ if (acceptNodeResult == NodeFilter::FILTER_REJECT || !sibling)
+ sibling = isNext ? node->nextSibling() : node->previousSibling();
}
node = node->parentNode();
if (!node || node == root())
}
}
+Node* TreeWalker::previousSibling()
+{
+ return traverseSiblings<SiblingTraversalType::Previous>();
+}
+
Node* TreeWalker::nextSibling()
{
- RefPtr<Node> node = m_current;
- if (node == root())
- return nullptr;
- while (1) {
- for (RefPtr<Node> sibling = node->nextSibling(); sibling; ) {
- short acceptNodeResult = acceptNode(sibling.get());
- switch (acceptNodeResult) {
- case NodeFilter::FILTER_ACCEPT:
- m_current = sibling.release();
- return m_current.get();
- case NodeFilter::FILTER_SKIP:
- if (sibling->firstChild()) {
- sibling = sibling->firstChild();
- node = sibling;
- continue;
- }
- break;
- case NodeFilter::FILTER_REJECT:
- break;
- }
- sibling = sibling->nextSibling();
- }
- node = node->parentNode();
- if (!node || node == root())
- return nullptr;
- short acceptNodeResult = acceptNode(node.get());
- if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
- return nullptr;
- }
+ return traverseSiblings<SiblingTraversalType::Next>();
}
Node* TreeWalker::previousNode()