compareDocumentPosition() should report PRECEEDING or FOLLOWING information even if nodes are disconnected

As per the latest specification, compareDocumentPosition() should report PRECEEDING or FOLLOWING
information even if nodes are disconnected:
- http://dom.spec.whatwg.org/#dom-node-comparedocumentposition

This behavior is consistent with both IE10 and Firefox 22.

Blink was not reporting PRECEEDING or FOLLOWING in all cases. This patches makes Blink behave
as expected.

BUG=263340
R=arv@chromium.org, haraken@chromium.org, tkent@chromium.org

Review URL: https://codereview.chromium.org/20042003

git-svn-id: svn://svn.chromium.org/blink/trunk@154835 bbb929c8-8fbe-4397-9dbb-9b2b20218538
diff --git a/LayoutTests/dom/xhtml/level3/core/nodecomparedocumentposition38-expected.txt b/LayoutTests/dom/xhtml/level3/core/nodecomparedocumentposition38-expected.txt
index 1a2c6f5..2492cbf 100644
--- a/LayoutTests/dom/xhtml/level3/core/nodecomparedocumentposition38-expected.txt
+++ b/LayoutTests/dom/xhtml/level3/core/nodecomparedocumentposition38-expected.txt
@@ -1,3 +1,3 @@
 Test	http://www.w3.org/2001/DOM-Test-Suite/level3/core/nodecomparedocumentposition38
 Status	failure
-Message	nodecomparedocumentpositionIsContainsFollowing38: assertEquals failed, actual 33, expected 20.
+Message	nodecomparedocumentpositionIsContainsFollowing38: assertEquals failed, actual 37, expected 20.
diff --git a/LayoutTests/fast/dom/compare-document-position-disconnected-nodes-expected.txt b/LayoutTests/fast/dom/compare-document-position-disconnected-nodes-expected.txt
index 6901514..4571fe1 100644
--- a/LayoutTests/fast/dom/compare-document-position-disconnected-nodes-expected.txt
+++ b/LayoutTests/fast/dom/compare-document-position-disconnected-nodes-expected.txt
@@ -1,9 +1,58 @@
+* Test with 2 disconnected elements
 PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
 PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
 PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
 PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
 PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_PRECEDING is not b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING
 PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING is not b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_FOLLOWING
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_PRECEDING || a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING || b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS a.compareDocumentPosition(b) is a.compareDocumentPosition(b)
+PASS b.compareDocumentPosition(a) is b.compareDocumentPosition(a)
+* Test with document and a disconnected element
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_PRECEDING is not b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING is not b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_FOLLOWING
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_PRECEDING || a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING || b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS a.compareDocumentPosition(b) is a.compareDocumentPosition(b)
+PASS b.compareDocumentPosition(a) is b.compareDocumentPosition(a)
+* Test with document and a disconnected attribute
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_PRECEDING is not b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING is not b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_FOLLOWING
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_PRECEDING || a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING || b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS a.compareDocumentPosition(b) is a.compareDocumentPosition(b)
+PASS b.compareDocumentPosition(a) is b.compareDocumentPosition(a)
+* Test with 2 disconnected attributes
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_PRECEDING is not b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING is not b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_FOLLOWING
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_PRECEDING || a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING || b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS a.compareDocumentPosition(b) is a.compareDocumentPosition(b)
+PASS b.compareDocumentPosition(a) is b.compareDocumentPosition(a)
+* Test with disconnected attribute and element
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_PRECEDING is not b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING is not b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_FOLLOWING
+PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_PRECEDING || a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING || b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS a.compareDocumentPosition(b) is a.compareDocumentPosition(b)
+PASS b.compareDocumentPosition(a) is b.compareDocumentPosition(a)
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/LayoutTests/fast/dom/compare-document-position-disconnected-nodes.html b/LayoutTests/fast/dom/compare-document-position-disconnected-nodes.html
index c3abef9..96aa209 100644
--- a/LayoutTests/fast/dom/compare-document-position-disconnected-nodes.html
+++ b/LayoutTests/fast/dom/compare-document-position-disconnected-nodes.html
@@ -3,15 +3,36 @@
 <head>
     <script src="../js/resources/js-test-pre.js"></script>
     <script>
-        window.a = document.createElement('a');
-        window.b = document.createElement('b');
+        var a;
+        var b;
 
-        shouldBe('a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_DISCONNECTED', 'Node.DOCUMENT_POSITION_DISCONNECTED');
-        shouldBe('b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_DISCONNECTED', 'Node.DOCUMENT_POSITION_DISCONNECTED');
-        shouldBe('a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC', 'Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
-        shouldBe('b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC', 'Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
-        shouldNotBe('a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_PRECEDING', 'b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING');
-        shouldNotBe('a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING', 'b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_FOLLOWING');
+        function testElements(_a, _b) {
+            a = _a;
+            b = _b;
+
+            shouldBe('a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_DISCONNECTED', 'Node.DOCUMENT_POSITION_DISCONNECTED');
+            shouldBe('b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_DISCONNECTED', 'Node.DOCUMENT_POSITION_DISCONNECTED');
+            shouldBe('a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC', 'Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
+            shouldBe('b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC', 'Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
+            shouldNotBe('a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_PRECEDING', 'b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING');
+            shouldNotBe('a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING', 'b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_FOLLOWING');
+            shouldBeNonZero('a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_PRECEDING || a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING');
+            shouldBeNonZero('b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_PRECEDING || b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_FOLLOWING');
+            // Make sure the returned result is consistent.
+            shouldBe('a.compareDocumentPosition(b)', 'a.compareDocumentPosition(b)');
+            shouldBe('b.compareDocumentPosition(a)', 'b.compareDocumentPosition(a)');
+        }
+
+        debug("* Test with 2 disconnected elements");
+        testElements(document.createElement('a'), document.createElement('b'));
+        debug("* Test with document and a disconnected element");
+        testElements(document, document.createElement('b'));
+        debug("* Test with document and a disconnected attribute");
+        testElements(document, document.createAttribute('b'));
+        debug("* Test with 2 disconnected attributes");
+        testElements(document.createAttribute("a"), document.createAttribute("b"));
+        debug("* Test with disconnected attribute and element");
+        testElements(document.createAttribute("a"), document.createElement("b"));
     </script>
     <script src="../js/resources/js-test-post.js"></script>
 </head>
diff --git a/LayoutTests/fast/dom/shadow/compare-document-position-expected.txt b/LayoutTests/fast/dom/shadow/compare-document-position-expected.txt
index 5d0cd7e..205801f 100644
--- a/LayoutTests/fast/dom/shadow/compare-document-position-expected.txt
+++ b/LayoutTests/fast/dom/shadow/compare-document-position-expected.txt
@@ -9,8 +9,14 @@
 PASS b1.compareDocumentPosition(b2) is Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING
 PASS b2.compareDocumentPosition(b1) is Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING
 PASS b2.compareDocumentPosition(b3) is Node.DOCUMENT_POSITION_FOLLOWING
-PASS a1.compareDocumentPosition(b1) is Node.DOCUMENT_POSITION_DISCONNECTED | Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
-PASS b1.compareDocumentPosition(c1) is Node.DOCUMENT_POSITION_DISCONNECTED | Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS a1.compareDocumentPosition(b1) & Node.DOCUMENT_POSITION_PRECEDING || a1.compareDocumentPosition(b1) & Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS a1.compareDocumentPosition(b1) & Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS a1.compareDocumentPosition(b1) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS a1.compareDocumentPosition(b1) is a1.compareDocumentPosition(b1)
+PASS b1.compareDocumentPosition(c1) & Node.DOCUMENT_POSITION_PRECEDING || b1.compareDocumentPosition(c1) & Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS b1.compareDocumentPosition(c1) & Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS b1.compareDocumentPosition(c1) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS b1.compareDocumentPosition(c1) is b1.compareDocumentPosition(c1)
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/LayoutTests/fast/dom/shadow/compare-document-position.html b/LayoutTests/fast/dom/shadow/compare-document-position.html
index 099e564..dbfbde7 100644
--- a/LayoutTests/fast/dom/shadow/compare-document-position.html
+++ b/LayoutTests/fast/dom/shadow/compare-document-position.html
@@ -45,10 +45,15 @@
     shouldBe('b2.compareDocumentPosition(b1)', 'Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING');
     shouldBe('b2.compareDocumentPosition(b3)', 'Node.DOCUMENT_POSITION_FOLLOWING');
 
-    // The current implementation does not return FOLLOWING OR PRECEDING flag.
-    // We need a stable implementation which decides the total order between nodes in different shadow trees.
-    shouldBe('a1.compareDocumentPosition(b1)', 'Node.DOCUMENT_POSITION_DISCONNECTED | Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
-    shouldBe('b1.compareDocumentPosition(c1)', 'Node.DOCUMENT_POSITION_DISCONNECTED | Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
+    // Nodes in different shadow trees.
+    shouldBeNonZero('a1.compareDocumentPosition(b1) & Node.DOCUMENT_POSITION_PRECEDING || a1.compareDocumentPosition(b1) & Node.DOCUMENT_POSITION_FOLLOWING');
+    shouldBe('a1.compareDocumentPosition(b1) & Node.DOCUMENT_POSITION_DISCONNECTED', 'Node.DOCUMENT_POSITION_DISCONNECTED');
+    shouldBe('a1.compareDocumentPosition(b1) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC', 'Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
+    shouldBe('a1.compareDocumentPosition(b1)', 'a1.compareDocumentPosition(b1)');
+    shouldBeNonZero('b1.compareDocumentPosition(c1) & Node.DOCUMENT_POSITION_PRECEDING || b1.compareDocumentPosition(c1) & Node.DOCUMENT_POSITION_FOLLOWING');
+    shouldBe('b1.compareDocumentPosition(c1) & Node.DOCUMENT_POSITION_DISCONNECTED', 'Node.DOCUMENT_POSITION_DISCONNECTED');
+    shouldBe('b1.compareDocumentPosition(c1) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC', 'Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
+    shouldBe('b1.compareDocumentPosition(c1)', 'b1.compareDocumentPosition(c1)');
 }
 
 testCompareDocumentPosition();
diff --git a/LayoutTests/fast/dom/shadow/compare-treescope-position-expected.txt b/LayoutTests/fast/dom/shadow/compare-treescope-position-expected.txt
index b0b493e..a1d5f43 100644
--- a/LayoutTests/fast/dom/shadow/compare-treescope-position-expected.txt
+++ b/LayoutTests/fast/dom/shadow/compare-treescope-position-expected.txt
@@ -13,7 +13,10 @@
 PASS internals.compareTreeScopePosition(sr3, sr1) is Node.DOCUMENT_POSITION_PRECEDING
 PASS internals.compareTreeScopePosition(document, document) is 0
 PASS internals.compareTreeScopePosition(sr1, sr1) is 0
-PASS internals.compareTreeScopePosition(sr3, sr2) is Node.DOCUMENT_POSITION_DISCONNECTED | Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS internals.compareTreeScopePosition(sr3, sr2) & Node.DOCUMENT_POSITION_PRECEDING || internals.compareTreeScopePosition(sr3, sr2) & Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS internals.compareTreeScopePosition(sr3, sr2) & Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS internals.compareTreeScopePosition(sr3, sr2) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS internals.compareTreeScopePosition(sr3, sr2) is internals.compareTreeScopePosition(sr3, sr2)
 PASS successfullyParsed is true
 
 TEST COMPLETE
diff --git a/LayoutTests/fast/dom/shadow/compare-treescope-position.html b/LayoutTests/fast/dom/shadow/compare-treescope-position.html
index 851a4e4..d2db890 100644
--- a/LayoutTests/fast/dom/shadow/compare-treescope-position.html
+++ b/LayoutTests/fast/dom/shadow/compare-treescope-position.html
@@ -55,7 +55,10 @@
 
     getNodeInShadowTreeStack('a3/c1').removeChild(getNodeInShadowTreeStack('a3/c2'));
 
-    shouldBe('internals.compareTreeScopePosition(sr3, sr2)', 'Node.DOCUMENT_POSITION_DISCONNECTED | Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
+    shouldBeNonZero('internals.compareTreeScopePosition(sr3, sr2) & Node.DOCUMENT_POSITION_PRECEDING || internals.compareTreeScopePosition(sr3, sr2) & Node.DOCUMENT_POSITION_FOLLOWING');
+    shouldBe('internals.compareTreeScopePosition(sr3, sr2) & Node.DOCUMENT_POSITION_DISCONNECTED', 'Node.DOCUMENT_POSITION_DISCONNECTED');
+    shouldBe('internals.compareTreeScopePosition(sr3, sr2) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC', 'Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
+    shouldBe('internals.compareTreeScopePosition(sr3, sr2)', 'internals.compareTreeScopePosition(sr3, sr2)');
 }
 
 testCompareTreeScopePosition();
diff --git a/Source/core/dom/Node.cpp b/Source/core/dom/Node.cpp
index b34efbf..a8e04bd 100644
--- a/Source/core/dom/Node.cpp
+++ b/Source/core/dom/Node.cpp
@@ -1704,8 +1704,10 @@
     
     // If either of start1 or start2 is null, then we are disconnected, since one of the nodes is
     // an orphaned attribute node.
-    if (!start1 || !start2)
-        return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
+    if (!start1 || !start2) {
+        unsigned short direction = (this > otherNode) ? DOCUMENT_POSITION_PRECEDING : DOCUMENT_POSITION_FOLLOWING;
+        return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | direction;
+    }
 
     Vector<const Node*, 16> chain1;
     Vector<const Node*, 16> chain2;
@@ -1739,10 +1741,10 @@
     // If one node is in the document and the other is not, we must be disconnected.
     // If the nodes have different owning documents, they must be disconnected.  Note that we avoid
     // comparing Attr nodes here, since they return false from inDocument() all the time (which seems like a bug).
-    if (start1->inDocument() != start2->inDocument())
-        return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
-    if (treatment == TreatShadowTreesAsDisconnected && start1->treeScope() != start2->treeScope())
-        return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
+    if (start1->inDocument() != start2->inDocument() || (treatment == TreatShadowTreesAsDisconnected && start1->treeScope() != start2->treeScope())) {
+        unsigned short direction = (this > otherNode) ? DOCUMENT_POSITION_PRECEDING : DOCUMENT_POSITION_FOLLOWING;
+        return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | direction;
+    }
 
     // We need to find a common ancestor container, and then compare the indices of the two immediate children.
     const Node* current;
@@ -1756,7 +1758,7 @@
 
     // If the two elements don't have a common root, they're not in the same tree.
     if (chain1[index1 - 1] != chain2[index2 - 1]) {
-        unsigned short direction = (start1 > start2) ? DOCUMENT_POSITION_PRECEDING : DOCUMENT_POSITION_FOLLOWING;
+        unsigned short direction = (this > otherNode) ? DOCUMENT_POSITION_PRECEDING : DOCUMENT_POSITION_FOLLOWING;
         return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | direction;
     }