Title: [188917] trunk
Revision
188917
Author
cdu...@apple.com
Date
2015-08-25 10:58:27 -0700 (Tue, 25 Aug 2015)

Log Message

compareDocumentPosition() should report PRECEDING or FOLLOWING information even if nodes are disconnected
https://bugs.webkit.org/show_bug.cgi?id=119316

Reviewed by Darin Adler.

Source/WebCore:

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

This behavior is consistent with both IE10, Firefox and Chrome.

The implementation relies on the comparison of cryptographic hashes
(SHA1) of the Node pointers so that the results returned by the function
are consistent. We don't compare Node pointers directly as it was done
previously in r153660 to avoid leaking information about our memory
model to the Web.

Test: fast/dom/compare-document-position-disconnected-nodes.html
W3C Test suite: http://w3c-test.org/dom/nodes/Node-compareDocumentPosition.html

* dom/Node.cpp:
(WebCore::hashPointer):
(WebCore::compareDetachedElementsPosition):
(WebCore::Node::compareDocumentPosition):

LayoutTests:

Update fast/dom/compare-document-position-disconnected-nodes.html to check that compareDocumentPosition()
now returns one of the following values for disconnected nodes:
- DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | DOCUMENT_POSITION_PRECEDING
- DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | DOCUMENT_POSITION_FOLLOWING

* TestExpectations:
Several dom/xhtml/level3 are skipped and marked as WonfFix because they are outdated and no longer match
the latest DOM specification. They expect compareDocumentPosition() not to return PRECEDING / FOLLOWING
information for disconnected nodes.

* dom/xhtml/level3/core/nodecomparedocumentposition38-expected.txt:
* fast/dom/compare-document-position-disconnected-nodes-expected.txt:
* fast/dom/compare-document-position-disconnected-nodes.html:
* fast/dom/shadow/compare-document-position-expected.txt:
* fast/dom/shadow/compare-document-position.html:

Modified Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (188916 => 188917)


--- trunk/LayoutTests/ChangeLog	2015-08-25 17:55:07 UTC (rev 188916)
+++ trunk/LayoutTests/ChangeLog	2015-08-25 17:58:27 UTC (rev 188917)
@@ -1,3 +1,26 @@
+2015-08-25  Chris Dumez  <cdu...@apple.com>
+
+        compareDocumentPosition() should report PRECEDING or FOLLOWING information even if nodes are disconnected
+        https://bugs.webkit.org/show_bug.cgi?id=119316
+
+        Reviewed by Darin Adler.
+
+        Update fast/dom/compare-document-position-disconnected-nodes.html to check that compareDocumentPosition()
+        now returns one of the following values for disconnected nodes:
+        - DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | DOCUMENT_POSITION_PRECEDING
+        - DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | DOCUMENT_POSITION_FOLLOWING
+
+        * TestExpectations:
+        Several dom/xhtml/level3 are skipped and marked as WonfFix because they are outdated and no longer match
+        the latest DOM specification. They expect compareDocumentPosition() not to return PRECEDING / FOLLOWING
+        information for disconnected nodes.
+
+        * dom/xhtml/level3/core/nodecomparedocumentposition38-expected.txt:
+        * fast/dom/compare-document-position-disconnected-nodes-expected.txt:
+        * fast/dom/compare-document-position-disconnected-nodes.html:
+        * fast/dom/shadow/compare-document-position-expected.txt:
+        * fast/dom/shadow/compare-document-position.html:
+
 2015-08-24  Nan Wang  <n_w...@apple.com>
 
         AX: Fix accessibility/mac/search-with-frames.html test

Modified: trunk/LayoutTests/TestExpectations (188916 => 188917)


--- trunk/LayoutTests/TestExpectations	2015-08-25 17:55:07 UTC (rev 188916)
+++ trunk/LayoutTests/TestExpectations	2015-08-25 17:58:27 UTC (rev 188917)
@@ -126,6 +126,21 @@
 webkit.org/b/74144 fast/regions/universal-selector-children-to-the-same-region.html [ Skip ]
 webkit.org/b/74144 fast/regions/region-content-flown-into-region.html [ Skip ]
 
+# These conformace tests are no longer in sync with the latest specification
+# and expect compareDocumentPosition() to return:
+# DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | DOCUMENT_POSITION_DISCONNECTED
+# for disconnected nodes (missing PRECEDING / FOLLOWING information).
+# We cannot check rebaseline them because their output is likely to change
+# between test runs as it decides PRECEDING / FOLLOWING using pointer
+# comparison.
+dom/xhtml/level3/core/nodecomparedocumentposition03.xhtml [ WontFix ]
+dom/xhtml/level3/core/nodecomparedocumentposition05.xhtml [ WontFix ]
+dom/xhtml/level3/core/nodecomparedocumentposition16.xhtml [ WontFix ]
+dom/xhtml/level3/core/nodecomparedocumentposition33.xhtml [ WontFix ]
+
+# Node::compareDocumentPosition() wrongly reports an attribute and its content as disconnected.
+webkit.org/b/119325 dom/xhtml/level3/core/nodecomparedocumentposition38.xhtml [ Failure ]
+
 # Expando properties on attribute nodes disappear
 webkit.org/b/88045 fast/dom/gc-attribute-node.html [ Failure Pass ]
 

Modified: trunk/LayoutTests/dom/xhtml/level3/core/nodecomparedocumentposition38-expected.txt (188916 => 188917)


--- trunk/LayoutTests/dom/xhtml/level3/core/nodecomparedocumentposition38-expected.txt	2015-08-25 17:55:07 UTC (rev 188916)
+++ trunk/LayoutTests/dom/xhtml/level3/core/nodecomparedocumentposition38-expected.txt	2015-08-25 17:58:27 UTC (rev 188917)
@@ -1,3 +1,2 @@
 Test	http://www.w3.org/2001/DOM-Test-Suite/level3/core/nodecomparedocumentposition38
-Status	failure
-Message	nodecomparedocumentpositionIsContainsFollowing38: assertEquals failed, actual 33, expected 20.
+Status	Success

Modified: trunk/LayoutTests/fast/dom/compare-document-position-disconnected-nodes-expected.txt (188916 => 188917)


--- trunk/LayoutTests/fast/dom/compare-document-position-disconnected-nodes-expected.txt	2015-08-25 17:55:07 UTC (rev 188916)
+++ trunk/LayoutTests/fast/dom/compare-document-position-disconnected-nodes-expected.txt	2015-08-25 17:58:27 UTC (rev 188917)
@@ -1,3 +1,4 @@
+* 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
@@ -2,4 +3,52 @@
 PASS b.compareDocumentPosition(a) & Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
-PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_PRECEDING is 0
-PASS a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING is 0
+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

Modified: trunk/LayoutTests/fast/dom/compare-document-position-disconnected-nodes.html (188916 => 188917)


--- trunk/LayoutTests/fast/dom/compare-document-position-disconnected-nodes.html	2015-08-25 17:55:07 UTC (rev 188916)
+++ trunk/LayoutTests/fast/dom/compare-document-position-disconnected-nodes.html	2015-08-25 17:58:27 UTC (rev 188917)
@@ -3,15 +3,35 @@
 <head>
     <script src=""
     <script>
-        window.a = document.createElement('a');
-        window.b = document.createElement('b');
+        var a, 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');
-        shouldBe('a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_PRECEDING', '0');
-        shouldBe('a.compareDocumentPosition(b) & Node.DOCUMENT_POSITION_FOLLOWING', '0');
+        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=""
 </head>

Modified: trunk/LayoutTests/fast/dom/shadow/compare-document-position-expected.txt (188916 => 188917)


--- trunk/LayoutTests/fast/dom/shadow/compare-document-position-expected.txt	2015-08-25 17:55:07 UTC (rev 188916)
+++ trunk/LayoutTests/fast/dom/shadow/compare-document-position-expected.txt	2015-08-25 17:58:27 UTC (rev 188917)
@@ -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

Modified: trunk/LayoutTests/fast/dom/shadow/compare-document-position.html (188916 => 188917)


--- trunk/LayoutTests/fast/dom/shadow/compare-document-position.html	2015-08-25 17:55:07 UTC (rev 188916)
+++ trunk/LayoutTests/fast/dom/shadow/compare-document-position.html	2015-08-25 17:58:27 UTC (rev 188917)
@@ -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();

Modified: trunk/Source/WebCore/ChangeLog (188916 => 188917)


--- trunk/Source/WebCore/ChangeLog	2015-08-25 17:55:07 UTC (rev 188916)
+++ trunk/Source/WebCore/ChangeLog	2015-08-25 17:58:27 UTC (rev 188917)
@@ -1,5 +1,32 @@
 2015-08-25  Chris Dumez  <cdu...@apple.com>
 
+        compareDocumentPosition() should report PRECEDING or FOLLOWING information even if nodes are disconnected
+        https://bugs.webkit.org/show_bug.cgi?id=119316
+
+        Reviewed by Darin Adler.
+
+        As the latest DOM specification, compareDocumentPosition() should report
+        PRECEDING or FOLLOWING information even if nodes are disconnected:
+        - http://dom.spec.whatwg.org/#dom-node-comparedocumentposition
+
+        This behavior is consistent with both IE10, Firefox and Chrome.
+
+        The implementation relies on the comparison of cryptographic hashes
+        (SHA1) of the Node pointers so that the results returned by the function
+        are consistent. We don't compare Node pointers directly as it was done
+        previously in r153660 to avoid leaking information about our memory
+        model to the Web.
+
+        Test: fast/dom/compare-document-position-disconnected-nodes.html
+        W3C Test suite: http://w3c-test.org/dom/nodes/Node-compareDocumentPosition.html
+
+        * dom/Node.cpp:
+        (WebCore::hashPointer):
+        (WebCore::compareDetachedElementsPosition):
+        (WebCore::Node::compareDocumentPosition):
+
+2015-08-25  Chris Dumez  <cdu...@apple.com>
+
         Add support for callback interfaces using other callback names than "handleEvent"
         https://bugs.webkit.org/show_bug.cgi?id=148418
 

Modified: trunk/Source/WebCore/dom/Node.cpp (188916 => 188917)


--- trunk/Source/WebCore/dom/Node.cpp	2015-08-25 17:55:07 UTC (rev 188916)
+++ trunk/Source/WebCore/dom/Node.cpp	2015-08-25 17:58:27 UTC (rev 188917)
@@ -71,6 +71,7 @@
 #include "WheelEvent.h"
 #include "XMLNames.h"
 #include <wtf/RefCountedLeakCounter.h>
+#include <wtf/SHA1.h>
 #include <wtf/text/CString.h>
 #include <wtf/text/StringBuilder.h>
 
@@ -1460,6 +1461,31 @@
     return false;
 }
 
+static SHA1::Digest hashPointer(void* pointer)
+{
+    SHA1 sha1;
+    sha1.addBytes(reinterpret_cast<const uint8_t*>(&pointer), sizeof(pointer));
+    SHA1::Digest digest;
+    sha1.computeHash(digest);
+    return digest;
+}
+
+static inline unsigned short compareDetachedElementsPosition(Node* firstNode, Node* secondNode)
+{
+    // If the 2 nodes are not in the same tree, return the result of adding DOCUMENT_POSITION_DISCONNECTED,
+    // DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC, and either DOCUMENT_POSITION_PRECEDING or
+    // DOCUMENT_POSITION_FOLLOWING, with the constraint that this is to be consistent. Whether to return
+    // DOCUMENT_POSITION_PRECEDING or DOCUMENT_POSITION_FOLLOWING is implemented by comparing cryptographic
+    // hashes of Node pointers.
+    // See step 3 in https://dom.spec.whatwg.org/#dom-node-comparedocumentposition
+    SHA1::Digest firstHash = hashPointer(firstNode);
+    SHA1::Digest secondHash = hashPointer(secondNode);
+
+    unsigned short direction = memcmp(firstHash.data(), secondHash.data(), SHA1::hashSize) > 0 ? Node::DOCUMENT_POSITION_PRECEDING : Node::DOCUMENT_POSITION_FOLLOWING;
+
+    return Node::DOCUMENT_POSITION_DISCONNECTED | Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | direction;
+}
+
 unsigned short Node::compareDocumentPosition(Node* otherNode)
 {
     // It is not clear what should be done if |otherNode| is nullptr.
@@ -1478,7 +1504,7 @@
     // 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;
+        return compareDetachedElementsPosition(this, otherNode);
 
     Vector<Node*, 16> chain1;
     Vector<Node*, 16> chain2;
@@ -1510,9 +1536,8 @@
     // 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() ||
-        &start1->treeScope() != &start2->treeScope())
-        return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
+    if (start1->inDocument() != start2->inDocument() || &start1->treeScope() != &start2->treeScope())
+        return compareDetachedElementsPosition(this, otherNode);
 
     // We need to find a common ancestor container, and then compare the indices of the two immediate children.
     Node* current;
@@ -1526,7 +1551,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])
-        return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
+        return compareDetachedElementsPosition(this, otherNode);
 
     // Walk the two chains backwards and look for the first difference.
     for (unsigned i = std::min(index1, index2); i; --i) {
_______________________________________________
webkit-changes mailing list
webkit-changes@lists.webkit.org
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to