<!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>[189327] 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/189327">189327</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2015-09-03 17:48:26 -0700 (Thu, 03 Sep 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>Range.comparePoint shouldn't throw an exception if the range and the node are in the same detached tree
https://bugs.webkit.org/show_bug.cgi?id=148733

Reviewed by Chris Dumez.

Source/WebCore:

Don't throw WRONG_DOCUMENT_ERR when refNode is not in the document. The new behavior matches DOM4 as well
as the behavior of Firefox. See https://dom.spec.whatwg.org/#dom-range-comparepoint

WRONG_DOCUMENT_ERR is still thrown by compareBoundaryPoints later in the function when the root nodes of
refNode and boundary points are different.

There is one subtlety here that we need to throw WRONG_DOCUMENT_ERR instead of INDEX_SIZE_ERR when refNode
and the boundary points don't share the same root node even if (refNode, offset) pair is invalid since
DOM4 spec checks the former condition first. We implement this behavior by first validating the offset
and then explicitly checking for the root node difference if the former check failed to avoid the latter
O(n) check in common cases.

Test: fast/dom/Range/range-comparePoint-detached-nodes.html

* dom/Range.cpp:
(WebCore::Range::comparePoint):

LayoutTests:

Added a regression test and rebaselined a W3C test with more test cases passing.

* fast/dom/Range/range-comparePoint-detached-nodes-expected.txt: Added.
* fast/dom/Range/range-comparePoint-detached-nodes.html: Added.
* http/tests/w3c/dom/ranges/Range-set-expected.txt:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestshttptestsw3cdomrangesRangesetexpectedtxt">trunk/LayoutTests/http/tests/w3c/dom/ranges/Range-set-expected.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoredomRangecpp">trunk/Source/WebCore/dom/Range.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastdomRangerangecomparePointdetachednodesexpectedtxt">trunk/LayoutTests/fast/dom/Range/range-comparePoint-detached-nodes-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastdomRangerangecomparePointdetachednodeshtml">trunk/LayoutTests/fast/dom/Range/range-comparePoint-detached-nodes.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (189326 => 189327)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-09-04 00:44:37 UTC (rev 189326)
+++ trunk/LayoutTests/ChangeLog        2015-09-04 00:48:26 UTC (rev 189327)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2015-09-03  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        Range.comparePoint shouldn't throw an exception if the range and the node are in the same detached tree
+        https://bugs.webkit.org/show_bug.cgi?id=148733
+
+        Reviewed by Chris Dumez.
+
+        Added a regression test and rebaselined a W3C test with more test cases passing.
+
+        * fast/dom/Range/range-comparePoint-detached-nodes-expected.txt: Added.
+        * fast/dom/Range/range-comparePoint-detached-nodes.html: Added.
+        * http/tests/w3c/dom/ranges/Range-set-expected.txt:
+
</ins><span class="cx"> 2015-09-03  Tim Horton  &lt;timothy_horton@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Add a test for swipe-start hysteresis
</span></span></pre></div>
<a id="trunkLayoutTestsfastdomRangerangecomparePointdetachednodesexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/dom/Range/range-comparePoint-detached-nodes-expected.txt (0 => 189327)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/dom/Range/range-comparePoint-detached-nodes-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/dom/Range/range-comparePoint-detached-nodes-expected.txt        2015-09-04 00:48:26 UTC (rev 189327)
</span><span class="lines">@@ -0,0 +1,17 @@
</span><ins>+This test calls comparePoint on detached nodes. They should compare nodes when they're in the same detached tree and throw otherwise.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS var range = new Range; range.setStart(detachedDiv, 0); range.comparePoint(detachedDiv, 0); is 0
+PASS var range = new Range; range.setStart(detachedDiv, 0); range.comparePoint(detachedDiv, 1); is 1
+PASS var range = new Range; range.setStart(detachedDiv, 2); range.comparePoint(detachedDiv, 1); is -1
+PASS var range = new Range; range.setStart(spanInDetachedDiv1, 0); range.comparePoint(spanInDetachedDiv2, 0); is 1
+PASS var range = new Range; range.setStart(spanInDetachedDiv2, 0); range.comparePoint(spanInDetachedDiv1, 0); is -1
+PASS var range = new Range; range.setStart(spanInDetachedDiv1, 0); range.comparePoint(spanInDetachedDiv1, 0); is 0
+PASS var range = new Range; range.setStart(detachedDiv, 0); range.comparePoint(detachedP, 0); threw exception Error: WrongDocumentError: DOM Exception 4.
+PASS var range = new Range; range.setStart(spanInDetachedDiv1, 0); range.comparePoint(spanInDetachedP, 0); threw exception Error: WrongDocumentError: DOM Exception 4.
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastdomRangerangecomparePointdetachednodeshtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/dom/Range/range-comparePoint-detached-nodes.html (0 => 189327)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/dom/Range/range-comparePoint-detached-nodes.html                                (rev 0)
+++ trunk/LayoutTests/fast/dom/Range/range-comparePoint-detached-nodes.html        2015-09-04 00:48:26 UTC (rev 189327)
</span><span class="lines">@@ -0,0 +1,33 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;script src=&quot;../../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+
+description(&quot;This test calls comparePoint on detached nodes. They should compare nodes when they're in the same detached tree and throw otherwise.&quot;)
+
+var detachedDiv = document.createElement('div');
+var spanInDetachedDiv1 = document.createElement('span');
+var spanInDetachedDiv2 = document.createElement('span');
+detachedDiv.appendChild(spanInDetachedDiv1);
+detachedDiv.appendChild(spanInDetachedDiv2);
+
+var detachedP = document.createElement('p');
+var spanInDetachedP = document.createElement('span');
+detachedP.appendChild(spanInDetachedP);
+
+shouldBe(&quot;var range = new Range; range.setStart(detachedDiv, 0); range.comparePoint(detachedDiv, 0);&quot;, &quot;0&quot;);
+shouldBe(&quot;var range = new Range; range.setStart(detachedDiv, 0); range.comparePoint(detachedDiv, 1);&quot;, &quot;1&quot;);
+shouldBe(&quot;var range = new Range; range.setStart(detachedDiv, 2); range.comparePoint(detachedDiv, 1);&quot;, &quot;-1&quot;);
+shouldBe(&quot;var range = new Range; range.setStart(spanInDetachedDiv1, 0); range.comparePoint(spanInDetachedDiv2, 0);&quot;, &quot;1&quot;);
+shouldBe(&quot;var range = new Range; range.setStart(spanInDetachedDiv2, 0); range.comparePoint(spanInDetachedDiv1, 0);&quot;, &quot;-1&quot;);
+shouldBe(&quot;var range = new Range; range.setStart(spanInDetachedDiv1, 0); range.comparePoint(spanInDetachedDiv1, 0);&quot;, &quot;0&quot;);
+shouldThrow(&quot;var range = new Range; range.setStart(detachedDiv, 0); range.comparePoint(detachedP, 0);&quot;, &quot;'Error: WrongDocumentError: DOM Exception 4'&quot;);
+shouldThrow(&quot;var range = new Range; range.setStart(spanInDetachedDiv1, 0); range.comparePoint(spanInDetachedP, 0);&quot;, &quot;'Error: WrongDocumentError: DOM Exception 4'&quot;);
+
+var successfullyParsed = true;
+
+&lt;/script&gt;
+&lt;script src=&quot;../../../resources/js-test-post.js&quot;&gt;&lt;/script&gt;
+&lt;/body&gt;
+&lt;/html&gt;
</ins></span></pre></div>
<a id="trunkLayoutTestshttptestsw3cdomrangesRangesetexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/http/tests/w3c/dom/ranges/Range-set-expected.txt (189326 => 189327)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/http/tests/w3c/dom/ranges/Range-set-expected.txt        2015-09-04 00:44:37 UTC (rev 189326)
+++ trunk/LayoutTests/http/tests/w3c/dom/ranges/Range-set-expected.txt        2015-09-04 00:48:26 UTC (rev 189327)
</span><span class="lines">@@ -581,9 +581,9 @@
</span><span class="cx"> PASS setStart() with range 6 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], point 13 [paras[1].firstChild, 9] 
</span><span class="cx"> PASS setStart() with range 6 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], point 14 [paras[1].firstChild, 10] 
</span><span class="cx"> PASS setStart() with range 6 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], point 15 [paras[1].firstChild, 65535] 
</span><del>-FAIL setStart() with range 6 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], point 16 [detachedPara1.firstChild, 0] WrongDocumentError: DOM Exception 4
-FAIL setStart() with range 6 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], point 17 [detachedPara1.firstChild, 1] WrongDocumentError: DOM Exception 4
-FAIL setStart() with range 6 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], point 18 [detachedPara1.firstChild, 8] WrongDocumentError: DOM Exception 4
</del><ins>+PASS setStart() with range 6 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], point 16 [detachedPara1.firstChild, 0] 
+PASS setStart() with range 6 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], point 17 [detachedPara1.firstChild, 1] 
+PASS setStart() with range 6 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], point 18 [detachedPara1.firstChild, 8] 
</ins><span class="cx"> PASS setStart() with range 6 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], point 19 [detachedPara1.firstChild, 9] 
</span><span class="cx"> PASS setStart() with range 6 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], point 20 [foreignPara1.firstChild, 0] 
</span><span class="cx"> PASS setStart() with range 6 [detachedPara1.firstChild, 0, detachedPara1.firstChild, 0], point 21 [foreignPara1.firstChild, 1] 
</span><span class="lines">@@ -669,9 +669,9 @@
</span><span class="cx"> PASS setStart() with range 7 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], point 13 [paras[1].firstChild, 9] 
</span><span class="cx"> PASS setStart() with range 7 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], point 14 [paras[1].firstChild, 10] 
</span><span class="cx"> PASS setStart() with range 7 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], point 15 [paras[1].firstChild, 65535] 
</span><del>-FAIL setStart() with range 7 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], point 16 [detachedPara1.firstChild, 0] WrongDocumentError: DOM Exception 4
-FAIL setStart() with range 7 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], point 17 [detachedPara1.firstChild, 1] WrongDocumentError: DOM Exception 4
-FAIL setStart() with range 7 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], point 18 [detachedPara1.firstChild, 8] WrongDocumentError: DOM Exception 4
</del><ins>+PASS setStart() with range 7 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], point 16 [detachedPara1.firstChild, 0] 
+PASS setStart() with range 7 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], point 17 [detachedPara1.firstChild, 1] 
+PASS setStart() with range 7 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], point 18 [detachedPara1.firstChild, 8] 
</ins><span class="cx"> PASS setStart() with range 7 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], point 19 [detachedPara1.firstChild, 9] 
</span><span class="cx"> PASS setStart() with range 7 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], point 20 [foreignPara1.firstChild, 0] 
</span><span class="cx"> PASS setStart() with range 7 [detachedPara1.firstChild, 2, detachedPara1.firstChild, 8], point 21 [foreignPara1.firstChild, 1] 
</span><span class="lines">@@ -1549,9 +1549,9 @@
</span><span class="cx"> PASS setStart() with range 17 [detachedPara1, 0, detachedPara1, 1], point 13 [paras[1].firstChild, 9] 
</span><span class="cx"> PASS setStart() with range 17 [detachedPara1, 0, detachedPara1, 1], point 14 [paras[1].firstChild, 10] 
</span><span class="cx"> PASS setStart() with range 17 [detachedPara1, 0, detachedPara1, 1], point 15 [paras[1].firstChild, 65535] 
</span><del>-FAIL setStart() with range 17 [detachedPara1, 0, detachedPara1, 1], point 16 [detachedPara1.firstChild, 0] WrongDocumentError: DOM Exception 4
-FAIL setStart() with range 17 [detachedPara1, 0, detachedPara1, 1], point 17 [detachedPara1.firstChild, 1] WrongDocumentError: DOM Exception 4
-FAIL setStart() with range 17 [detachedPara1, 0, detachedPara1, 1], point 18 [detachedPara1.firstChild, 8] WrongDocumentError: DOM Exception 4
</del><ins>+PASS setStart() with range 17 [detachedPara1, 0, detachedPara1, 1], point 16 [detachedPara1.firstChild, 0] 
+PASS setStart() with range 17 [detachedPara1, 0, detachedPara1, 1], point 17 [detachedPara1.firstChild, 1] 
+PASS setStart() with range 17 [detachedPara1, 0, detachedPara1, 1], point 18 [detachedPara1.firstChild, 8] 
</ins><span class="cx"> PASS setStart() with range 17 [detachedPara1, 0, detachedPara1, 1], point 19 [detachedPara1.firstChild, 9] 
</span><span class="cx"> PASS setStart() with range 17 [detachedPara1, 0, detachedPara1, 1], point 20 [foreignPara1.firstChild, 0] 
</span><span class="cx"> PASS setStart() with range 17 [detachedPara1, 0, detachedPara1, 1], point 21 [foreignPara1.firstChild, 1] 
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (189326 => 189327)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-09-04 00:44:37 UTC (rev 189326)
+++ trunk/Source/WebCore/ChangeLog        2015-09-04 00:48:26 UTC (rev 189327)
</span><span class="lines">@@ -1,3 +1,27 @@
</span><ins>+2015-09-03  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        Range.comparePoint shouldn't throw an exception if the range and the node are in the same detached tree
+        https://bugs.webkit.org/show_bug.cgi?id=148733
+
+        Reviewed by Chris Dumez.
+
+        Don't throw WRONG_DOCUMENT_ERR when refNode is not in the document. The new behavior matches DOM4 as well
+        as the behavior of Firefox. See https://dom.spec.whatwg.org/#dom-range-comparepoint
+
+        WRONG_DOCUMENT_ERR is still thrown by compareBoundaryPoints later in the function when the root nodes of
+        refNode and boundary points are different.
+
+        There is one subtlety here that we need to throw WRONG_DOCUMENT_ERR instead of INDEX_SIZE_ERR when refNode
+        and the boundary points don't share the same root node even if (refNode, offset) pair is invalid since
+        DOM4 spec checks the former condition first. We implement this behavior by first validating the offset
+        and then explicitly checking for the root node difference if the former check failed to avoid the latter
+        O(n) check in common cases.
+
+        Test: fast/dom/Range/range-comparePoint-detached-nodes.html
+
+        * dom/Range.cpp:
+        (WebCore::Range::comparePoint):
+
</ins><span class="cx"> 2015-09-03  Jer Noble  &lt;jer.noble@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [iOS] Playback does not pause when deselecting route and locking screen.
</span></span></pre></div>
<a id="trunkSourceWebCoredomRangecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Range.cpp (189326 => 189327)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Range.cpp        2015-09-04 00:44:37 UTC (rev 189326)
+++ trunk/Source/WebCore/dom/Range.cpp        2015-09-04 00:48:26 UTC (rev 189327)
</span><span class="lines">@@ -253,15 +253,20 @@
</span><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="cx"> 
</span><del>-    if (!refNode-&gt;inDocument() || &amp;refNode-&gt;document() != &amp;ownerDocument()) {
</del><ins>+    if (&amp;refNode-&gt;document() != &amp;ownerDocument()) {
</ins><span class="cx">         ec = WRONG_DOCUMENT_ERR;
</span><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="cx">     ec = 0;
</span><span class="cx">     checkNodeWOffset(refNode, offset, ec);
</span><del>-    if (ec)
</del><ins>+    if (ec) {
+        // DOM4 spec requires us to check whether refNode and start container have the same root first
+        // but we do it in the reverse order to avoid O(n) operation here in common case.
+        if (!refNode-&gt;inDocument() &amp;&amp; !commonAncestorContainer(refNode, &amp;startContainer()))
+            ec = WRONG_DOCUMENT_ERR;
</ins><span class="cx">         return 0;
</span><ins>+    }
</ins><span class="cx"> 
</span><span class="cx">     // compare to start, and point comes before
</span><span class="cx">     if (compareBoundaryPoints(refNode, offset, &amp;startContainer(), m_start.offset(), ec) &lt; 0)
</span></span></pre>
</div>
</div>

</body>
</html>