WebCore:
authordarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Feb 2008 10:35:20 +0000 (10:35 +0000)
committerdarin@apple.com <darin@apple.com@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Fri, 8 Feb 2008 10:35:20 +0000 (10:35 +0000)
        Reviewed by Eric.

        - fix http://bugs.webkit.org/show_bug.cgi?id=3492
          TreeWalker implementation needs to be fixed (affects Acid3)
        - fix http://bugs.webkit.org/show_bug.cgi?id=4714
          NodeIterator does not handle exceptions from the filter function (affects Acid3)
        - fix http://bugs.webkit.org/show_bug.cgi?id=4716
          NodeIterator will crash if the filter function removes the current node from the document

        Test: traversal/exception-forwarding.html

        This turned into a near-rewrite of NodeIterator and TreeWalker.

        * bindings/js/JSNodeFilterCondition.h:
        * bindings/js/JSNodeFilterCondition.cpp:
        (WebCore::takeException): Added.
        (WebCore::JSNodeFilterCondition::acceptNode): Added an out parameter to return
        a JavaScript exception.

        * bindings/js/JSNodeFilterCustom.cpp:
        (WebCore::JSNodeFilter::acceptNode): Wrote a custom binding for this that raises
        a JavaScript exception if the out parameter is set.

        * bindings/js/JSNodeIteratorCustom.cpp:
        (WebCore::JSNodeIterator::nextNode): Wrote a custom binding for this that raises
        a JavaScript exception if the out parameter is set.
        (WebCore::JSNodeIterator::previousNode): Ditto.

        * bindings/js/JSTreeWalkerCustom.cpp:
        (WebCore::JSTreeWalker::parentNode): Wrote a custom binding for this that raises
        a JavaScript exception if the out parameter is set.
        (WebCore::JSTreeWalker::firstChild): Ditto.
        (WebCore::JSTreeWalker::lastChild): Ditto.
        (WebCore::JSTreeWalker::nextSibling): Ditto.
        (WebCore::JSTreeWalker::previousSibling): Ditto.
        (WebCore::JSTreeWalker::previousNode): Ditto.
        (WebCore::JSTreeWalker::nextNode): Ditto.

        * bindings/objc/DOM.mm:
        (WebCore::ObjCNodeFilterCondition::acceptNode): Updated to include new exception
        out parameter.
        (-[DOMDocument createNodeIterator:whatToShow:filter:expandEntityReferences:]):
        Use RefPtr to make object lifetimes clearer.
        (-[DOMDocument createTreeWalker:whatToShow:filter:expandEntityReferences:]):
        Ditto.

        * bindings/scripts/CodeGeneratorJS.pm: Added include of NodeFilter.h for
        JSDocument.cpp.

        * dom/Document.h:
        * dom/Document.cpp:
        (WebCore::Document::createNodeIterator): Changed to use PassRefPtr.
        (WebCore::Document::createTreeWalker): Ditto.

        * dom/NodeFilter.h:
        * dom/NodeFilter.cpp:
        (WebCore::NodeFilter::NodeFilter): Changed to use PassRefPtr.
        (WebCore::NodeFilter::acceptNode): Added an out parameter to return
        a JavaScript exception.
        * dom/NodeFilter.idl: Custom binding for acceptNode.

        * dom/NodeFilterCondition.h:
        * dom/NodeFilterCondition.cpp:
        (WebCore::NodeFilterCondition::acceptNode): Added an out parameter to return
        a JavaScript exception.

        * dom/NodeIterator.cpp:
        (WebCore::NodeIterator::NodeIterator): Changed to use PassRefPtr more.
        Eliminated m_doc, using the root node instead, and unnecessary check for
        null -- rootNode must be non-null and all nodes have a non-null document.
        (WebCore::NodeIterator::~NodeIterator): Changed to get document from root.
        (WebCore::NodeIterator::nextNode): Rewrote to use a RefPtr since the
        acceptNode function could do anything, including removing the last
        reference to the current node. Also folded findNextNode into this function
        since it's the only one that needs to call it.
        (WebCore::NodeIterator::previousNode): Same thing, but the other direction.
        (WebCore::NodeIterator::detach): Changed to use the root node as the indication
        that we're detached rather than a separate boolean.
        (WebCore::NodeIterator::notifyBeforeNodeRemoval): Removed some unnneeded
        checks. Removed incorrect use of findNextNode/findPreviousNode -- those
        functions call acceptNode and the DOM standard is quite clear that these
        functions do not take that into account, allowing the current node to become
        one that's not accepted.

        * dom/NodeIterator.h: Changed constructor to use PassRefPtr more. Changed
        nextNode and previousNode to have an out parameter with a JavaScript exception.
        Removed helper functions setReferenceNode, setPointerBeforeReferenceNode,
        detached, setDetached, document, findNextNode, and findPreviousNode. All were
        unnecessary. Removed data member m_doc which was just rootNode()->document().

        * dom/NodeIterator.idl: Custom binding for nextNode and previousNode.

        * dom/Traversal.cpp:
        (WebCore::Traversal::Traversal): Use PassRefPtr more.
        (WebCore::Traversal::acceptNode): Added out parameter for JavaScript exception.
        Also rearranged the function a little bit for clarity.

        * dom/Traversal.h: Changed acceptNode to have an out parameter with a JavaScript
        exception and made it protected, since it's only for use by the derived classes.

        * dom/TreeWalker.cpp:
        (WebCore::TreeWalker::TreeWalker): Updated to use PassRefPtr.
        (WebCore::TreeWalker::setCurrentNode): Updated to use PassRefPtr and deleted
        the overloaded version since it's not needed.
        (WebCore::TreeWalker::parentNode): Rewrote to propagate the exception and also
        to implement rules about when to check things like whether we're in the tree.
        The previous fix where we called isDescendantOf was not entirely correct, because
        the specification allows you to walk outside the tree if you get there somehow.
        What it doesn't allow is walking outside the tree from inside. The new
        implementation handles this correctly.
        (WebCore::TreeWalker::firstChild): Ditto.
        (WebCore::TreeWalker::lastChild): Ditto.
        (WebCore::TreeWalker::previousSibling): Ditto.
        (WebCore::TreeWalker::nextSibling): Ditto.
        (WebCore::TreeWalker::previousNode): Ditto. Because of the need to check the
        acceptNode function on parents, this can't use traversePreviousNode (more's the
        pity, because it's a bit complicated).
        (WebCore::TreeWalker::nextNode): Ditto.

        * dom/TreeWalker.h: Changed constructor and setCurrentNode to use PassRefPtr
        more. Changed the navigation functions to have an out parameter with a JavaScript
        exception. Removed helper functions setCurrentNode and ancestorRejected.

        * dom/TreeWalker.idl: Custom binding for navigation functions.

LayoutTests:

        Reviewed by Eric.

        - test for http://bugs.webkit.org/show_bug.cgi?id=4714
          NodeIterator does not handle exceptions from the filter function (affects Acid3)

        - grabbed NodeIterator and TreeWalker tests from Hixie's site and KHTML

        * traversal/exception-forwarding-expected.txt: Added.
        * traversal/exception-forwarding.html: Added.
        * traversal/resources: Added.
        * traversal/resources/TEMPLATE.html: Copied from LayoutTests/fast/js/resources/TEMPLATE.html.
        * traversal/resources/exception-forwarding.js: Added.

        * traversal/node-iterator-001-expected.txt: Updated to reflect correct results.
        The old results reflected a bug in our NodeIterator.
        * traversal/node-iterator-001.html: Ditto.

        * traversal/node-iterator-006.html: Changed test so there's no whitespace node after
        the <span> elements inside the test root element (a <div>). The old test results were
        incorrect; the new NodeIterator implementation correctly returned the whitespace node
        for this test.

        * traversal/node-iterator-006a.html: Copied from traversal/node-iterator-006.html.
        Preserve the original test, which now has a strange result. But the result is correct,
        so it's worth keeping around.
        * traversal/node-iterator-006a-expected.txt: Added.

        * fast/dom/TreeWalker/TreeWalker-currentNode-expected.txt: Regenerated.
        * fast/dom/TreeWalker/resources/TreeWalker-currentNode.js: Updated test to expect results
        that match the DOM specification.

        * traversal/hixie-node-iterator/001-expected.txt: Added.
        * traversal/hixie-node-iterator/001.xml: Added.
        * traversal/hixie-node-iterator/002-expected.txt: Added.
        * traversal/hixie-node-iterator/002.xml: Added.
        * traversal/hixie-node-iterator/003-expected.txt: Added.
        * traversal/hixie-node-iterator/003.xml: Added.
        * traversal/hixie-node-iterator/004-expected.txt: Added.
        * traversal/hixie-node-iterator/004.xml: Added.
        * traversal/hixie-node-iterator/005-expected.txt: Added.
        * traversal/hixie-node-iterator/005.xml: Added.
        * traversal/hixie-node-iterator/006-expected.txt: Added.
        * traversal/hixie-node-iterator/006.xml: Added.
        * traversal/hixie-node-iterator/007-expected.txt: Added.
        * traversal/hixie-node-iterator/007.xml: Added.
        * traversal/hixie-node-iterator/008-expected.txt: Added.
        * traversal/hixie-node-iterator/008.xml: Added.
        * traversal/hixie-node-iterator/009-expected.txt: Added.
        * traversal/hixie-node-iterator/009.xml: Added.
        * traversal/hixie-node-iterator/010-expected.txt: Added.
        * traversal/hixie-node-iterator/010.xml: Added.
        * traversal/hixie-node-iterator/origin.txt: Added.

        * traversal/tree-walker-filter-1-expected.txt: Added.
        * traversal/tree-walker-filter-1.html: Added.

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@30089 268f45cc-cd09-0410-ab3c-d52691b4dbfc

60 files changed:
LayoutTests/ChangeLog
LayoutTests/fast/dom/TreeWalker/TreeWalker-currentNode-expected.txt
LayoutTests/fast/dom/TreeWalker/resources/TreeWalker-currentNode.js
LayoutTests/traversal/exception-forwarding-expected.txt [new file with mode: 0644]
LayoutTests/traversal/exception-forwarding.html [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/001-expected.txt [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/001.xml [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/002-expected.txt [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/002.xml [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/003-expected.txt [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/003.xml [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/004-expected.txt [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/004.xml [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/005-expected.txt [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/005.xml [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/006-expected.txt [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/006.xml [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/007-expected.txt [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/007.xml [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/008-expected.txt [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/008.xml [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/009-expected.txt [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/009.xml [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/010-expected.txt [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/010.xml [new file with mode: 0644]
LayoutTests/traversal/hixie-node-iterator/origin.txt [new file with mode: 0644]
LayoutTests/traversal/node-iterator-001-expected.txt
LayoutTests/traversal/node-iterator-001.html
LayoutTests/traversal/node-iterator-006.html
LayoutTests/traversal/node-iterator-006a-expected.txt [new file with mode: 0644]
LayoutTests/traversal/node-iterator-006a.html [new file with mode: 0644]
LayoutTests/traversal/resources/TEMPLATE.html [new file with mode: 0644]
LayoutTests/traversal/resources/exception-forwarding.js [new file with mode: 0644]
LayoutTests/traversal/tree-walker-filter-1-expected.txt [new file with mode: 0644]
LayoutTests/traversal/tree-walker-filter-1.html [new file with mode: 0644]
WebCore/ChangeLog
WebCore/bindings/js/JSNodeFilterCondition.cpp
WebCore/bindings/js/JSNodeFilterCondition.h
WebCore/bindings/js/JSNodeFilterCustom.cpp
WebCore/bindings/js/JSNodeIteratorCustom.cpp
WebCore/bindings/js/JSTreeWalkerCustom.cpp
WebCore/bindings/objc/DOM.mm
WebCore/bindings/scripts/CodeGeneratorJS.pm
WebCore/dom/Document.cpp
WebCore/dom/Document.h
WebCore/dom/Node.cpp
WebCore/dom/Node.h
WebCore/dom/NodeFilter.cpp
WebCore/dom/NodeFilter.h
WebCore/dom/NodeFilter.idl
WebCore/dom/NodeFilterCondition.cpp
WebCore/dom/NodeFilterCondition.h
WebCore/dom/NodeIterator.cpp
WebCore/dom/NodeIterator.h
WebCore/dom/NodeIterator.idl
WebCore/dom/Traversal.cpp
WebCore/dom/Traversal.h
WebCore/dom/TreeWalker.cpp
WebCore/dom/TreeWalker.h
WebCore/dom/TreeWalker.idl

index ac8c1f4..ce7b0d3 100644 (file)
@@ -1,3 +1,61 @@
+2008-02-08  Darin Adler  <darin@apple.com>
+
+        Reviewed by Eric.
+
+        - test for http://bugs.webkit.org/show_bug.cgi?id=4714
+          NodeIterator does not handle exceptions from the filter function (affects Acid3)
+
+        - grabbed NodeIterator and TreeWalker tests from Hixie's site and KHTML
+
+        * traversal/exception-forwarding-expected.txt: Added.
+        * traversal/exception-forwarding.html: Added.
+        * traversal/resources: Added.
+        * traversal/resources/TEMPLATE.html: Copied from LayoutTests/fast/js/resources/TEMPLATE.html.
+        * traversal/resources/exception-forwarding.js: Added.
+
+        * traversal/node-iterator-001-expected.txt: Updated to reflect correct results.
+        The old results reflected a bug in our NodeIterator.
+        * traversal/node-iterator-001.html: Ditto.
+
+        * traversal/node-iterator-006.html: Changed test so there's no whitespace node after
+        the <span> elements inside the test root element (a <div>). The old test results were
+        incorrect; the new NodeIterator implementation correctly returned the whitespace node
+        for this test.
+
+        * traversal/node-iterator-006a.html: Copied from traversal/node-iterator-006.html.
+        Preserve the original test, which now has a strange result. But the result is correct,
+        so it's worth keeping around.
+        * traversal/node-iterator-006a-expected.txt: Added.
+
+        * fast/dom/TreeWalker/TreeWalker-currentNode-expected.txt: Regenerated.
+        * fast/dom/TreeWalker/resources/TreeWalker-currentNode.js: Updated test to expect results
+        that match the DOM specification.
+
+        * traversal/hixie-node-iterator/001-expected.txt: Added.
+        * traversal/hixie-node-iterator/001.xml: Added.
+        * traversal/hixie-node-iterator/002-expected.txt: Added.
+        * traversal/hixie-node-iterator/002.xml: Added.
+        * traversal/hixie-node-iterator/003-expected.txt: Added.
+        * traversal/hixie-node-iterator/003.xml: Added.
+        * traversal/hixie-node-iterator/004-expected.txt: Added.
+        * traversal/hixie-node-iterator/004.xml: Added.
+        * traversal/hixie-node-iterator/005-expected.txt: Added.
+        * traversal/hixie-node-iterator/005.xml: Added.
+        * traversal/hixie-node-iterator/006-expected.txt: Added.
+        * traversal/hixie-node-iterator/006.xml: Added.
+        * traversal/hixie-node-iterator/007-expected.txt: Added.
+        * traversal/hixie-node-iterator/007.xml: Added.
+        * traversal/hixie-node-iterator/008-expected.txt: Added.
+        * traversal/hixie-node-iterator/008.xml: Added.
+        * traversal/hixie-node-iterator/009-expected.txt: Added.
+        * traversal/hixie-node-iterator/009.xml: Added.
+        * traversal/hixie-node-iterator/010-expected.txt: Added.
+        * traversal/hixie-node-iterator/010.xml: Added.
+        * traversal/hixie-node-iterator/origin.txt: Added.
+
+        * traversal/tree-walker-filter-1-expected.txt: Added.
+        * traversal/tree-walker-filter-1.html: Added.
+
 2008-02-08  Eric Seidel  <eric@webkit.org>
 
         Reviewed by darin.
index 54336da..d9ea239 100644 (file)
@@ -13,14 +13,14 @@ Test that we handle setting the currentNode to arbitrary nodes not under the roo
 
 PASS w.parentNode() is null
 PASS w.currentNode is document.documentElement
-PASS w.nextNode() is null
-PASS w.currentNode is document.documentElement
+PASS w.nextNode() is document.documentElement.firstChild
+PASS w.currentNode is document.documentElement.firstChild
 PASS w.previousNode() is null
 PASS w.currentNode is document.documentElement
-PASS w.firstChild() is null
-PASS w.currentNode is document.documentElement
-PASS w.lastChild() is null
-PASS w.currentNode is document.documentElement
+PASS w.firstChild() is document.documentElement.firstChild
+PASS w.currentNode is document.documentElement.firstChild
+PASS w.lastChild() is document.documentElement.lastChild
+PASS w.currentNode is document.documentElement.lastChild
 PASS w.nextSibling() is null
 PASS w.currentNode is document.documentElement
 PASS w.previousSibling() is null
index 3f20e21..4a6768b 100644 (file)
@@ -21,16 +21,22 @@ debug("");
 w.currentNode = document.documentElement;
 shouldBeNull("w.parentNode()");
 shouldBe("w.currentNode", "document.documentElement");
-shouldBeNull("w.nextNode()");
-shouldBe("w.currentNode", "document.documentElement");
+w.currentNode = document.documentElement;
+shouldBe("w.nextNode()", "document.documentElement.firstChild");
+shouldBe("w.currentNode", "document.documentElement.firstChild");
+w.currentNode = document.documentElement;
 shouldBeNull("w.previousNode()");
 shouldBe("w.currentNode", "document.documentElement");
-shouldBeNull("w.firstChild()");
-shouldBe("w.currentNode", "document.documentElement");
-shouldBeNull("w.lastChild()");
-shouldBe("w.currentNode", "document.documentElement");
+w.currentNode = document.documentElement;
+shouldBe("w.firstChild()", "document.documentElement.firstChild");
+shouldBe("w.currentNode", "document.documentElement.firstChild");
+w.currentNode = document.documentElement;
+shouldBe("w.lastChild()", "document.documentElement.lastChild");
+shouldBe("w.currentNode", "document.documentElement.lastChild");
+w.currentNode = document.documentElement;
 shouldBeNull("w.nextSibling()");
 shouldBe("w.currentNode", "document.documentElement");
+w.currentNode = document.documentElement;
 shouldBeNull("w.previousSibling()");
 shouldBe("w.currentNode", "document.documentElement");
 
@@ -40,7 +46,7 @@ debug("");
 
 w.currentNode = subTree.previousSibling;
 shouldBe("w.nextNode()", "subTree");
-w.currentNode = document.body
+w.currentNode = document.body;
 shouldBe("w.lastChild()", "subTree");
 
 // Cleanup
diff --git a/LayoutTests/traversal/exception-forwarding-expected.txt b/LayoutTests/traversal/exception-forwarding-expected.txt
new file mode 100644 (file)
index 0000000..08a2a01
--- /dev/null
@@ -0,0 +1,22 @@
+Test of exception forwarding for NodeIterator and TreeWalker, derived from an early version of Acid3
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+PASS i.nextNode() threw exception Roses.
+PASS i.nextNode() is document.documentElement
+PASS i.previousNode() threw exception Roses.
+PASS w.nextNode() threw exception Roses.
+PASS w.nextNode() is document.documentElement.firstChild
+PASS w.previousNode() threw exception Roses.
+PASS w.firstChild() threw exception Roses.
+PASS w.lastChild() threw exception Roses.
+PASS w.nextSibling() threw exception Roses.
+PASS w.previousSibling() is null
+PASS w.nextSibling() is document.body
+PASS w.previousSibling() is document.body.previousSibling
+PASS iteration is 11
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
diff --git a/LayoutTests/traversal/exception-forwarding.html b/LayoutTests/traversal/exception-forwarding.html
new file mode 100644 (file)
index 0000000..ea76897
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../fast/js/resources/js-test-style.css">
+<script src="../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="resources/exception-forwarding.js"></script>
+<script src="../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/traversal/hixie-node-iterator/001-expected.txt b/LayoutTests/traversal/hixie-node-iterator/001-expected.txt
new file mode 100644 (file)
index 0000000..7ef22e9
--- /dev/null
@@ -0,0 +1 @@
+PASS
diff --git a/LayoutTests/traversal/hixie-node-iterator/001.xml b/LayoutTests/traversal/hixie-node-iterator/001.xml
new file mode 100644 (file)
index 0000000..f9490a6
--- /dev/null
@@ -0,0 +1,54 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>DOM Traversal: NodeIterator: Basics</title>
+  <script type="text/javascript"> <![CDATA[
+    function doTest() {
+      if (window.layoutTestController) layoutTestController.dumpAsText();
+      var iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL, null, false);
+      var expected = new Array(9, // document
+                               1, // html
+                               3, 1, // head
+                               3, 1, 3, // title
+                               3, 1, 3, 4, // script and CDATA block
+                               3, 3, 1, // body
+                               3, 1, 3, // pre
+                               3, // </body>
+                               3, 8, // <!-- -->
+                               3, 7, // <? ?>,
+                               3, 4, 3); // CDATA
+      var found = new Array();
+
+      // walk document
+      var node;
+      while (node = iterator.nextNode())
+        found.push(node.nodeType);
+
+      // check results
+      var errors = 0;
+      var s = '';
+      var length = (found.length > expected.length) ? found.length : expected.length;
+      s += 'EXPECTED  FOUND\n';
+      for (var i = 0; i < length; i += 1) {
+        s += '  ' + (expected[i] ? expected[i] : '-') +
+      '         ' + (found[i] ? found[i] : '-');
+        if (found[i] != expected[i]) {
+          s += '      MISMATCH';
+          errors += 1;
+        }
+        s += '\n';
+      }
+      var p = document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'pre')[0];
+      if (errors)
+        p.firstChild.data = 'FAIL: ' + errors + ' errors found:\n\n' + s;
+      else
+        p.firstChild.data = 'PASS';
+    }
+  ]]></script>
+ </head>
+ <body onload="doTest()">
+  <pre id="result">FAIL: Script failed to run.</pre>
+ </body>
+ <!-- some more nodes to test this: -->
+ <?test node?>
+ <![CDATA[ ]]>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/traversal/hixie-node-iterator/002-expected.txt b/LayoutTests/traversal/hixie-node-iterator/002-expected.txt
new file mode 100644 (file)
index 0000000..7ef22e9
--- /dev/null
@@ -0,0 +1 @@
+PASS
diff --git a/LayoutTests/traversal/hixie-node-iterator/002.xml b/LayoutTests/traversal/hixie-node-iterator/002.xml
new file mode 100644 (file)
index 0000000..35f22ad
--- /dev/null
@@ -0,0 +1,55 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>DOM Traversal: NodeIterator: Basics Backwards</title>
+  <script type="text/javascript"> <![CDATA[
+    function doTest() {
+      if (window.layoutTestController) layoutTestController.dumpAsText();
+      var iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL, null, false);
+      var expected = new Array(9, // document
+                               1, // html
+                               3, 1, // head
+                               3, 1, 3, // title
+                               3, 1, 3, 4, // script and CDATA block
+                               3, 3, 1, // body
+                               3, 1, 3, // pre
+                               3, // </body>
+                               3, 8, // <!-- -->
+                               3, 7, // <? ?>,
+                               3, 4, 3); // CDATA
+      var found = new Array();
+
+      // walk document
+      var node;
+      while (node = iterator.nextNode());
+      while (node = iterator.previousNode())
+        found.unshift(node.nodeType);
+
+      // check results
+      var errors = 0;
+      var s = '';
+      var length = (found.length > expected.length) ? found.length : expected.length;
+      s += 'EXPECTED  FOUND\n';
+      for (var i = 0; i < length; i += 1) {
+        s += '  ' + (expected[i] ? expected[i] : '-') +
+      '         ' + (found[i] ? found[i] : '-');
+        if (found[i] != expected[i]) {
+          s += '      MISMATCH';
+          errors += 1;
+        }
+        s += '\n';
+      }
+      var p = document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'pre')[0];
+      if (errors)
+        p.firstChild.data = 'FAIL: ' + errors + ' errors found:\n\n' + s;
+      else
+        p.firstChild.data = 'PASS';
+    }
+  ]]></script>
+ </head>
+ <body onload="doTest()">
+  <pre id="result">FAIL: Script failed to run.</pre>
+ </body>
+ <!-- some more nodes to test this: -->
+ <?test node?>
+ <![CDATA[ ]]>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/traversal/hixie-node-iterator/003-expected.txt b/LayoutTests/traversal/hixie-node-iterator/003-expected.txt
new file mode 100644 (file)
index 0000000..69cfc5a
--- /dev/null
@@ -0,0 +1,2 @@
+PASS
+
diff --git a/LayoutTests/traversal/hixie-node-iterator/003.xml b/LayoutTests/traversal/hixie-node-iterator/003.xml
new file mode 100644 (file)
index 0000000..a6bcfe0
--- /dev/null
@@ -0,0 +1,59 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>DOM Traversal: NodeIterator: Removal of nodes that should have no effect</title>
+  <!--
+   This tests these cases that should have no effect:
+    1. Remove a node unrelated to the reference node
+    2. Remove an ancestor of the root node
+    3. Remove the root node itself
+    4. Remove descendant of reference node
+  -->
+  <script type="text/javascript"> <![CDATA[
+    var errors = 0;
+    var log = '';
+    function doTest() {
+      if (window.layoutTestController) layoutTestController.dumpAsText();
+      var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false);
+      var root = document.getElementById('root');
+      var A = document.getElementById('A');
+      var B = document.getElementById('B');
+      var C = document.getElementById('C');
+      var D = document.getElementById('D');
+      var E = document.getElementById('E');
+      check(iterator.nextNode(), root);
+      remove(document.getElementById('X'));
+      check(iterator.nextNode(), A);
+      remove(document.getElementById('Y'));
+      check(iterator.nextNode(), B);
+      remove(root);
+      check(iterator.nextNode(), C);
+      remove(E);
+      check(iterator.nextNode(), D);
+      if (errors)
+        document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log;
+      else
+        document.getElementById('result').firstChild.data = 'PASS';
+    }
+    function check(a, b) {
+      if (!a) {
+        errors += 1;
+        log += 'Found null but expected ' + b + ' (' + b.id + ').\n';
+      } else if (a != b) {
+        errors += 1;
+        log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n';
+      }
+    }
+    function remove(a) {
+      if (!a) {
+        errors += 1;
+        log += 'Tried removing null node.\n';
+      } else
+      a.parentNode.removeChild(a);
+    }
+  ]]></script>
+ </head>
+ <body onload="doTest()">
+  <pre id="result">FAIL: Script did not complete.</pre>
+  <p><span id="X"></span><span id="Y"><span id="root"><span id="A"><span id="B"><span id="C"><span id="D"><span id="E"></span></span></span></span></span></span></span></p>
+ </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/traversal/hixie-node-iterator/004-expected.txt b/LayoutTests/traversal/hixie-node-iterator/004-expected.txt
new file mode 100644 (file)
index 0000000..69cfc5a
--- /dev/null
@@ -0,0 +1,2 @@
+PASS
+
diff --git a/LayoutTests/traversal/hixie-node-iterator/004.xml b/LayoutTests/traversal/hixie-node-iterator/004.xml
new file mode 100644 (file)
index 0000000..1292188
--- /dev/null
@@ -0,0 +1,50 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>DOM Traversal: NodeIterator: Removal of the Reference Node</title>
+  <script type="text/javascript"> <![CDATA[
+    var errors = 0;
+    var log = '';
+    function doTest() {
+      if (window.layoutTestController) layoutTestController.dumpAsText();
+      var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false);
+      var root = document.getElementById('root');
+      var A = document.getElementById('A');
+      var AA = document.getElementById('AA');
+      var B = document.getElementById('B');
+      var C = document.getElementById('C');
+      check(iterator.nextNode(), root);
+      check(iterator.nextNode(), A);
+      check(iterator.nextNode(), AA);
+      check(iterator.nextNode(), B);
+      remove(B);
+      check(iterator.previousNode(), AA);
+      remove(AA);
+      check(iterator.nextNode(), C);
+      if (errors)
+        document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log;
+      else
+        document.getElementById('result').firstChild.data = 'PASS';
+    }
+    function check(a, b) {
+      if (!a) {
+        errors += 1;
+        log += 'Found null but expected ' + b + ' (' + b.id + ').\n';
+      } else if (a != b) {
+        errors += 1;
+        log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n';
+      }
+    }
+    function remove(a) {
+      if (!a) {
+        errors += 1;
+        log += 'Tried removing null node.\n';
+      } else
+      a.parentNode.removeChild(a);
+    }
+  ]]></script>
+ </head>
+ <body onload="doTest()">
+  <pre id="result">FAIL: Script did not complete.</pre>
+  <p><span id="root"><span id="A"><span id="AA"></span></span><span id="B"></span><span id="C"><span id="CC"></span></span></span></p>
+ </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/traversal/hixie-node-iterator/005-expected.txt b/LayoutTests/traversal/hixie-node-iterator/005-expected.txt
new file mode 100644 (file)
index 0000000..69cfc5a
--- /dev/null
@@ -0,0 +1,2 @@
+PASS
+
diff --git a/LayoutTests/traversal/hixie-node-iterator/005.xml b/LayoutTests/traversal/hixie-node-iterator/005.xml
new file mode 100644 (file)
index 0000000..d99b793
--- /dev/null
@@ -0,0 +1,58 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>DOM Traversal: NodeIterator: Removal of the Reference Node (deep check)</title>
+  <script type="text/javascript"> <![CDATA[
+    var errors = 0;
+    var log = '';
+    function doTest() {
+      if (window.layoutTestController) layoutTestController.dumpAsText();
+      var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false);
+      var root = document.getElementById('root');
+      var A = document.getElementById('A');
+      var AA = document.getElementById('AA');
+      var B = document.getElementById('B');
+      var C = document.getElementById('C');
+      check(iterator.nextNode(), root);
+      check(iterator.nextNode(), A);
+      check(iterator.nextNode(), AA);
+      check(iterator.nextNode(), B);
+      remove(B);
+      var X = addChildTo(AA);
+      check(iterator.nextNode(), X);
+      check(iterator.previousNode(), X);
+      remove(X);
+      var Y = addChildTo(AA);
+      check(iterator.previousNode(), Y);
+      if (errors)
+        document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log;
+      else
+        document.getElementById('result').firstChild.data = 'PASS';
+    }
+    function check(a, b) {
+      if (!a) {
+        errors += 1;
+        log += 'Found null but expected ' + b + ' (' + b.id + ').\n';
+      } else if (a != b) {
+        errors += 1;
+        log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n';
+      }
+    }
+    function remove(a) {
+      if (!a) {
+        errors += 1;
+        log += 'Tried removing null node.\n';
+      } else
+      a.parentNode.removeChild(a);
+    }
+    function addChildTo(a) {
+      var x = document.createElementNS('http://www.w3.org/1999/xhtml', 'span');
+      a.appendChild(x);
+      return x;
+    }
+  ]]></script>
+ </head>
+ <body onload="doTest()">
+  <pre id="result">FAIL: Script did not complete.</pre>
+  <p><span id="root"><span id="A"><span id="AA"></span></span><span id="B"></span><span id="C"><span id="CC"></span></span></span></p>
+ </body>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/traversal/hixie-node-iterator/006-expected.txt b/LayoutTests/traversal/hixie-node-iterator/006-expected.txt
new file mode 100644 (file)
index 0000000..69cfc5a
--- /dev/null
@@ -0,0 +1,2 @@
+PASS
+
diff --git a/LayoutTests/traversal/hixie-node-iterator/006.xml b/LayoutTests/traversal/hixie-node-iterator/006.xml
new file mode 100644 (file)
index 0000000..aa91b91
--- /dev/null
@@ -0,0 +1,48 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>DOM Traversal: NodeIterator: Removal of an ancestor of the Reference Node (forwards)</title>
+  <script type="text/javascript"> <![CDATA[
+    var errors = 0;
+    var log = '';
+    function doTest() {
+      if (window.layoutTestController) layoutTestController.dumpAsText();
+      var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false);
+      var root = document.getElementById('root');
+      var A = document.getElementById('A');
+      var B = document.getElementById('B');
+      var BB = document.getElementById('BB');
+      var C = document.getElementById('C');
+      check(iterator.nextNode(), root);
+      check(iterator.nextNode(), A);
+      check(iterator.nextNode(), B);
+      check(iterator.nextNode(), BB);
+      remove(B);
+      check(iterator.previousNode(), A);
+      if (errors)
+        document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log;
+      else
+        document.getElementById('result').firstChild.data = 'PASS';
+    }
+    function check(a, b) {
+      if (!a) {
+        errors += 1;
+        log += 'Found null but expected ' + b + ' (' + b.id + ').\n';
+      } else if (a != b) {
+        errors += 1;
+        log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n';
+      }
+    }
+    function remove(a) {
+      if (!a) {
+        errors += 1;
+        log += 'Tried removing null node.\n';
+      } else
+      a.parentNode.removeChild(a);
+    }
+  ]]></script>
+ </head>
+ <body onload="doTest()">
+  <pre id="result">FAIL: Script did not complete.</pre>
+  <p><span id="root"><span id="A"></span><span id="B"><span id="BB"></span></span><span id="C"></span></span></p>
+ </body>
+</html>
diff --git a/LayoutTests/traversal/hixie-node-iterator/007-expected.txt b/LayoutTests/traversal/hixie-node-iterator/007-expected.txt
new file mode 100644 (file)
index 0000000..69cfc5a
--- /dev/null
@@ -0,0 +1,2 @@
+PASS
+
diff --git a/LayoutTests/traversal/hixie-node-iterator/007.xml b/LayoutTests/traversal/hixie-node-iterator/007.xml
new file mode 100644 (file)
index 0000000..0f9c049
--- /dev/null
@@ -0,0 +1,55 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>DOM Traversal: NodeIterator: Removal of an ancestor of the Reference Node (forwards) (deep check)</title>
+  <script type="text/javascript"> <![CDATA[
+    var errors = 0;
+    var log = '';
+    function doTest() {
+      if (window.layoutTestController) layoutTestController.dumpAsText();
+      var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false);
+      var root = document.getElementById('root');
+      var A = document.getElementById('A');
+      var B = document.getElementById('B');
+      var BB = document.getElementById('BB');
+      var C = document.getElementById('C');
+      check(iterator.nextNode(), root);
+      check(iterator.nextNode(), A);
+      check(iterator.nextNode(), B);
+      check(iterator.nextNode(), BB);
+      remove(B);
+      var X = addChildTo(A);
+      check(iterator.nextNode(), X);
+      if (errors)
+        document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log;
+      else
+        document.getElementById('result').firstChild.data = 'PASS';
+    }
+    function check(a, b) {
+      if (!a) {
+        errors += 1;
+        log += 'Found null but expected ' + b + ' (' + b.id + ').\n';
+      } else if (a != b) {
+        errors += 1;
+        log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n';
+      }
+    }
+    function remove(a) {
+      if (!a) {
+        errors += 1;
+        log += 'Tried removing null node.\n';
+      } else
+      a.parentNode.removeChild(a);
+    }
+    function addChildTo(a) {
+      var x = document.createElementNS('http://www.w3.org/1999/xhtml', 'span');
+      x.id = 'X';
+      a.appendChild(x);
+      return x;
+    }
+  ]]></script>
+ </head>
+ <body onload="doTest()">
+  <pre id="result">FAIL: Script did not complete.</pre>
+  <p><span id="root"><span id="A"></span><span id="B"><span id="BB"></span></span><span id="C"></span></span></p>
+ </body>
+</html>
diff --git a/LayoutTests/traversal/hixie-node-iterator/008-expected.txt b/LayoutTests/traversal/hixie-node-iterator/008-expected.txt
new file mode 100644 (file)
index 0000000..69cfc5a
--- /dev/null
@@ -0,0 +1,2 @@
+PASS
+
diff --git a/LayoutTests/traversal/hixie-node-iterator/008.xml b/LayoutTests/traversal/hixie-node-iterator/008.xml
new file mode 100644 (file)
index 0000000..0962b4f
--- /dev/null
@@ -0,0 +1,49 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>DOM Traversal: NodeIterator: Removal of an ancestor of the Reference Node (backwards)</title>
+  <script type="text/javascript"> <![CDATA[
+    var errors = 0;
+    var log = '';
+    function doTest() {
+      if (window.layoutTestController) layoutTestController.dumpAsText();
+      var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false);
+      var root = document.getElementById('root');
+      var A = document.getElementById('A');
+      var B = document.getElementById('B');
+      var BB = document.getElementById('BB');
+      var C = document.getElementById('C');
+      check(iterator.nextNode(), root);
+      check(iterator.nextNode(), A);
+      check(iterator.nextNode(), B);
+      check(iterator.nextNode(), BB);
+      check(iterator.previousNode(), BB);
+      remove(B);
+      check(iterator.nextNode(), C);
+      if (errors)
+        document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log;
+      else
+        document.getElementById('result').firstChild.data = 'PASS';
+    }
+    function check(a, b) {
+      if (!a) {
+        errors += 1;
+        log += 'Found null but expected ' + b + ' (' + b.id + ').\n';
+      } else if (a != b) {
+        errors += 1;
+        log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n';
+      }
+    }
+    function remove(a) {
+      if (!a) {
+        errors += 1;
+        log += 'Tried removing null node.\n';
+      } else
+      a.parentNode.removeChild(a);
+    }
+  ]]></script>
+ </head>
+ <body onload="doTest()">
+  <pre id="result">FAIL: Script did not complete.</pre>
+  <p><span id="root"><span id="A"></span><span id="B"><span id="BB"></span></span><span id="C"></span></span></p>
+ </body>
+</html>
diff --git a/LayoutTests/traversal/hixie-node-iterator/009-expected.txt b/LayoutTests/traversal/hixie-node-iterator/009-expected.txt
new file mode 100644 (file)
index 0000000..69cfc5a
--- /dev/null
@@ -0,0 +1,2 @@
+PASS
+
diff --git a/LayoutTests/traversal/hixie-node-iterator/009.xml b/LayoutTests/traversal/hixie-node-iterator/009.xml
new file mode 100644 (file)
index 0000000..3c400fa
--- /dev/null
@@ -0,0 +1,56 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>DOM Traversal: NodeIterator: Removal of an ancestor of the Reference Node (backwards) (deep check)</title>
+  <script type="text/javascript"> <![CDATA[
+    var errors = 0;
+    var log = '';
+    function doTest() {
+      if (window.layoutTestController) layoutTestController.dumpAsText();
+      var iterator = document.createNodeIterator(document.getElementById('root'), NodeFilter.SHOW_ALL, null, false);
+      var root = document.getElementById('root');
+      var A = document.getElementById('A');
+      var B = document.getElementById('B');
+      var BB = document.getElementById('BB');
+      var C = document.getElementById('C');
+      check(iterator.nextNode(), root);
+      check(iterator.nextNode(), A);
+      check(iterator.nextNode(), B);
+      check(iterator.nextNode(), BB);
+      check(iterator.previousNode(), BB);
+      remove(B);
+      var X = addChildTo(A);
+      check(iterator.previousNode(), X);
+      if (errors)
+        document.getElementById('result').firstChild.data = 'FAIL: ' + errors + ' errors:\n' + log;
+      else
+        document.getElementById('result').firstChild.data = 'PASS';
+    }
+    function check(a, b) {
+      if (!a) {
+        errors += 1;
+        log += 'Found null but expected ' + b + ' (' + b.id + ').\n';
+      } else if (a != b) {
+        errors += 1;
+        log += 'Found ' + a + ' (' + a.id + ') but expected ' + b + ' (' + b.id + ').\n';
+      }
+    }
+    function remove(a) {
+      if (!a) {
+        errors += 1;
+        log += 'Tried removing null node.\n';
+      } else
+      a.parentNode.removeChild(a);
+    }
+    function addChildTo(a) {
+      var x = document.createElementNS('http://www.w3.org/1999/xhtml', 'span');
+      x.id = 'X';
+      a.appendChild(x);
+      return x;
+    }
+  ]]></script>
+ </head>
+ <body onload="doTest()">
+  <pre id="result">FAIL: Script did not complete.</pre>
+  <p><span id="root"><span id="A"></span><span id="B"><span id="BB"></span></span><span id="C"></span></span></p>
+ </body>
+</html>
diff --git a/LayoutTests/traversal/hixie-node-iterator/010-expected.txt b/LayoutTests/traversal/hixie-node-iterator/010-expected.txt
new file mode 100644 (file)
index 0000000..7ef22e9
--- /dev/null
@@ -0,0 +1 @@
+PASS
diff --git a/LayoutTests/traversal/hixie-node-iterator/010.xml b/LayoutTests/traversal/hixie-node-iterator/010.xml
new file mode 100644 (file)
index 0000000..5c67135
--- /dev/null
@@ -0,0 +1,65 @@
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+  <title>DOM Traversal: NodeIterator: Filters</title>
+  <script type="text/javascript"> <![CDATA[
+    function doTest() {
+      if (window.layoutTestController) layoutTestController.dumpAsText();
+      var iterator = document.createNodeIterator(document, NodeFilter.SHOW_ALL, testFilter, false);
+      // skips text nodes and body element
+      var expected = new Array(9, // document
+                               1, // html
+                               1, // head
+                               1, // title
+                               1, 4, // script and CDATA block
+                               // body (skipped)
+                               1, // pre
+                               // </body>
+                               8, // <!-- -->
+                               // PI skipped
+                               4); // CDATA
+      var found = new Array();
+
+      // walk document
+      var node;
+      while (node = iterator.nextNode())
+        found.push(node.nodeType);
+
+      // check results
+      var errors = 0;
+      var s = '';
+      var length = (found.length > expected.length) ? found.length : expected.length;
+      s += 'EXPECTED  FOUND\n';
+      for (var i = 0; i < length; i += 1) {
+        s += '  ' + (expected[i] ? expected[i] : '-') +
+      '         ' + (found[i] ? found[i] : '-');
+        if (found[i] != expected[i]) {
+          s += '      MISMATCH';
+          errors += 1;
+        }
+        s += '\n';
+      }
+      var p = document.getElementsByTagNameNS('http://www.w3.org/1999/xhtml', 'pre')[0];
+      if (errors)
+        p.firstChild.data = 'FAIL: ' + errors + ' errors found:\n\n' + s;
+      else
+        p.firstChild.data = 'PASS';
+    }
+
+    function testFilter(n) {
+      if (n.nodeType == 3) {
+        return NodeFilter.FILTER_SKIP;
+      } else if (n.nodeName == 'body') {
+        return NodeFilter.FILTER_REJECT; // same as _SKIP
+      }
+      return 1; // FILTER_ACCEPT
+    }
+
+  ]]></script>
+ </head>
+ <body onload="doTest()">
+  <pre id="result">FAIL: Script failed to run.</pre>
+ </body>
+ <!-- some more nodes to test this: -->
+ <?body test?>
+ <![CDATA[ ]]>
+</html>
\ No newline at end of file
diff --git a/LayoutTests/traversal/hixie-node-iterator/origin.txt b/LayoutTests/traversal/hixie-node-iterator/origin.txt
new file mode 100644 (file)
index 0000000..18b00f9
--- /dev/null
@@ -0,0 +1,10 @@
+I got these tests from http://www.hixie.ch/tests/adhoc/dom/traversal/node-iterator/ on February 3, 2008.
+The only changes I made were:
+
+    1) Add layoutTestController.dumpAsText() calls to each test.
+
+    2) Changed the <![CDATA[]]> near the bottom of tests 001, 002, and 010 to
+       <![CDATA[ ]]> to work around <http://bugzilla.gnome.org/show_bug.cgi?id=514181>.
+       Without the space, libxml2 omits the CharacterData node, causing the tests to fail.
+
+    -- Darin
index e4ff15f..24d450e 100644 (file)
@@ -1,4 +1,4 @@
-Expect ref node 'A'; pointer before: * A B C D E F G H I
+Expect ref node root; pointer after: A B C D E F G H I
 
 Expect ref node 'A'; pointer after: [A] * B C D E F G H I
 
index acc926b..3e7b2d2 100644 (file)
@@ -21,7 +21,7 @@ function testNodeFiter(n)
 }
 
 var it = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT, testNodeFiter, false);
-document.write(dumpNodeIterator(it, "ref node 'A'; pointer before"));
+document.write(dumpNodeIterator(it, "ref node root; pointer after"));
 it.nextNode();
 document.write(dumpNodeIterator(it, "ref node 'A'; pointer after"));
 it.previousNode();
index d4c5b3f..92f50e1 100644 (file)
@@ -4,9 +4,7 @@
 <title>Traversal Test</title> 
 </head> 
 <body>
-<div id="test">
-<span id="A"></span><span id="B"></span><span id="C"></span>
-</div>
+<div id="test"><span id="A"></span><span id="B"></span><span id="C"></span></div>
 <div style="font-family: Courier; font-size: 14;">
 <script>
 if (window.layoutTestController)
diff --git a/LayoutTests/traversal/node-iterator-006a-expected.txt b/LayoutTests/traversal/node-iterator-006a-expected.txt
new file mode 100644 (file)
index 0000000..822fbf2
--- /dev/null
@@ -0,0 +1,5 @@
+Expect ref node 'C'; pointer before: A B * [C]
+
+remove node 'C'
+
+Expect ref node 'B'; pointer after: A B
diff --git a/LayoutTests/traversal/node-iterator-006a.html b/LayoutTests/traversal/node-iterator-006a.html
new file mode 100644 (file)
index 0000000..d4c5b3f
--- /dev/null
@@ -0,0 +1,37 @@
+<html> 
+<head>
+<script src=traversal.js language="JavaScript" type="text/JavaScript" ></script>
+<title>Traversal Test</title> 
+</head> 
+<body>
+<div id="test">
+<span id="A"></span><span id="B"></span><span id="C"></span>
+</div>
+<div style="font-family: Courier; font-size: 14;">
+<script>
+if (window.layoutTestController)
+    layoutTestController.dumpAsText();
+
+var root = document.getElementById('test');
+
+function testNodeFiter(n)
+{
+    if (n.tagName == 'SPAN') return NodeFilter.FILTER_ACCEPT;
+    return NodeFilter.FILTER_SKIP;
+}
+
+var it = document.createNodeIterator(root, NodeFilter.SHOW_ELEMENT, testNodeFiter, false);
+for (i = 0; i < 3; i++)
+    it.nextNode();
+ it.previousNode();
+document.write(dumpNodeIterator(it, "ref node 'C'; pointer before"));
+
+// remove node 'C'
+document.write("<p>remove node 'C'");
+var D = document.getElementById('C');
+root.removeChild(D);
+document.write(dumpNodeIterator(it, "ref node 'B'; pointer after"));
+</script>
+</div>
+</body>
+</html>
diff --git a/LayoutTests/traversal/resources/TEMPLATE.html b/LayoutTests/traversal/resources/TEMPLATE.html
new file mode 100644 (file)
index 0000000..70ce56c
--- /dev/null
@@ -0,0 +1,13 @@
+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
+<html>
+<head>
+<link rel="stylesheet" href="../../fast/js/resources/js-test-style.css">
+<script src="../../fast/js/resources/js-test-pre.js"></script>
+</head>
+<body>
+<p id="description"></p>
+<div id="console"></div>
+<script src="YOUR_JS_FILE_HERE"></script>
+<script src="../../fast/js/resources/js-test-post.js"></script>
+</body>
+</html>
diff --git a/LayoutTests/traversal/resources/exception-forwarding.js b/LayoutTests/traversal/resources/exception-forwarding.js
new file mode 100644 (file)
index 0000000..570769d
--- /dev/null
@@ -0,0 +1,32 @@
+description("Test of exception forwarding for NodeIterator and TreeWalker, derived from an early version of Acid3");
+
+var iteration = 0;
+function test(node)
+{
+    iteration += 1;
+    switch (iteration) {
+        case 1: case 3: case 4: case 6: case 7: case 8: case 9: case 12: throw "Roses";
+        case 2: case 5: case 10: case 11: return true;
+        default: throw 0;
+    }
+}
+
+var i = document.createNodeIterator(document.documentElement, 0xFFFFFFFF, test, true);
+shouldThrow("i.nextNode()"); // 1
+shouldBe("i.nextNode()", "document.documentElement"); // 2
+shouldThrow("i.previousNode()"); // 3
+var w = document.createTreeWalker(document.documentElement, 0xFFFFFFFF, test, true);
+shouldThrow("w.nextNode()"); // 4
+shouldBe("w.nextNode()", "document.documentElement.firstChild"); // 5
+shouldThrow("w.previousNode()"); // 6
+shouldThrow("w.firstChild()"); // 7
+shouldThrow("w.lastChild()"); // 8
+shouldThrow("w.nextSibling()"); // 9
+shouldBe("w.previousSibling()", "null");
+shouldBe("w.nextSibling()", "document.body"); // 10
+shouldBe("w.previousSibling()", "document.body.previousSibling"); // 11
+shouldBe("iteration", "11");
+
+var succesfullyParsed = true;
+
+var successfullyParsed = true;
diff --git a/LayoutTests/traversal/tree-walker-filter-1-expected.txt b/LayoutTests/traversal/tree-walker-filter-1-expected.txt
new file mode 100644 (file)
index 0000000..5f50e6a
--- /dev/null
@@ -0,0 +1,20 @@
+PASS:Proper a.firstChild()
+PASS:Proper b.firstChild()
+PASS:Shouldn't move
+PASS:Proper b.nextSibling()
+PASS:Proper c.nextSibling()
+PASS:Proper e.nextSibling()
+PASS:Proper f.previousSibling()
+PASS:Proper e.previousSibling()
+PASS:Shouldn't move
+PASS:Proper h.previousSibling()
+PASS:Proper g.previousSibling()
+PASS:Proper f.nextSibling()
+PASS:Proper f.parentNode()
+PASS:Proper a.parentNode()
+PASS:Proper a's parent.nextNode()
+PASS:Re-capture #1
+PASS:Re-capture #2
+PASS:nextNode from a
+PASS:prevNode to a
+All done!
diff --git a/LayoutTests/traversal/tree-walker-filter-1.html b/LayoutTests/traversal/tree-walker-filter-1.html
new file mode 100644 (file)
index 0000000..2777e2f
--- /dev/null
@@ -0,0 +1,117 @@
+<script>
+function doLog(msg)
+{
+    var d = document.createElement("div");
+    d.innerHTML = msg;
+    document.body.appendChild(d);
+}
+
+function report(msg, res)
+{
+    if (res)
+        msg = "<font color=green>PASS:</font>" + msg;
+    else
+        msg = "<font color=red>FAIL:</font>" + msg;
+    doLog(msg);
+}
+
+/*
+ Tree:
+    a
+        b
+            c
+        d
+            e
+        f
+        g
+            h
+   b, c are rejected,
+   d is skipped.
+   g is rejected
+*/
+function kid(parent) {
+    var newKid = document.createElement("div");
+    parent.appendChild(newKid);
+    return newKid;
+}
+
+function test() {
+    if (window.layoutTestController)
+        layoutTestController.dumpAsText();
+
+    var wrapper = document.createElement("div"); // just to have one more level up.
+
+    var a = kid(wrapper);
+        var b = kid(a);
+            var c = kid(b);
+        var d = kid(a);
+            var e = kid(d);
+        var f = kid(a);
+        var g = kid(a);
+            var h = kid(g);
+    a.setAttribute("id", "a");
+    b.setAttribute("id", "b");
+    c.setAttribute("id", "c");
+    d.setAttribute("id", "d");
+    e.setAttribute("id", "e");
+    f.setAttribute("id", "f");
+    g.setAttribute("id", "g");
+    h.setAttribute("id", "h");
+
+    function filter(node) {
+        if (node == b || node == c || node == g)
+            return NodeFilter.FILTER_REJECT;
+        if (node == d)
+            return NodeFilter.FILTER_SKIP;
+        return NodeFilter.FILTER_ACCEPT;
+    }
+    
+    var tw = document.createTreeWalker(a, NodeFilter.SHOW_ALL, filter, true);
+    report("Proper a.firstChild()", tw.firstChild() == e);
+
+    tw.currentNode = b;
+    report("Proper b.firstChild()", tw.firstChild() == null);
+    // shouldn't move.
+    report("Shouldn't move", tw.currentNode == b);
+
+    tw.currentNode = b;
+    report("Proper b.nextSibling()", tw.nextSibling() == e);
+
+    // This is because we should treat 'b' as skipped when we are under it.
+    tw.currentNode = c;
+    report("Proper c.nextSibling()", tw.nextSibling() == e);
+
+    tw.currentNode = e;
+    report("Proper e.nextSibling()", tw.nextSibling() == f);
+
+    tw.currentNode = f;
+    report("Proper f.previousSibling()", tw.previousSibling() == e);
+    tw.currentNode = e;
+    report("Proper e.previousSibling()", tw.previousSibling() == null);
+    report("Shouldn't move", tw.currentNode == e);
+
+    tw.currentNode = h;
+    report("Proper h.previousSibling()", tw.previousSibling() == f);
+
+    tw.currentNode = g;
+    report("Proper g.previousSibling()", tw.previousSibling() == f);
+    // f is g's previous sibling, but not the other way around :-)
+    tw.currentNode = f;
+    report("Proper f.nextSibling()", tw.nextSibling() == null);
+    report("Proper f.parentNode()", tw.parentNode() == a);
+    report("Proper a.parentNode()", tw.parentNode() == null);
+
+    // Test exit/capture.
+    tw.currentNode = a.parentNode;
+    report("Proper a's parent.nextNode()", tw.nextNode() == a);
+    // Should get caught..
+    report("Re-capture #1", tw.previousNode() == null);
+    report("Re-capture #2", tw.parentNode() == null);
+    report("nextNode from a", tw.nextNode() == e);
+    report("prevNode to a", tw.previousNode() == a);
+
+    doLog("All done!");
+}
+
+</script>
+<body onload="test()">
index aabb976..08ba8de 100644 (file)
@@ -1,3 +1,130 @@
+2008-02-08  Darin Adler  <darin@apple.com>
+
+        Reviewed by Eric.
+
+        - fix http://bugs.webkit.org/show_bug.cgi?id=3492
+          TreeWalker implementation needs to be fixed (affects Acid3)
+        - fix http://bugs.webkit.org/show_bug.cgi?id=4714
+          NodeIterator does not handle exceptions from the filter function (affects Acid3)
+        - fix http://bugs.webkit.org/show_bug.cgi?id=4716
+          NodeIterator will crash if the filter function removes the current node from the document
+
+        Test: traversal/exception-forwarding.html
+
+        This turned into a near-rewrite of NodeIterator and TreeWalker.
+
+        * bindings/js/JSNodeFilterCondition.h:
+        * bindings/js/JSNodeFilterCondition.cpp:
+        (WebCore::takeException): Added.
+        (WebCore::JSNodeFilterCondition::acceptNode): Added an out parameter to return
+        a JavaScript exception.
+
+        * bindings/js/JSNodeFilterCustom.cpp:
+        (WebCore::JSNodeFilter::acceptNode): Wrote a custom binding for this that raises
+        a JavaScript exception if the out parameter is set.
+
+        * bindings/js/JSNodeIteratorCustom.cpp:
+        (WebCore::JSNodeIterator::nextNode): Wrote a custom binding for this that raises
+        a JavaScript exception if the out parameter is set.
+        (WebCore::JSNodeIterator::previousNode): Ditto.
+
+        * bindings/js/JSTreeWalkerCustom.cpp:
+        (WebCore::JSTreeWalker::parentNode): Wrote a custom binding for this that raises
+        a JavaScript exception if the out parameter is set.
+        (WebCore::JSTreeWalker::firstChild): Ditto.
+        (WebCore::JSTreeWalker::lastChild): Ditto.
+        (WebCore::JSTreeWalker::nextSibling): Ditto.
+        (WebCore::JSTreeWalker::previousSibling): Ditto.
+        (WebCore::JSTreeWalker::previousNode): Ditto.
+        (WebCore::JSTreeWalker::nextNode): Ditto.
+
+        * bindings/objc/DOM.mm:
+        (WebCore::ObjCNodeFilterCondition::acceptNode): Updated to include new exception
+        out parameter.
+        (-[DOMDocument createNodeIterator:whatToShow:filter:expandEntityReferences:]):
+        Use RefPtr to make object lifetimes clearer.
+        (-[DOMDocument createTreeWalker:whatToShow:filter:expandEntityReferences:]):
+        Ditto.
+
+        * bindings/scripts/CodeGeneratorJS.pm: Added include of NodeFilter.h for
+        JSDocument.cpp.
+
+        * dom/Document.h:
+        * dom/Document.cpp:
+        (WebCore::Document::createNodeIterator): Changed to use PassRefPtr.
+        (WebCore::Document::createTreeWalker): Ditto.
+
+        * dom/NodeFilter.h:
+        * dom/NodeFilter.cpp:
+        (WebCore::NodeFilter::NodeFilter): Changed to use PassRefPtr.
+        (WebCore::NodeFilter::acceptNode): Added an out parameter to return
+        a JavaScript exception.
+        * dom/NodeFilter.idl: Custom binding for acceptNode.
+
+        * dom/NodeFilterCondition.h:
+        * dom/NodeFilterCondition.cpp:
+        (WebCore::NodeFilterCondition::acceptNode): Added an out parameter to return
+        a JavaScript exception.
+
+        * dom/NodeIterator.cpp:
+        (WebCore::NodeIterator::NodeIterator): Changed to use PassRefPtr more.
+        Eliminated m_doc, using the root node instead, and unnecessary check for
+        null -- rootNode must be non-null and all nodes have a non-null document.
+        (WebCore::NodeIterator::~NodeIterator): Changed to get document from root.
+        (WebCore::NodeIterator::nextNode): Rewrote to use a RefPtr since the
+        acceptNode function could do anything, including removing the last
+        reference to the current node. Also folded findNextNode into this function
+        since it's the only one that needs to call it.
+        (WebCore::NodeIterator::previousNode): Same thing, but the other direction.
+        (WebCore::NodeIterator::detach): Changed to use the root node as the indication
+        that we're detached rather than a separate boolean.
+        (WebCore::NodeIterator::notifyBeforeNodeRemoval): Removed some unnneeded
+        checks. Removed incorrect use of findNextNode/findPreviousNode -- those
+        functions call acceptNode and the DOM standard is quite clear that these
+        functions do not take that into account, allowing the current node to become
+        one that's not accepted.
+
+        * dom/NodeIterator.h: Changed constructor to use PassRefPtr more. Changed
+        nextNode and previousNode to have an out parameter with a JavaScript exception.
+        Removed helper functions setReferenceNode, setPointerBeforeReferenceNode,
+        detached, setDetached, document, findNextNode, and findPreviousNode. All were
+        unnecessary. Removed data member m_doc which was just rootNode()->document().
+
+        * dom/NodeIterator.idl: Custom binding for nextNode and previousNode.
+
+        * dom/Traversal.cpp:
+        (WebCore::Traversal::Traversal): Use PassRefPtr more.
+        (WebCore::Traversal::acceptNode): Added out parameter for JavaScript exception.
+        Also rearranged the function a little bit for clarity.
+
+        * dom/Traversal.h: Changed acceptNode to have an out parameter with a JavaScript
+        exception and made it protected, since it's only for use by the derived classes.
+
+        * dom/TreeWalker.cpp:
+        (WebCore::TreeWalker::TreeWalker): Updated to use PassRefPtr.
+        (WebCore::TreeWalker::setCurrentNode): Updated to use PassRefPtr and deleted
+        the overloaded version since it's not needed.
+        (WebCore::TreeWalker::parentNode): Rewrote to propagate the exception and also
+        to implement rules about when to check things like whether we're in the tree.
+        The previous fix where we called isDescendantOf was not entirely correct, because
+        the specification allows you to walk outside the tree if you get there somehow.
+        What it doesn't allow is walking outside the tree from inside. The new
+        implementation handles this correctly.
+        (WebCore::TreeWalker::firstChild): Ditto.
+        (WebCore::TreeWalker::lastChild): Ditto.
+        (WebCore::TreeWalker::previousSibling): Ditto.
+        (WebCore::TreeWalker::nextSibling): Ditto.
+        (WebCore::TreeWalker::previousNode): Ditto. Because of the need to check the
+        acceptNode function on parents, this can't use traversePreviousNode (more's the
+        pity, because it's a bit complicated).
+        (WebCore::TreeWalker::nextNode): Ditto.
+
+        * dom/TreeWalker.h: Changed constructor and setCurrentNode to use PassRefPtr
+        more. Changed the navigation functions to have an out parameter with a JavaScript
+        exception. Removed helper functions setCurrentNode and ancestorRejected.
+
+        * dom/TreeWalker.idl: Custom binding for navigation functions.
+
 2008-02-08  Eric Seidel  <eric@webkit.org>
 
         Reviewed by darin.
index a21509a..17884f9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
- *  Copyright (C) 2007 Apple Inc. All rights reserved.
+ *  Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
 
 namespace WebCore {
 
-JSNodeFilterCondition::JSNodeFilterCondition(KJS::JSObject* filter)
+using namespace KJS;
+
+// FIXME: Add takeException as a member of ExecState?
+static JSValue* takeException(ExecState* exec)
+{
+    JSValue* exception = exec->exception();
+    exec->clearException();
+    return exception;
+}
+
+JSNodeFilterCondition::JSNodeFilterCondition(JSObject* filter)
     : m_filter(filter)
 {
 }
@@ -39,22 +49,36 @@ void JSNodeFilterCondition::mark()
     m_filter->mark();
 }
 
-short JSNodeFilterCondition::acceptNode(Node* filterNode) const
+short JSNodeFilterCondition::acceptNode(Node* filterNode, JSValue*& exception) const
 {
-    Node* node = filterNode;
-    Frame* frame = node->document()->frame();
-    KJSProxy* proxy = frame->scriptProxy();
-    if (proxy && m_filter->implementsCall()) {
-        KJS::JSLock lock;
-        KJS::ExecState* exec = proxy->globalObject()->globalExec();
-        KJS::List args;
-        args.append(toJS(exec, node));
-        KJS::JSObject* obj = m_filter;
-        KJS::JSValue* result = obj->call(exec, obj, args);
-        return result->toInt32(exec);
-    }
+    // FIXME: It makes no sense for this to depend on the document being in a frame!
+    Frame* frame = filterNode->document()->frame();
+    if (!frame)
+        return NodeFilter::FILTER_REJECT;
 
-    return NodeFilter::FILTER_REJECT;
+    JSLock lock;
+
+    if (!m_filter->implementsCall())
+        return NodeFilter::FILTER_REJECT;
+
+    ExecState* exec = frame->scriptProxy()->globalObject()->globalExec();
+    List args;
+    args.append(toJS(exec, filterNode));
+    if (exec->hadException()) {
+        exception = takeException(exec);
+        return NodeFilter::FILTER_REJECT;
+    }
+    JSValue* result = m_filter->call(exec, m_filter, args);
+    if (exec->hadException()) {
+        exception = takeException(exec);
+        return NodeFilter::FILTER_REJECT;
+    }
+    int intResult = result->toInt32(exec);
+    if (exec->hadException()) {
+        exception = takeException(exec);
+        return NodeFilter::FILTER_REJECT;
+    }
+    return intResult;
 }
 
 } // namespace WebCore
index bd172b9..65519e9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *  Copyright (C) 2001 Peter Kelly (pmk@post.com)
- *  Copyright (C) 2007 Apple Inc. All rights reserved.
+ *  Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
  *
  *  This library is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU Lesser General Public
 #define JSNodeFilterCondition_h
 
 #include "NodeFilterCondition.h"
-#include "kjs_dom.h"
+
+namespace KJS {
+    class JSObject;
+}
 
 namespace WebCore {
 
@@ -30,7 +33,7 @@ namespace WebCore {
     class JSNodeFilterCondition : public NodeFilterCondition {
     public:
         JSNodeFilterCondition(KJS::JSObject* filter);
-        virtual short acceptNode(Node*) const;
+        virtual short acceptNode(Node*, KJS::JSValue*& exception) const;
         virtual void mark();
 
     protected:
index 258059c..413abf9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -29,6 +29,9 @@
 #include "JSNodeFilterCondition.h"
 #include "NodeFilter.h"
 #include "kjs_binding.h"
+#include "kjs_dom.h"
+
+using namespace KJS;
 
 namespace WebCore {
 
@@ -38,6 +41,15 @@ void JSNodeFilter::mark()
     DOMObject::mark();
 }
 
+JSValue* JSNodeFilter::acceptNode(ExecState* exec, const List& args)
+{
+    JSValue* exception = 0;
+    short result = impl()->acceptNode(toNode(args[0]), exception);
+    if (exception)
+        exec->setException(exception);
+    return jsNumber(result);
+}
+
 NodeFilter* toNodeFilter(KJS::JSValue* val)
 {
     if (!val || !val->isObject())
index deb0ffe..937efa0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  * Boston, MA 02110-1301, USA.
  */
+
 #include "config.h"
 #include "JSNodeIterator.h"
 
+#include "JSNode.h"
+#include "Node.h"
 #include "NodeFilter.h"
 #include "NodeIterator.h"
 
+using namespace KJS;
+
 namespace WebCore {
 
 void JSNodeIterator::mark()
@@ -32,4 +37,36 @@ void JSNodeIterator::mark()
     DOMObject::mark();
 }
 
+JSValue* JSNodeIterator::nextNode(ExecState* exec, const List& args)
+{
+    ExceptionCode ec = 0;
+    JSValue* exception = 0;
+    Node* node = impl()->nextNode(ec, exception);
+    if (ec) {
+        setDOMException(exec, ec);
+        return jsUndefined();
+    }
+    if (exception) {
+        exec->setException(exception);
+        return jsUndefined();
+    }
+    return toJS(exec, node);
+}
+
+JSValue* JSNodeIterator::previousNode(ExecState* exec, const List& args)
+{
+    ExceptionCode ec = 0;
+    JSValue* exception = 0;
+    Node* node = impl()->previousNode(ec, exception);
+    if (ec) {
+        setDOMException(exec, ec);
+        return jsUndefined();
+    }
+    if (exception) {
+        exec->setException(exception);
+        return jsUndefined();
+    }
+    return toJS(exec, node);
+}
+
 }
index c73fe40..c9dbcd9 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  * Boston, MA 02110-1301, USA.
  */
+
 #include "config.h"
 #include "JSTreeWalker.h"
 
+#include "JSNode.h"
+#include "Node.h"
 #include "NodeFilter.h"
 #include "TreeWalker.h"
 
+using namespace KJS;
+
 namespace WebCore {
     
 void JSTreeWalker::mark()
@@ -32,4 +37,81 @@ void JSTreeWalker::mark()
     DOMObject::mark();
 }
     
+JSValue* JSTreeWalker::parentNode(ExecState* exec, const List& args)
+{
+    JSValue* exception = 0;
+    Node* node = impl()->parentNode(exception);
+    if (exception) {
+        exec->setException(exception);
+        return jsUndefined();
+    }
+    return toJS(exec, node);
+}
+    
+JSValue* JSTreeWalker::firstChild(ExecState* exec, const List& args)
+{
+    JSValue* exception = 0;
+    Node* node = impl()->firstChild(exception);
+    if (exception) {
+        exec->setException(exception);
+        return jsUndefined();
+    }
+    return toJS(exec, node);
+}
+    
+JSValue* JSTreeWalker::lastChild(ExecState* exec, const List& args)
+{
+    JSValue* exception = 0;
+    Node* node = impl()->lastChild(exception);
+    if (exception) {
+        exec->setException(exception);
+        return jsUndefined();
+    }
+    return toJS(exec, node);
+}
+    
+JSValue* JSTreeWalker::nextSibling(ExecState* exec, const List& args)
+{
+    JSValue* exception = 0;
+    Node* node = impl()->nextSibling(exception);
+    if (exception) {
+        exec->setException(exception);
+        return jsUndefined();
+    }
+    return toJS(exec, node);
+}
+    
+JSValue* JSTreeWalker::previousSibling(ExecState* exec, const List& args)
+{
+    JSValue* exception = 0;
+    Node* node = impl()->previousSibling(exception);
+    if (exception) {
+        exec->setException(exception);
+        return jsUndefined();
+    }
+    return toJS(exec, node);
+}
+    
+JSValue* JSTreeWalker::previousNode(ExecState* exec, const List& args)
+{
+    JSValue* exception = 0;
+    Node* node = impl()->previousNode(exception);
+    if (exception) {
+        exec->setException(exception);
+        return jsUndefined();
+    }
+    return toJS(exec, node);
+}
+    
+JSValue* JSTreeWalker::nextNode(ExecState* exec, const List& args)
+{
+    JSValue* exception = 0;
+    Node* node = impl()->nextNode(exception);
+    if (exception) {
+        exec->setException(exception);
+        return jsUndefined();
+    }
+    return toJS(exec, node);
+}
+
 }
index 93deb23..956d849 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
  * Copyright (C) 2006 James G. Speth (speth@end.com)
  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
  *
@@ -74,6 +74,9 @@
 #import "DOMSVG.h"
 #endif
 
+using namespace KJS;
+using namespace WebCore;
+
 namespace WebCore {
 
 class ObjCEventListener : public EventListener {
@@ -682,15 +685,16 @@ static NSArray *kit(const Vector<IntRect>& rects)
 
 @end
 
-
 //------------------------------------------------------------------------------------------
 // ObjCNodeFilterCondition
 
-class ObjCNodeFilterCondition : public WebCore::NodeFilterCondition {
+namespace WebCore {
+
+class ObjCNodeFilterCondition : public NodeFilterCondition {
 public:
     ObjCNodeFilterCondition(id <DOMNodeFilter>);
     virtual ~ObjCNodeFilterCondition();
-    virtual short acceptNode(WebCore::Node*) const;
+    virtual short acceptNode(Node*, JSValue*& exception) const;
 
 private:
     ObjCNodeFilterCondition(const ObjCNodeFilterCondition&);
@@ -711,13 +715,14 @@ ObjCNodeFilterCondition::~ObjCNodeFilterCondition()
     HardRelease(m_filter);
 }
 
-short ObjCNodeFilterCondition::acceptNode(WebCore::Node* node) const
+short ObjCNodeFilterCondition::acceptNode(Node* node, JSValue*&) const
 {
     if (!node)
-        return WebCore::NodeFilter::FILTER_REJECT;
+        return NodeFilter::FILTER_REJECT;
     return [m_filter acceptNode:[DOMNode _wrapNode:node]];
 }
 
+} // namespace WebCore
 
 //------------------------------------------------------------------------------------------
 // DOMDocument (DOMDocumentTraversal)
@@ -727,23 +732,23 @@ short ObjCNodeFilterCondition::acceptNode(WebCore::Node* node) const
 
 - (DOMNodeIterator *)createNodeIterator:(DOMNode *)root whatToShow:(unsigned)whatToShow filter:(id <DOMNodeFilter>)filter expandEntityReferences:(BOOL)expandEntityReferences
 {
-    WebCore::NodeFilter* cppFilter = 0;
+    RefPtr<NodeFilter> cppFilter;
     if (filter)
-        cppFilter = new WebCore::NodeFilter(new ObjCNodeFilterCondition(filter));
-    WebCore::ExceptionCode ec = 0;
-    RefPtr<WebCore::NodeIterator> impl = [self _document]->createNodeIterator([root _node], whatToShow, cppFilter, expandEntityReferences, ec);
-    WebCore::raiseOnDOMError(ec);
+        cppFilter = new NodeFilter(new ObjCNodeFilterCondition(filter));
+    ExceptionCode ec = 0;
+    RefPtr<NodeIterator> impl = [self _document]->createNodeIterator([root _node], whatToShow, cppFilter.release(), expandEntityReferences, ec);
+    raiseOnDOMError(ec);
     return [DOMNodeIterator _wrapNodeIterator:impl.get() filter:filter];
 }
 
 - (DOMTreeWalker *)createTreeWalker:(DOMNode *)root whatToShow:(unsigned)whatToShow filter:(id <DOMNodeFilter>)filter expandEntityReferences:(BOOL)expandEntityReferences
 {
-    WebCore::NodeFilter* cppFilter = 0;
+    RefPtr<NodeFilter> cppFilter;
     if (filter)
-        cppFilter = new WebCore::NodeFilter(new ObjCNodeFilterCondition(filter));
-    WebCore::ExceptionCode ec = 0;
-    RefPtr<WebCore::TreeWalker> impl = [self _document]->createTreeWalker([root _node], whatToShow, cppFilter, expandEntityReferences, ec);
-    WebCore::raiseOnDOMError(ec);
+        cppFilter = new NodeFilter(new ObjCNodeFilterCondition(filter));
+    ExceptionCode ec = 0;
+    RefPtr<TreeWalker> impl = [self _document]->createTreeWalker([root _node], whatToShow, cppFilter.release(), expandEntityReferences, ec);
+    raiseOnDOMError(ec);
     return [DOMTreeWalker _wrapTreeWalker:impl.get() filter:filter];
 }
 
index a57bacf..c4c818f 100644 (file)
@@ -207,6 +207,10 @@ sub AddIncludesForType
     if ($type eq "CanvasGradient" or $type eq "XPathNSResolver") {
         $implIncludes{"PlatformString.h"} = 1;
     }
+
+    if ($type eq "Document") {
+        $implIncludes{"NodeFilter.h"} = 1;
+    }
 }
 
 sub AddIncludesForSVGAnimatedType
index 4617133..9fdeeeb 100644 (file)
@@ -3,7 +3,7 @@
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2001 Dirk Mueller (mueller@kde.org)
  *           (C) 2006 Alexey Proskuryakov (ap@webkit.org)
- * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -1004,7 +1004,7 @@ PassRefPtr<Range> Document::createRange()
 }
 
 PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatToShow, 
-    NodeFilter* filter, bool expandEntityReferences, ExceptionCode& ec)
+    PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec)
 {
     if (!root) {
         ec = NOT_SUPPORTED_ERR;
@@ -1014,7 +1014,7 @@ PassRefPtr<NodeIterator> Document::createNodeIterator(Node* root, unsigned whatT
 }
 
 PassRefPtr<TreeWalker> Document::createTreeWalker(Node *root, unsigned whatToShow, 
-    NodeFilter* filter, bool expandEntityReferences, ExceptionCode& ec)
+    PassRefPtr<NodeFilter> filter, bool expandEntityReferences, ExceptionCode& ec)
 {
     if (!root) {
         ec = NOT_SUPPORTED_ERR;
index 7fedfe9..9503974 100644 (file)
@@ -3,7 +3,7 @@
  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
  *           (C) 2001 Dirk Mueller (mueller@kde.org)
  *           (C) 2006 Alexey Proskuryakov (ap@webkit.org)
- * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -330,10 +330,10 @@ public:
     PassRefPtr<Range> createRange();
 
     PassRefPtr<NodeIterator> createNodeIterator(Node* root, unsigned whatToShow,
-        NodeFilter*, bool expandEntityReferences, ExceptionCode&);
+        PassRefPtr<NodeFilter>, bool expandEntityReferences, ExceptionCode&);
 
     PassRefPtr<TreeWalker> createTreeWalker(Node* root, unsigned whatToShow, 
-        NodeFilter*, bool expandEntityReferences, ExceptionCode&);
+        PassRefPtr<NodeFilter>, bool expandEntityReferences, ExceptionCode&);
 
     // Special support for editing
     PassRefPtr<CSSStyleDeclaration> createCSSStyleDeclaration();
index e53d30f..e38a515 100644 (file)
@@ -478,23 +478,17 @@ Node *Node::childNode(unsigned /*index*/) const
 
 Node *Node::traverseNextNode(const Node *stayWithin) const
 {
-    if (firstChild()) {
-        ASSERT(!stayWithin || firstChild()->isDescendantOf(stayWithin));
+    if (firstChild())
         return firstChild();
-    }
     if (this == stayWithin)
         return 0;
-    if (nextSibling()) {
-        ASSERT(!stayWithin || nextSibling()->isDescendantOf(stayWithin));
+    if (nextSibling())
         return nextSibling();
-    }
     const Node *n = this;
     while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin))
         n = n->parentNode();
-    if (n) {
-        ASSERT(!stayWithin || !n->nextSibling() || n->nextSibling()->isDescendantOf(stayWithin));
+    if (n)
         return n->nextSibling();
-    }
     return 0;
 }
 
@@ -502,17 +496,13 @@ Node *Node::traverseNextSibling(const Node *stayWithin) const
 {
     if (this == stayWithin)
         return 0;
-    if (nextSibling()) {
-        ASSERT(!stayWithin || nextSibling()->isDescendantOf(stayWithin));
+    if (nextSibling())
         return nextSibling();
-    }
     const Node *n = this;
     while (n && !n->nextSibling() && (!stayWithin || n->parentNode() != stayWithin))
         n = n->parentNode();
-    if (n) {
-        ASSERT(!stayWithin || !n->nextSibling() || n->nextSibling()->isDescendantOf(stayWithin));
+    if (n)
         return n->nextSibling();
-    }
     return 0;
 }
 
@@ -531,23 +521,31 @@ Node *Node::traversePreviousNode(const Node *stayWithin) const
 
 Node *Node::traversePreviousNodePostOrder(const Node *stayWithin) const
 {
-    if (lastChild()) {
-        ASSERT(!stayWithin || lastChild()->isDescendantOf(stayWithin));
+    if (lastChild())
         return lastChild();
-    }
     if (this == stayWithin)
         return 0;
-    if (previousSibling()) {
-        ASSERT(!stayWithin || previousSibling()->isDescendantOf(stayWithin));
+    if (previousSibling())
+        return previousSibling();
+    const Node *n = this;
+    while (n && !n->previousSibling() && (!stayWithin || n->parentNode() != stayWithin))
+        n = n->parentNode();
+    if (n)
+        return n->previousSibling();
+    return 0;
+}
+
+Node* Node::traversePreviousSiblingPostOrder(const Node* stayWithin) const
+{
+    if (this == stayWithin)
+        return 0;
+    if (previousSibling())
         return previousSibling();
-    }
     const Node *n = this;
     while (n && !n->previousSibling() && (!stayWithin || n->parentNode() != stayWithin))
         n = n->parentNode();
-    if (n) {
-        ASSERT(!stayWithin || !n->previousSibling() || n->previousSibling()->isDescendantOf(stayWithin));
+    if (n)
         return n->previousSibling();
-    }
     return 0;
 }
 
index 53285a6..42326bf 100644 (file)
@@ -328,6 +328,7 @@ public:
 
     /* Like traversePreviousNode, but visits nodes before their children. */
     Node* traversePreviousNodePostOrder(const Node *stayWithin = 0) const;
+    Node* traversePreviousSiblingPostOrder(const Node *stayWithin = 0) const;
 
     /**
      * Finds previous or next editable leaf node.
index ff5ad92..1844a2d 100644 (file)
@@ -1,11 +1,9 @@
-/**
- * This file is part of the DOM implementation for KDE.
- *
+/*
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
  * Copyright (C) 2001 Peter Kelly (pmk@post.com)
  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004 Apple Computer, Inc.
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 #include "config.h"
 #include "NodeFilter.h"
 
-namespace WebCore {
+using namespace KJS;
 
-NodeFilter::NodeFilter(NodeFilterCondition* condition)
-    : m_condition(condition)
-{
-}
+namespace WebCore {
 
-short NodeFilter::acceptNode(Node* node) const
+short NodeFilter::acceptNode(Node* node, JSValue*& exception) const
 {
     // cast to short silences "enumeral and non-enumeral types in return" warning
-    return m_condition ? m_condition->acceptNode(node) : static_cast<short>(FILTER_ACCEPT);
+    return m_condition ? m_condition->acceptNode(node, exception) : static_cast<short>(FILTER_ACCEPT);
 }
 
 } // namespace WebCore
index 66b175d..1100bd2 100644 (file)
@@ -1,11 +1,9 @@
 /*
- * This file is part of the DOM implementation for KDE.
- *
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
  * Copyright (C) 2001 Peter Kelly (pmk@post.com)
  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004 Apple Computer, Inc.
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -28,6 +26,7 @@
 #define NodeFilter_h
 
 #include "NodeFilterCondition.h"
+#include <wtf/PassRefPtr.h>
 #include <wtf/RefPtr.h>
 
 namespace WebCore {
@@ -66,10 +65,13 @@ namespace WebCore {
             SHOW_NOTATION                  = 0x00000800
         };
 
-        NodeFilter(NodeFilterCondition*);
-        short acceptNode(Node*) const;
+        NodeFilter(PassRefPtr<NodeFilterCondition> condition) : m_condition(condition) { }
+        short acceptNode(Node*, KJS::JSValue*& exception) const;
         void mark() { m_condition->mark(); };
 
+        // For non-JS bindings. Silently ignores the JavaScript exception if any.
+        short acceptNode(Node* node) const { KJS::JSValue* exception; return acceptNode(node, exception); }
+
     private:
         RefPtr<NodeFilterCondition> m_condition;
     };
index 1e0eac0..3cc5e86 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
  * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
@@ -43,7 +43,7 @@ module traversal {
         const unsigned long       SHOW_DOCUMENT_FRAGMENT         = 0x00000400;
         const unsigned long       SHOW_NOTATION                  = 0x00000800;
 
-        short acceptNode(in Node n);
+        [Custom] short acceptNode(in Node n);
 
     };
 
index 5ee81c3..48bdcb4 100644 (file)
@@ -1,11 +1,9 @@
-/**
- * This file is part of the DOM implementation for KDE.
- *
+/*
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
  * Copyright (C) 2001 Peter Kelly (pmk@post.com)
  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004 Apple Computer, Inc.
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 
 #include "NodeFilter.h"
 
+using namespace KJS;
+
 namespace WebCore {
 
-short NodeFilterCondition::acceptNode(Node*) const
+short NodeFilterCondition::acceptNode(Node*, JSValue*&) const
 {
     return NodeFilter::FILTER_ACCEPT;
 }
index 74fa2fa..0882249 100644 (file)
@@ -1,11 +1,9 @@
 /*
- * This file is part of the DOM implementation for KDE.
- *
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
  * Copyright (C) 2001 Peter Kelly (pmk@post.com)
  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004 Apple Computer, Inc.
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 
 #include <wtf/RefCounted.h>
 
+namespace KJS {
+    class JSValue;
+}
+
 namespace WebCore {
 
     class Node;
@@ -36,7 +38,7 @@ namespace WebCore {
     class NodeFilterCondition : public RefCounted<NodeFilterCondition> {
     public:
         virtual ~NodeFilterCondition() { }
-        virtual short acceptNode(Node*) const;
+        virtual short acceptNode(Node*, KJS::JSValue*& exception) const;
         virtual void mark() { }
     };
 
index 47117b2..502d393 100644 (file)
@@ -1,11 +1,9 @@
-/**
- * This file is part of the DOM implementation for KDE.
- *
+/*
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
  * Copyright (C) 2001 Peter Kelly (pmk@post.com)
  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004 Apple Computer, Inc.
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 #include "ExceptionCode.h"
 #include "NodeFilter.h"
 
+using namespace KJS;
+
 namespace WebCore {
 
-NodeIterator::NodeIterator(Node* rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences)
+NodeIterator::NodePointer::NodePointer()
+{
+}
+
+NodeIterator::NodePointer::NodePointer(PassRefPtr<Node> n, bool b)
+    : node(n)
+    , isPointerBeforeNode(b)
+{
+}
+
+void NodeIterator::NodePointer::clear()
+{
+    node.clear();
+}
+
+bool NodeIterator::NodePointer::moveToNext(Node* root)
+{
+    if (!node)
+        return false;
+    if (isPointerBeforeNode) {
+        isPointerBeforeNode = false;
+        return true;
+    }
+    node = node->traverseNextNode(root);
+    return node;
+}
+
+bool NodeIterator::NodePointer::moveToPrevious(Node* root)
+{
+    if (!node)
+        return false;
+    if (!isPointerBeforeNode) {
+        isPointerBeforeNode = true;
+        return true;
+    }
+    node = node->traversePreviousNode(root);
+    return node;
+}
+
+NodeIterator::NodeIterator(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences)
     : Traversal(rootNode, whatToShow, filter, expandEntityReferences)
-    , m_beforeReferenceNode(true)
+    , m_referenceNode(root(), true)
     , m_detached(false)
-    , m_doc(rootNode ? rootNode->document() : 0)
 {
-    if (document())
-        document()->attachNodeIterator(this);
+    root()->document()->attachNodeIterator(this);
 }
 
 NodeIterator::~NodeIterator()
 {
-    if (document())
-        document()->detachNodeIterator(this);
+    root()->document()->detachNodeIterator(this);
 }
 
-Node* NodeIterator::findNextNode(Node* node) const
+Node* NodeIterator::nextNode(ExceptionCode& ec, JSValue*& exception)
 {
-    while ((node = node->traverseNextNode(root()))) {
+    if (m_detached) {
+        ec = INVALID_STATE_ERR;
+        return 0;
+    }
+
+    Node* result = 0;
+
+    m_candidateNode = m_referenceNode;
+    while (m_candidateNode.moveToNext(root())) {
         // NodeIterators treat the DOM tree as a flat list of nodes.
         // In other words, FILTER_REJECT does not pass over descendants
         // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
-        if (acceptNode(node) == NodeFilter::FILTER_ACCEPT)
+        exception = 0;
+        bool nodeWasAccepted = acceptNode(m_candidateNode.node.get(), exception) == NodeFilter::FILTER_ACCEPT;
+        if (exception)
+            break;
+        if (nodeWasAccepted) {
+            m_referenceNode = m_candidateNode;
+            result = m_referenceNode.node.get();
             break;
+        }
     }
-    return node;
+
+    m_candidateNode.clear();
+    return result;
 }
 
-Node* NodeIterator::nextNode(ExceptionCode& ec)
+Node* NodeIterator::previousNode(ExceptionCode& ec, JSValue*& exception)
 {
-    if (detached()) {
+    if (m_detached) {
         ec = INVALID_STATE_ERR;
         return 0;
     }
 
-    Node* node = referenceNode() ? referenceNode() : root();
-    if (!pointerBeforeReferenceNode() || acceptNode(node) != NodeFilter::FILTER_ACCEPT)
-        node = findNextNode(node);
-    if (node)
-        setReferenceNode(node);
-    setPointerBeforeReferenceNode(false);
-    return node;
-}
+    Node* result = 0;
 
-Node* NodeIterator::findPreviousNode(Node* node) const
-{
-    while ((node = node->traversePreviousNode(root()))) {
+    m_candidateNode = m_referenceNode;
+    while (m_candidateNode.moveToPrevious(root())) {
         // NodeIterators treat the DOM tree as a flat list of nodes.
         // In other words, FILTER_REJECT does not pass over descendants
         // of the rejected node. Hence, FILTER_REJECT is the same as FILTER_SKIP.
-        if (acceptNode(node) == NodeFilter::FILTER_ACCEPT)
+        exception = 0;
+        bool nodeWasAccepted = acceptNode(m_candidateNode.node.get(), exception) == NodeFilter::FILTER_ACCEPT;
+        if (exception)
+            break;
+        if (nodeWasAccepted) {
+            m_referenceNode = m_candidateNode;
+            result = m_referenceNode.node.get();
             break;
+        }
     }
-    return node;
-}
 
-Node* NodeIterator::previousNode(ExceptionCode&)
-{
-    Node* node = referenceNode() ? referenceNode() : root();
-    if (pointerBeforeReferenceNode() || acceptNode(node) != NodeFilter::FILTER_ACCEPT)
-        node = findPreviousNode(node);
-    if (node)
-        setReferenceNode(node);
-    setPointerBeforeReferenceNode();
-    return node;
+    m_candidateNode.clear();
+    return result;
 }
 
 void NodeIterator::detach()
 {
-    if (!detached() && document())
-        document()->detachNodeIterator(this);
-    setDetached();
+    root()->document()->detachNodeIterator(this);
+    m_detached = true;
+    m_referenceNode.node.clear();
 }
 
-void NodeIterator::setReferenceNode(Node* node)
+void NodeIterator::notifyBeforeNodeRemoval(Node* removedNode)
 {
-    m_referenceNode = node;
+    updateForNodeRemoval(removedNode, m_referenceNode);
 }
 
-void NodeIterator::notifyBeforeNodeRemoval(Node* removedNode)
+void NodeIterator::updateForNodeRemoval(Node* removedNode, NodePointer& referenceNode) const
 {
+    ASSERT(!m_detached);
+    ASSERT(removedNode);
+    ASSERT(root()->document() == removedNode->document());
+
     // Iterator is not affected if the removed node is the reference node and is the root.
     // or if removed node is not the reference node, or the ancestor of the reference node.
-    if (!removedNode || removedNode == root() || !removedNode->isDescendantOf(root()))
+    if (!removedNode->isDescendantOf(root()))
         return;
-    bool willRemoveReferenceNode = removedNode == referenceNode();
-    bool willRemoveReferenceNodeAncestor = referenceNode() && referenceNode()->isDescendantOf(removedNode);
+    bool willRemoveReferenceNode = removedNode == referenceNode.node;
+    bool willRemoveReferenceNodeAncestor = referenceNode.node && referenceNode.node->isDescendantOf(removedNode);
     if (!willRemoveReferenceNode && !willRemoveReferenceNodeAncestor)
         return;
 
-    if (pointerBeforeReferenceNode()) {
-        Node* node = findNextNode(removedNode);
+    if (referenceNode.isPointerBeforeNode) {
+        Node* node = removedNode->traverseNextNode(root());
         if (node) {
             // Move out from under the node being removed if the reference node is
             // a descendant of the node being removed.
             if (willRemoveReferenceNodeAncestor) {
                 while (node && node->isDescendantOf(removedNode))
-                    node = findNextNode(node);
+                    node = node->traverseNextNode(root());
             }
             if (node)
-                setReferenceNode(node);
+                referenceNode.node = node;
         } else {
-            node = findPreviousNode(removedNode);
+            node = removedNode->traversePreviousNode(root());
             if (node) {
                 // Move out from under the node being removed if the reference node is
                 // a descendant of the node being removed.
                 if (willRemoveReferenceNodeAncestor) {
                     while (node && node->isDescendantOf(removedNode))
-                        node = findPreviousNode(node);
+                        node = node->traversePreviousNode(root());
                 }
                 if (node) {
                     // Removing last node.
                     // Need to move the pointer after the node preceding the 
                     // new reference node.
-                    setReferenceNode(node);
-                    setPointerBeforeReferenceNode(false);
+                    referenceNode.node = node;
+                    referenceNode.isPointerBeforeNode = false;
                 }
             }
         }
     } else {
-        Node* node = findPreviousNode(removedNode);
+        Node* node = removedNode->traversePreviousNode(root());
         if (node) {
             // Move out from under the node being removed if the reference node is
             // a descendant of the node being removed.
             if (willRemoveReferenceNodeAncestor) {
                 while (node && node->isDescendantOf(removedNode))
-                    node = findPreviousNode(node);
+                    node = node->traversePreviousNode(root());
             }
             if (node)
-                setReferenceNode(node);
+                referenceNode.node = node;
         } else {
-            node = findNextNode(removedNode);
+            node = removedNode->traverseNextNode(root());
             // Move out from under the node being removed if the reference node is
             // a descendant of the node being removed.
             if (willRemoveReferenceNodeAncestor) {
                 while (node && node->isDescendantOf(removedNode))
-                    node = findPreviousNode(node);
+                    node = node->traversePreviousNode(root());
             }
             if (node)
-                setReferenceNode(node);
+                referenceNode.node = node;
         }
     }
 }
index b737e57..b2a7c70 100644 (file)
@@ -1,11 +1,9 @@
 /*
- * This file is part of the DOM implementation for KDE.
- *
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
  * Copyright (C) 2001 Peter Kelly (pmk@post.com)
  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004 Apple Computer, Inc.
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 #define NodeIterator_h
 
 #include "Traversal.h"
+#include <wtf/PassRefPtr.h>
 
 namespace WebCore {
 
-    class Document;
-
     typedef int ExceptionCode;
 
     class NodeIterator : public Traversal {
     public:
-        NodeIterator(Node*, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences);
-        ~NodeIterator();
+        NodeIterator(PassRefPtr<Node>, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences);
+        virtual ~NodeIterator();
 
-        Node* nextNode(ExceptionCode&);
-        Node* previousNode(ExceptionCode&);
+        Node* nextNode(ExceptionCode&, KJS::JSValue*& exception);
+        Node* previousNode(ExceptionCode&, KJS::JSValue*& exception);
         void detach();
 
-        Node* referenceNode() const { return m_referenceNode.get(); }
-        bool pointerBeforeReferenceNode() const { return m_beforeReferenceNode; }
+        Node* referenceNode() const { return m_referenceNode.node.get(); }
+        bool pointerBeforeReferenceNode() const { return m_referenceNode.isPointerBeforeNode; }
 
-        /**
-         * This function has to be called if you delete a node from the
-         * document tree and you want the Iterator to react if there
-         * are any changes concerning it.
-         */
-        void notifyBeforeNodeRemoval(Node* removed);
+        // This function is called before any node is removed from the document tree.
+        void notifyBeforeNodeRemoval(Node* nodeToBeRemoved);
+
+        // For non-JS bindings. Silently ignores the JavaScript exception if any.
+        Node* nextNode(ExceptionCode& ec) { KJS::JSValue* exception; return nextNode(ec, exception); }
+        Node* previousNode(ExceptionCode& ec) { KJS::JSValue* exception; return previousNode(ec, exception); }
 
     private:
-        void setReferenceNode(Node*);
-        void setPointerBeforeReferenceNode(bool flag = true) { m_beforeReferenceNode = flag; }
-        bool detached() const { return m_detached; }
-        void setDetached(bool flag = true) { m_detached = flag; }
-        Document* document() const { return m_doc.get(); }
-        Node* findNextNode(Node*) const;
-        Node* findPreviousNode(Node*) const;
+        struct NodePointer {
+            RefPtr<Node> node;
+            bool isPointerBeforeNode;
+            NodePointer();
+            NodePointer(PassRefPtr<Node>, bool);
+            void clear();
+            bool moveToNext(Node* root);
+            bool moveToPrevious(Node* root);
+        };
+
+        void updateForNodeRemoval(Node* nodeToBeRemoved, NodePointer&) const;
 
-        RefPtr<Node> m_referenceNode;
-        bool m_beforeReferenceNode;
+        NodePointer m_referenceNode;
+        NodePointer m_candidateNode;
         bool m_detached;
-        RefPtr<Document> m_doc;
     };
 
 } // namespace WebCore
index 4c82cc0..e129de3 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2006 Apple Computer, Inc.
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
  * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
@@ -29,9 +29,9 @@ module traversal {
         readonly attribute Node referenceNode;
         readonly attribute boolean pointerBeforeReferenceNode;
 
-        Node nextNode() 
+        [Custom] Node nextNode() 
             raises (DOMException);
-        Node previousNode()
+        [Custom] Node previousNode()
             raises (DOMException);
         void detach();
     };
index 5e1aa03..dca6c68 100644 (file)
@@ -1,11 +1,9 @@
-/**
- * This file is part of the DOM implementation for KDE.
- *
+/*
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
  * Copyright (C) 2001 Peter Kelly (pmk@post.com)
  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004 Apple Computer, Inc.
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 
 #include "Node.h"
 #include "NodeFilter.h"
-#include <wtf/PassRefPtr.h>
+
+using namespace KJS;
 
 namespace WebCore {
 
-Traversal::Traversal(Node* rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> nodeFilter, bool expandEntityReferences)
+Traversal::Traversal(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> nodeFilter, bool expandEntityReferences)
     : m_root(rootNode)
     , m_whatToShow(whatToShow)
     , m_filter(nodeFilter)
@@ -45,15 +44,17 @@ Traversal::~Traversal()
 {
 }
 
-short Traversal::acceptNode(Node* node) const
+short Traversal::acceptNode(Node* node, JSValue*& exception) const
 {
-    // FIXME: If XML is implemented we have to check expandEntityRerefences in this function.
+    // FIXME: To handle XML properly we would have to check m_expandEntityReferences.
+
     // The bid twiddling here is done to map DOM node types, which are given as integers from
     // 1 through 12, to whatToShow bit masks.
-    if (node && ((1 << (node->nodeType()-1)) & m_whatToShow))
-        // cast to short silences "enumeral and non-enumeral types in return" warning
-        return m_filter ? m_filter->acceptNode(node) : static_cast<short>(NodeFilter::FILTER_ACCEPT);
-    return NodeFilter::FILTER_SKIP;
+    if (!(((1 << (node->nodeType() - 1)) & m_whatToShow)))
+        return NodeFilter::FILTER_SKIP;
+    if (!m_filter)
+        return NodeFilter::FILTER_ACCEPT;
+    return m_filter->acceptNode(node, exception);
 }
 
 } // namespace WebCore
index 7611145..78265e0 100644 (file)
@@ -1,11 +1,9 @@
 /*
- * This file is part of the DOM implementation for KDE.
- *
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
  * Copyright (C) 2001 Peter Kelly (pmk@post.com)
  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004 Apple Computer, Inc.
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 #ifndef Traversal_h
 #define Traversal_h
 
-#include <wtf/RefCounted.h>
 #include <wtf/Forward.h>
+#include <wtf/RefCounted.h>
 #include <wtf/RefPtr.h>
 
+namespace KJS {
+    class JSValue;
+}
+
 namespace WebCore {
 
     class Node;
@@ -38,7 +40,7 @@ namespace WebCore {
 
     class Traversal : public RefCounted<Traversal> {
     public:
-        Traversal(Node*, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences);
+        Traversal(PassRefPtr<Node>, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences);
         virtual ~Traversal();
 
         Node* root() const { return m_root.get(); }
@@ -46,7 +48,8 @@ namespace WebCore {
         NodeFilter* filter() const { return m_filter.get(); }
         bool expandEntityReferences() const { return m_expandEntityReferences; }
 
-        short acceptNode(Node*) const;
+    protected:
+        short acceptNode(Node*, KJS::JSValue*& jsException) const;
 
     private:
         RefPtr<Node> m_root;
index ffa8ae7..09c1c95 100644 (file)
@@ -1,11 +1,9 @@
-/**
- * This file is part of the DOM implementation for KDE.
- *
+/*
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
  * Copyright (C) 2001 Peter Kelly (pmk@post.com)
  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004 Apple Computer, Inc.
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
 #include "NodeFilter.h"
 #include <wtf/PassRefPtr.h>
 
+using namespace KJS;
+
 namespace WebCore {
 
-TreeWalker::TreeWalker(Node* rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences)
+TreeWalker::TreeWalker(PassRefPtr<Node> rootNode, unsigned whatToShow, PassRefPtr<NodeFilter> filter, bool expandEntityReferences)
     : Traversal(rootNode, whatToShow, filter, expandEntityReferences)
-    , m_current(rootNode)
+    , m_current(root())
 {
 }
 
-void TreeWalker::setCurrentNode(Node* node, ExceptionCode& ec)
+void TreeWalker::setCurrentNode(PassRefPtr<Node> node, ExceptionCode& ec)
 {
     if (!node) {
         ec = NOT_SUPPORTED_ERR;
@@ -49,97 +49,237 @@ void TreeWalker::setCurrentNode(Node* node, ExceptionCode& ec)
     m_current = node;
 }
 
-void TreeWalker::setCurrentNode(Node* node)
+inline Node* TreeWalker::setCurrent(PassRefPtr<Node> node)
 {
-    ASSERT(node);
-    int dummy;
-    setCurrentNode(node, dummy);
+    m_current = node;
+    return m_current.get();
 }
 
-Node* TreeWalker::parentNode()
+Node* TreeWalker::parentNode(JSValue*& exception)
 {
-    for (Node* node = currentNode()->parentNode(); node && (node == root() || node->isDescendantOf(root())); node = node->parentNode()) {
-        if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) {
-            setCurrentNode(node);
-            return node;
-        }
+    exception = 0;
+    RefPtr<Node> node = m_current;
+    while (node != root()) {
+        node = node->parentNode();
+        if (!node)
+            return 0;
+        short acceptNodeResult = acceptNode(node.get(), exception);
+        if (exception)
+            return 0;
+        if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
+            return setCurrent(node.release());
     }
     return 0;
 }
 
-Node* TreeWalker::firstChild()
+Node* TreeWalker::firstChild(JSValue*& exception)
 {
-    for (Node* node = currentNode()->firstChild(); node && (node == root() || node->isDescendantOf(root())); node = node->nextSibling()) {
-        if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) {
-            setCurrentNode(node);
-            return node;
+    exception = 0;
+    for (RefPtr<Node> node = m_current->firstChild(); node; ) {
+        short acceptNodeResult = acceptNode(node.get(), exception);
+        if (exception)
+            return 0;
+        switch (acceptNodeResult) {
+            case NodeFilter::FILTER_ACCEPT:
+                m_current = node.release();
+                return m_current.get();
+            case NodeFilter::FILTER_SKIP:
+                if (node->firstChild()) {
+                    node = node->firstChild();
+                    continue;
+                }
+                break;
+            case NodeFilter::FILTER_REJECT:
+                break;
         }
+        do {
+            if (node->nextSibling()) {
+                node = node->nextSibling();
+                break;
+            }
+            Node* parent = node->parentNode();
+            if (!parent || parent == root() || parent == m_current)
+                return 0;
+            node = parent;
+        } while (node);
     }
     return 0;
 }
 
-Node* TreeWalker::lastChild()
+Node* TreeWalker::lastChild(JSValue*& exception)
 {
-    for (Node* node = currentNode()->lastChild(); node && (node == root() || node->isDescendantOf(root())); node = node->previousSibling()) {
-        if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) {
-            setCurrentNode(node);
-            return node;
+    exception = 0;
+    for (RefPtr<Node> node = m_current->lastChild(); node; ) {
+        short acceptNodeResult = acceptNode(node.get(), exception);
+        if (exception)
+            return 0;
+        switch (acceptNodeResult) {
+            case NodeFilter::FILTER_ACCEPT:
+                m_current = node.release();
+                return m_current.get();
+            case NodeFilter::FILTER_SKIP:
+                if (node->lastChild()) {
+                    node = node->lastChild();
+                    continue;
+                }
+                break;
+            case NodeFilter::FILTER_REJECT:
+                break;
         }
+        do {
+            if (node->previousSibling()) {
+                node = node->previousSibling();
+                break;
+            }
+            Node* parent = node->parentNode();
+            if (!parent || parent == root() || parent == m_current)
+                return 0;
+            node = parent;
+        } while (node);
     }
     return 0;
 }
 
-Node* TreeWalker::previousSibling()
+Node* TreeWalker::previousSibling(JSValue*& exception)
 {
-    for (Node* node = currentNode()->previousSibling(); node && (node == root() || node->isDescendantOf(root())); node = node->previousSibling()) {
-        if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) {
-            setCurrentNode(node);
-            return node;
+    exception = 0;
+    RefPtr<Node> node = m_current;
+    if (node == root())
+        return 0;
+    while (1) {
+        for (RefPtr<Node> sibling = node->previousSibling(); sibling; ) {
+            short acceptNodeResult = acceptNode(sibling.get(), exception);
+            if (exception)
+                return 0;
+            switch (acceptNodeResult) {
+                case NodeFilter::FILTER_ACCEPT:
+                    m_current = sibling.release();
+                    return m_current.get();
+                case NodeFilter::FILTER_SKIP:
+                    if (sibling->firstChild()) {
+                        sibling = sibling->firstChild();
+                        continue;
+                    }
+                    break;
+                case NodeFilter::FILTER_REJECT:
+                    break;
+            }
+            sibling = sibling->previousSibling();
         }
+        node = node->parentNode();
+        if (!node || node == root())
+            return 0;
+        short acceptNodeResult = acceptNode(node.get(), exception);
+        if (exception)
+            return 0;
+        if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
+            return 0;
     }
-    return 0;
 }
 
-Node* TreeWalker::nextSibling()
+Node* TreeWalker::nextSibling(JSValue*& exception)
 {
-    for (Node* node = currentNode()->nextSibling(); node && (node == root() || node->isDescendantOf(root())); node = node->nextSibling()) {
-        if (acceptNode(node) == NodeFilter::FILTER_ACCEPT) {
-            setCurrentNode(node);
-            return node;
+    exception = 0;
+    RefPtr<Node> node = m_current;
+    if (node == root())
+        return 0;
+    while (1) {
+        for (RefPtr<Node> sibling = node->nextSibling(); sibling; ) {
+            short acceptNodeResult = acceptNode(sibling.get(), exception);
+            if (exception)
+                return 0;
+            switch (acceptNodeResult) {
+                case NodeFilter::FILTER_ACCEPT:
+                    m_current = sibling.release();
+                    return m_current.get();
+                case NodeFilter::FILTER_SKIP:
+                    if (sibling->firstChild()) {
+                        sibling = sibling->firstChild();
+                        continue;
+                    }
+                    break;
+                case NodeFilter::FILTER_REJECT:
+                    break;
+            }
+            sibling = sibling->nextSibling();
         }
+        node = node->parentNode();
+        if (!node || node == root())
+            return 0;
+        short acceptNodeResult = acceptNode(node.get(), exception);
+        if (exception)
+            return 0;
+        if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
+            return 0;
     }
-    return 0;
 }
 
-Node* TreeWalker::previousNode()
+Node* TreeWalker::previousNode(JSValue*& exception)
 {
-    for (Node* node = currentNode()->traversePreviousNode(); node && (node == root() || node->isDescendantOf(root())); node = node->traversePreviousNode()) {
-        if (acceptNode(node) == NodeFilter::FILTER_ACCEPT && !ancestorRejected(node)) {
-            setCurrentNode(node);
-            return node;
+    exception = 0;
+    RefPtr<Node> node = m_current;
+    while (node != root()) {
+        while (Node* previousSibling = node->previousSibling()) {
+            node = previousSibling;
+            short acceptNodeResult = acceptNode(node.get(), exception);
+            if (exception)
+                return 0;
+            if (acceptNodeResult == NodeFilter::FILTER_REJECT)
+                continue;
+            while (Node* lastChild = node->lastChild()) {
+                node = lastChild;
+                acceptNodeResult = acceptNode(node.get(), exception);
+                if (exception)
+                    return 0;
+                if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
+                    continue;
+            }
+            if (acceptNodeResult == NodeFilter::FILTER_ACCEPT) {
+                m_current = node.release();
+                return m_current.get();
+            }
         }
+        if (node == root())
+            return 0;
+        Node* parent = node->parentNode();
+        if (!parent)
+            return 0;
+        node = parent;
+        short acceptNodeResult = acceptNode(node.get(), exception);
+        if (exception)
+            return 0;
+        if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
+            return setCurrent(node.release());
     }
     return 0;
 }
 
-Node* TreeWalker::nextNode()
+Node* TreeWalker::nextNode(JSValue*& exception)
 {
-    for (Node* node = currentNode()->traverseNextNode(); node && (node == root() || node->isDescendantOf(root())); node = node->traverseNextNode()) {
-        if (acceptNode(node) == NodeFilter::FILTER_ACCEPT && !ancestorRejected(node)) {
-            setCurrentNode(node);
-            return node;
-        }
+    exception = 0;
+    RefPtr<Node> node = m_current;
+Children:
+    while (Node* firstChild = node->firstChild()) {
+        node = firstChild;
+        short acceptNodeResult = acceptNode(node.get(), exception);
+        if (exception)
+            return 0;
+        if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
+            return setCurrent(node.release());
+        if (acceptNodeResult == NodeFilter::FILTER_REJECT)
+            break;
     }
-    return 0;
-}
-
-bool TreeWalker::ancestorRejected(const Node* node) const
-{
-    for (Node* a = node->parentNode(); a && a != root(); a = a->parentNode()) {
-        if (acceptNode(a) == NodeFilter::FILTER_REJECT)
-            return true;
+    while (Node* nextSibling = node->traverseNextSibling(root())) {
+        node = nextSibling;
+        short acceptNodeResult = acceptNode(node.get(), exception);
+        if (exception)
+            return 0;
+        if (acceptNodeResult == NodeFilter::FILTER_ACCEPT)
+            return setCurrent(node.release());
+        if (acceptNodeResult == NodeFilter::FILTER_SKIP)
+            goto Children;
     }
-    return false;
+    return 0;
 }
 
 } // namespace WebCore
index 206d8ac..8b0ea98 100644 (file)
@@ -1,11 +1,9 @@
 /*
- * This file is part of the DOM implementation for KDE.
- *
  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
  * Copyright (C) 2000 Frederik Holljen (frederik.holljen@hig.no)
  * Copyright (C) 2001 Peter Kelly (pmk@post.com)
  * Copyright (C) 2006 Samuel Weinig (sam.weinig@gmail.com)
- * Copyright (C) 2004 Apple Computer, Inc.
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Library General Public
@@ -28,7 +26,6 @@
 #define TreeWalker_h
 
 #include "Traversal.h"
-#include <wtf/RefPtr.h>
 
 namespace WebCore {
 
@@ -36,23 +33,30 @@ namespace WebCore {
 
     class TreeWalker : public Traversal {
     public:
-        TreeWalker(Node*, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences);
+        TreeWalker(PassRefPtr<Node>, unsigned whatToShow, PassRefPtr<NodeFilter>, bool expandEntityReferences);
 
         Node* currentNode() const { return m_current.get(); }
-        void setCurrentNode(Node*, ExceptionCode&);
+        void setCurrentNode(PassRefPtr<Node>, ExceptionCode&);
+
+        Node* parentNode(KJS::JSValue*& exception);
+        Node* firstChild(KJS::JSValue*& exception);
+        Node* lastChild(KJS::JSValue*& exception);
+        Node* previousSibling(KJS::JSValue*& exception);
+        Node* nextSibling(KJS::JSValue*& exception);
+        Node* previousNode(KJS::JSValue*& exception);
+        Node* nextNode(KJS::JSValue*& exception);
 
-        Node* parentNode();
-        Node* firstChild();
-        Node* lastChild();
-        Node* previousSibling();
-        Node* nextSibling();
-        Node* previousNode();
-        Node* nextNode();
+        // For non-JS bindings. Silently ignores the JavaScript exception if any.
+        Node* parentNode() { KJS::JSValue* exception; return parentNode(exception); }
+        Node* firstChild() { KJS::JSValue* exception; return firstChild(exception); }
+        Node* lastChild() { KJS::JSValue* exception; return lastChild(exception); }
+        Node* previousSibling() { KJS::JSValue* exception; return previousSibling(exception); }
+        Node* nextSibling() { KJS::JSValue* exception; return nextSibling(exception); }
+        Node* previousNode() { KJS::JSValue* exception; return previousNode(exception); }
+        Node* nextNode() { KJS::JSValue* exception; return nextNode(exception); }
 
     private:
-        // convenience for when it is known there will be no exception
-        void setCurrentNode(Node*);
-        bool ancestorRejected(const Node*) const;
+        Node* setCurrent(PassRefPtr<Node>);
 
         RefPtr<Node> m_current;
     };
index bc983c3..4f98d3a 100644 (file)
@@ -29,13 +29,13 @@ module traversal {
                  attribute Node currentNode
                      setter raises(DOMException);
 
-        Node parentNode();
-        Node firstChild();
-        Node lastChild();
-        Node previousSibling();
-        Node nextSibling();
-        Node previousNode();
-        Node nextNode();
+        [Custom] Node parentNode();
+        [Custom] Node firstChild();
+        [Custom] Node lastChild();
+        [Custom] Node previousSibling();
+        [Custom] Node nextSibling();
+        [Custom] Node previousNode();
+        [Custom] Node nextNode();
     };
 
 }