<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[188917] trunk</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="http://trac.webkit.org/projects/webkit/changeset/188917">188917</a></dd>
<dt>Author</dt> <dd>cdumez@apple.com</dd>
<dt>Date</dt> <dd>2015-08-25 10:58:27 -0700 (Tue, 25 Aug 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>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 <a href="http://trac.webkit.org/projects/webkit/changeset/153660">r153660</a> 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:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsTestExpectations">trunk/LayoutTests/TestExpectations</a></li>
<li><a href="#trunkLayoutTestsdomxhtmllevel3corenodecomparedocumentposition38expectedtxt">trunk/LayoutTests/dom/xhtml/level3/core/nodecomparedocumentposition38-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastdomcomparedocumentpositiondisconnectednodesexpectedtxt">trunk/LayoutTests/fast/dom/compare-document-position-disconnected-nodes-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastdomcomparedocumentpositiondisconnectednodeshtml">trunk/LayoutTests/fast/dom/compare-document-position-disconnected-nodes.html</a></li>
<li><a href="#trunkLayoutTestsfastdomshadowcomparedocumentpositionexpectedtxt">trunk/LayoutTests/fast/dom/shadow/compare-document-position-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastdomshadowcomparedocumentpositionhtml">trunk/LayoutTests/fast/dom/shadow/compare-document-position.html</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoredomNodecpp">trunk/Source/WebCore/dom/Node.cpp</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (188916 => 188917)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-08-25 17:55:07 UTC (rev 188916)
+++ trunk/LayoutTests/ChangeLog        2015-08-25 17:58:27 UTC (rev 188917)
</span><span class="lines">@@ -1,3 +1,26 @@
</span><ins>+2015-08-25  Chris Dumez  &lt;cdumez@apple.com&gt;
+
+        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:
+
</ins><span class="cx"> 2015-08-24  Nan Wang  &lt;n_wang@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         AX: Fix accessibility/mac/search-with-frames.html test
</span></span></pre></div>
<a id="trunkLayoutTestsTestExpectations"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/TestExpectations (188916 => 188917)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/TestExpectations        2015-08-25 17:55:07 UTC (rev 188916)
+++ trunk/LayoutTests/TestExpectations        2015-08-25 17:58:27 UTC (rev 188917)
</span><span class="lines">@@ -126,6 +126,21 @@
</span><span class="cx"> webkit.org/b/74144 fast/regions/universal-selector-children-to-the-same-region.html [ Skip ]
</span><span class="cx"> webkit.org/b/74144 fast/regions/region-content-flown-into-region.html [ Skip ]
</span><span class="cx"> 
</span><ins>+# 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 ]
+
</ins><span class="cx"> # Expando properties on attribute nodes disappear
</span><span class="cx"> webkit.org/b/88045 fast/dom/gc-attribute-node.html [ Failure Pass ]
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkLayoutTestsdomxhtmllevel3corenodecomparedocumentposition38expectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/dom/xhtml/level3/core/nodecomparedocumentposition38-expected.txt (188916 => 188917)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,3 +1,2 @@
</span><span class="cx"> Test        http://www.w3.org/2001/DOM-Test-Suite/level3/core/nodecomparedocumentposition38
</span><del>-Status        failure
-Message        nodecomparedocumentpositionIsContainsFollowing38: assertEquals failed, actual 33, expected 20.
</del><ins>+Status        Success
</ins></span></pre></div>
<a id="trunkLayoutTestsfastdomcomparedocumentpositiondisconnectednodesexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/dom/compare-document-position-disconnected-nodes-expected.txt (188916 => 188917)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,3 +1,4 @@
</span><ins>+* Test with 2 disconnected elements
</ins><span class="cx"> PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
</span><span class="cx"> PASS b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
</span><span class="cx"> PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
</span><span class="lines">@@ -2,4 +3,52 @@
</span><span class="cx"> PASS b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
</span><del>-PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_PRECEDING is 0
-PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_FOLLOWING is 0
</del><ins>+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_PRECEDING is not b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_PRECEDING
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_FOLLOWING is not b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_FOLLOWING
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_PRECEDING || a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_PRECEDING || b.compareDocumentPosition(a) &amp; 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) &amp; Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_PRECEDING is not b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_PRECEDING
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_FOLLOWING is not b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_FOLLOWING
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_PRECEDING || a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_PRECEDING || b.compareDocumentPosition(a) &amp; 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) &amp; Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_PRECEDING is not b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_PRECEDING
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_FOLLOWING is not b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_FOLLOWING
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_PRECEDING || a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_PRECEDING || b.compareDocumentPosition(a) &amp; 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) &amp; Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_PRECEDING is not b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_PRECEDING
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_FOLLOWING is not b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_FOLLOWING
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_PRECEDING || a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_PRECEDING || b.compareDocumentPosition(a) &amp; 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) &amp; Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_PRECEDING is not b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_PRECEDING
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_FOLLOWING is not b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_FOLLOWING
+PASS a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_PRECEDING || a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_PRECEDING || b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS a.compareDocumentPosition(b) is a.compareDocumentPosition(b)
+PASS b.compareDocumentPosition(a) is b.compareDocumentPosition(a)
</ins><span class="cx"> PASS successfullyParsed is true
</span></span></pre></div>
<a id="trunkLayoutTestsfastdomcomparedocumentpositiondisconnectednodeshtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/dom/compare-document-position-disconnected-nodes.html (188916 => 188917)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -3,15 +3,35 @@
</span><span class="cx"> &lt;head&gt;
</span><span class="cx">     &lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
</span><span class="cx">     &lt;script&gt;
</span><del>-        window.a = document.createElement('a');
-        window.b = document.createElement('b');
</del><ins>+        var a, b;
</ins><span class="cx"> 
</span><del>-        shouldBe('a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_DISCONNECTED', 'Node.DOCUMENT_POSITION_DISCONNECTED');
-        shouldBe('b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_DISCONNECTED', 'Node.DOCUMENT_POSITION_DISCONNECTED');
-        shouldBe('a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC', 'Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
-        shouldBe('b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC', 'Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
-        shouldBe('a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_PRECEDING', '0');
-        shouldBe('a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_FOLLOWING', '0');
</del><ins>+        function testElements(_a, _b) {
+            a = _a;
+            b = _b;
+
+            shouldBe('a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_DISCONNECTED', 'Node.DOCUMENT_POSITION_DISCONNECTED');
+            shouldBe('b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_DISCONNECTED', 'Node.DOCUMENT_POSITION_DISCONNECTED');
+            shouldBe('a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC', 'Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
+            shouldBe('b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC', 'Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
+            shouldNotBe('a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_PRECEDING', 'b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_PRECEDING');
+            shouldNotBe('a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_FOLLOWING', 'b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_FOLLOWING');
+            shouldBeNonZero('a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_PRECEDING || a.compareDocumentPosition(b) &amp; Node.DOCUMENT_POSITION_FOLLOWING');
+            shouldBeNonZero('b.compareDocumentPosition(a) &amp; Node.DOCUMENT_POSITION_PRECEDING || b.compareDocumentPosition(a) &amp; 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(&quot;* Test with 2 disconnected elements&quot;);
+        testElements(document.createElement('a'), document.createElement('b'));
+        debug(&quot;* Test with document and a disconnected element&quot;);
+        testElements(document, document.createElement('b'));
+        debug(&quot;* Test with document and a disconnected attribute&quot;);
+        testElements(document, document.createAttribute('b'));
+        debug(&quot;* Test with 2 disconnected attributes&quot;);
+        testElements(document.createAttribute(&quot;a&quot;), document.createAttribute(&quot;b&quot;));
+        debug(&quot;* Test with disconnected attribute and element&quot;);
+        testElements(document.createAttribute(&quot;a&quot;), document.createElement(&quot;b&quot;));
</ins><span class="cx">     &lt;/script&gt;
</span><span class="cx">     &lt;script src=&quot;../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
</span><span class="cx"> &lt;/head&gt;
</span></span></pre></div>
<a id="trunkLayoutTestsfastdomshadowcomparedocumentpositionexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/dom/shadow/compare-document-position-expected.txt (188916 => 188917)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -9,8 +9,14 @@
</span><span class="cx"> PASS b1.compareDocumentPosition(b2) is Node.DOCUMENT_POSITION_CONTAINED_BY | Node.DOCUMENT_POSITION_FOLLOWING
</span><span class="cx"> PASS b2.compareDocumentPosition(b1) is Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING
</span><span class="cx"> PASS b2.compareDocumentPosition(b3) is Node.DOCUMENT_POSITION_FOLLOWING
</span><del>-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
</del><ins>+PASS a1.compareDocumentPosition(b1) &amp; Node.DOCUMENT_POSITION_PRECEDING || a1.compareDocumentPosition(b1) &amp; Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS a1.compareDocumentPosition(b1) &amp; Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS a1.compareDocumentPosition(b1) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS a1.compareDocumentPosition(b1) is a1.compareDocumentPosition(b1)
+PASS b1.compareDocumentPosition(c1) &amp; Node.DOCUMENT_POSITION_PRECEDING || b1.compareDocumentPosition(c1) &amp; Node.DOCUMENT_POSITION_FOLLOWING is non-zero.
+PASS b1.compareDocumentPosition(c1) &amp; Node.DOCUMENT_POSITION_DISCONNECTED is Node.DOCUMENT_POSITION_DISCONNECTED
+PASS b1.compareDocumentPosition(c1) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC is Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC
+PASS b1.compareDocumentPosition(c1) is b1.compareDocumentPosition(c1)
</ins><span class="cx"> PASS successfullyParsed is true
</span><span class="cx"> 
</span><span class="cx"> TEST COMPLETE
</span></span></pre></div>
<a id="trunkLayoutTestsfastdomshadowcomparedocumentpositionhtml"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/fast/dom/shadow/compare-document-position.html (188916 => 188917)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -45,10 +45,15 @@
</span><span class="cx">     shouldBe('b2.compareDocumentPosition(b1)', 'Node.DOCUMENT_POSITION_CONTAINS | Node.DOCUMENT_POSITION_PRECEDING');
</span><span class="cx">     shouldBe('b2.compareDocumentPosition(b3)', 'Node.DOCUMENT_POSITION_FOLLOWING');
</span><span class="cx"> 
</span><del>-    // 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');
</del><ins>+    // Nodes in different shadow trees.
+    shouldBeNonZero('a1.compareDocumentPosition(b1) &amp; Node.DOCUMENT_POSITION_PRECEDING || a1.compareDocumentPosition(b1) &amp; Node.DOCUMENT_POSITION_FOLLOWING');
+    shouldBe('a1.compareDocumentPosition(b1) &amp; Node.DOCUMENT_POSITION_DISCONNECTED', 'Node.DOCUMENT_POSITION_DISCONNECTED');
+    shouldBe('a1.compareDocumentPosition(b1) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC', 'Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
+    shouldBe('a1.compareDocumentPosition(b1)', 'a1.compareDocumentPosition(b1)');
+    shouldBeNonZero('b1.compareDocumentPosition(c1) &amp; Node.DOCUMENT_POSITION_PRECEDING || b1.compareDocumentPosition(c1) &amp; Node.DOCUMENT_POSITION_FOLLOWING');
+    shouldBe('b1.compareDocumentPosition(c1) &amp; Node.DOCUMENT_POSITION_DISCONNECTED', 'Node.DOCUMENT_POSITION_DISCONNECTED');
+    shouldBe('b1.compareDocumentPosition(c1) &amp; Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC', 'Node.DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC');
+    shouldBe('b1.compareDocumentPosition(c1)', 'b1.compareDocumentPosition(c1)');
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> testCompareDocumentPosition();
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (188916 => 188917)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -1,5 +1,32 @@
</span><span class="cx"> 2015-08-25  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><ins>+        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  &lt;cdumez@apple.com&gt;
+
</ins><span class="cx">         Add support for callback interfaces using other callback names than &quot;handleEvent&quot;
</span><span class="cx">         https://bugs.webkit.org/show_bug.cgi?id=148418
</span><span class="cx"> 
</span></span></pre></div>
<a id="trunkSourceWebCoredomNodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Node.cpp (188916 => 188917)</h4>
<pre class="diff"><span>
<span class="info">--- 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)
</span><span class="lines">@@ -71,6 +71,7 @@
</span><span class="cx"> #include &quot;WheelEvent.h&quot;
</span><span class="cx"> #include &quot;XMLNames.h&quot;
</span><span class="cx"> #include &lt;wtf/RefCountedLeakCounter.h&gt;
</span><ins>+#include &lt;wtf/SHA1.h&gt;
</ins><span class="cx"> #include &lt;wtf/text/CString.h&gt;
</span><span class="cx"> #include &lt;wtf/text/StringBuilder.h&gt;
</span><span class="cx"> 
</span><span class="lines">@@ -1460,6 +1461,31 @@
</span><span class="cx">     return false;
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+static SHA1::Digest hashPointer(void* pointer)
+{
+    SHA1 sha1;
+    sha1.addBytes(reinterpret_cast&lt;const uint8_t*&gt;(&amp;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) &gt; 0 ? Node::DOCUMENT_POSITION_PRECEDING : Node::DOCUMENT_POSITION_FOLLOWING;
+
+    return Node::DOCUMENT_POSITION_DISCONNECTED | Node::DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC | direction;
+}
+
</ins><span class="cx"> unsigned short Node::compareDocumentPosition(Node* otherNode)
</span><span class="cx"> {
</span><span class="cx">     // It is not clear what should be done if |otherNode| is nullptr.
</span><span class="lines">@@ -1478,7 +1504,7 @@
</span><span class="cx">     // If either of start1 or start2 is null, then we are disconnected, since one of the nodes is
</span><span class="cx">     // an orphaned attribute node.
</span><span class="cx">     if (!start1 || !start2)
</span><del>-        return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
</del><ins>+        return compareDetachedElementsPosition(this, otherNode);
</ins><span class="cx"> 
</span><span class="cx">     Vector&lt;Node*, 16&gt; chain1;
</span><span class="cx">     Vector&lt;Node*, 16&gt; chain2;
</span><span class="lines">@@ -1510,9 +1536,8 @@
</span><span class="cx">     // If one node is in the document and the other is not, we must be disconnected.
</span><span class="cx">     // If the nodes have different owning documents, they must be disconnected.  Note that we avoid
</span><span class="cx">     // comparing Attr nodes here, since they return false from inDocument() all the time (which seems like a bug).
</span><del>-    if (start1-&gt;inDocument() != start2-&gt;inDocument() ||
-        &amp;start1-&gt;treeScope() != &amp;start2-&gt;treeScope())
-        return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
</del><ins>+    if (start1-&gt;inDocument() != start2-&gt;inDocument() || &amp;start1-&gt;treeScope() != &amp;start2-&gt;treeScope())
+        return compareDetachedElementsPosition(this, otherNode);
</ins><span class="cx"> 
</span><span class="cx">     // We need to find a common ancestor container, and then compare the indices of the two immediate children.
</span><span class="cx">     Node* current;
</span><span class="lines">@@ -1526,7 +1551,7 @@
</span><span class="cx"> 
</span><span class="cx">     // If the two elements don't have a common root, they're not in the same tree.
</span><span class="cx">     if (chain1[index1 - 1] != chain2[index2 - 1])
</span><del>-        return DOCUMENT_POSITION_DISCONNECTED | DOCUMENT_POSITION_IMPLEMENTATION_SPECIFIC;
</del><ins>+        return compareDetachedElementsPosition(this, otherNode);
</ins><span class="cx"> 
</span><span class="cx">     // Walk the two chains backwards and look for the first difference.
</span><span class="cx">     for (unsigned i = std::min(index1, index2); i; --i) {
</span></span></pre>
</div>
</div>

</body>
</html>