<!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>[204368] 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/204368">204368</a></dd>
<dt>Author</dt> <dd>cdumez@apple.com</dd>
<dt>Date</dt> <dd>2016-08-10 19:21:42 -0700 (Wed, 10 Aug 2016)</dd>
</dl>

<h3>Log Message</h3>
<pre>Optimization in Node.insertBefore() is not spec-compliant
https://bugs.webkit.org/show_bug.cgi?id=160746

Reviewed by Ryosuke Niwa.

LayoutTests/imported/w3c:

Rebaseline W3C test now that more checks are passing.

* web-platform-tests/dom/ranges/Range-mutations-expected.txt:

Source/WebCore:

We have an optimization in Node.insertBefore(newNode, refChild) to avoid
doing any work when newNode == refChild or newNode.nextSibling == refChild.

This optimization is not in the specification:
- https://dom.spec.whatwg.org/#concept-node-replace

The issue is that this optimization is observable with DOM mutation
observers / listeners or DOM ranges.

This patch addresses the issue by dropping the optimization. This case
does not seem common enough to be worth optimizing for. However, if it
turns out to regress the performance of things we care about, we could
fallback to doing the optimization only when it is not observable.

Test: fast/dom/Node/insertBefore-no-op-mutationobserver.html

* dom/ContainerNode.cpp:
(WebCore::checkAcceptChild):
Move refChild-&gt;parent() == parent check from insertBefore() to our
pre-insertion check function, right after checking if newNode contains
parent. This was done in order to match more closely the specification
and to make sure that exception are thrown in the correct order:
- https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity (steps 2 and 3)

(WebCore::ContainerNode::insertBefore):
1. Drop the (refChild-&gt;previousSibling() == &amp;newChild || refChild == &amp;newChild)
   optimization as it is not spc-compliant.
2. If refChild is newNode, then set refChild to newChild.nextSibling as per:
   - https://dom.spec.whatwg.org/#concept-node-pre-insert (step 3)

LayoutTests:

Add layout test to make sure mutation observers / listeners are always
notified when Node.insertBefore() is called.

* fast/dom/Node/insertBefore-no-op-mutationobserver-expected.txt: Added.
* fast/dom/Node/insertBefore-no-op-mutationobserver.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsimportedw3cChangeLog">trunk/LayoutTests/imported/w3c/ChangeLog</a></li>
<li><a href="#trunkLayoutTestsimportedw3cwebplatformtestsdomrangesRangemutationsexpectedtxt">trunk/LayoutTests/imported/w3c/web-platform-tests/dom/ranges/Range-mutations-expected.txt</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoredomContainerNodecpp">trunk/Source/WebCore/dom/ContainerNode.cpp</a></li>
<li><a href="#trunkSourceWebCoredomContainerNodeh">trunk/Source/WebCore/dom/ContainerNode.h</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsfastdomNodeinsertBeforenoopmutationobserverexpectedtxt">trunk/LayoutTests/fast/dom/Node/insertBefore-no-op-mutationobserver-expected.txt</a></li>
<li><a href="#trunkLayoutTestsfastdomNodeinsertBeforenoopmutationobserverhtml">trunk/LayoutTests/fast/dom/Node/insertBefore-no-op-mutationobserver.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (204367 => 204368)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2016-08-11 02:08:17 UTC (rev 204367)
+++ trunk/LayoutTests/ChangeLog        2016-08-11 02:21:42 UTC (rev 204368)
</span><span class="lines">@@ -1,3 +1,16 @@
</span><ins>+2016-08-10  Chris Dumez  &lt;cdumez@apple.com&gt;
+
+        Optimization in Node.insertBefore() is not spec-compliant
+        https://bugs.webkit.org/show_bug.cgi?id=160746
+
+        Reviewed by Ryosuke Niwa.
+
+        Add layout test to make sure mutation observers / listeners are always
+        notified when Node.insertBefore() is called.
+
+        * fast/dom/Node/insertBefore-no-op-mutationobserver-expected.txt: Added.
+        * fast/dom/Node/insertBefore-no-op-mutationobserver.html: Added.
+
</ins><span class="cx"> 2016-08-10  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Move document.defineElement to customElements.define
</span></span></pre></div>
<a id="trunkLayoutTestsfastdomNodeinsertBeforenoopmutationobserverexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/dom/Node/insertBefore-no-op-mutationobserver-expected.txt (0 => 204368)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/dom/Node/insertBefore-no-op-mutationobserver-expected.txt                                (rev 0)
+++ trunk/LayoutTests/fast/dom/Node/insertBefore-no-op-mutationobserver-expected.txt        2016-08-11 02:21:42 UTC (rev 204368)
</span><span class="lines">@@ -0,0 +1,13 @@
</span><ins>+Tests that calls of insertBefore() lead to mutation events even if they are no-ops.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+PASS Mutation observer was notified
+PASS wasMutationEventListenerCalled is true
+PASS Mutation observer was notified
+PASS wasMutationEventListenerCalled is true
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestsfastdomNodeinsertBeforenoopmutationobserverhtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/fast/dom/Node/insertBefore-no-op-mutationobserver.html (0 => 204368)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/fast/dom/Node/insertBefore-no-op-mutationobserver.html                                (rev 0)
+++ trunk/LayoutTests/fast/dom/Node/insertBefore-no-op-mutationobserver.html        2016-08-11 02:21:42 UTC (rev 204368)
</span><span class="lines">@@ -0,0 +1,57 @@
</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;div id=&quot;testDiv&quot;&gt;&lt;p&gt;&lt;/p&gt;&lt;p&gt;&lt;/p&gt;&lt;/div&gt;
+&lt;script&gt;
+description(&quot;Tests that calls of insertBefore() lead to mutation events even if they are no-ops.&quot;);
+jsTestIsAsync = true;
+
+var testDiv = document.getElementById(&quot;testDiv&quot;);
+var p1 = testDiv.firstChild;
+var p2 = testDiv.lastChild;
+
+var operations = [
+    function() { testDiv.insertBefore(p1, p1); },
+    function() { testDiv.insertBefore(p1, p2); }
+];
+var currentOperation = 0;
+
+function testMutationObserver()
+{
+    var config = { childList: true };
+    var observer = new MutationObserver(function(mutations) {
+        testPassed(&quot;Mutation observer was notified&quot;);
+        observer.disconnect();
+        testMutationEventListener();
+    });
+
+    observer.observe(testDiv, config);
+    operations[currentOperation]();
+}
+
+function subtreeModifiedHandler()
+{
+    wasMutationEventListenerCalled = true;
+}
+
+function testMutationEventListener()
+{
+    wasMutationEventListenerCalled = false;
+    testDiv.addEventListener(&quot;DOMSubtreeModified&quot;, subtreeModifiedHandler);
+    operations[currentOperation]();
+    shouldBeTrue(&quot;wasMutationEventListenerCalled&quot;);
+    testDiv.removeEventListener(&quot;DOMSubtreeModified&quot;, subtreeModifiedHandler);
+
+    currentOperation++;
+    if (currentOperation &lt; operations.length)
+        testMutationObserver();
+    else
+        finishJSTest();
+}
+
+testMutationObserver();
+&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="trunkLayoutTestsimportedw3cChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/imported/w3c/ChangeLog (204367 => 204368)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/imported/w3c/ChangeLog        2016-08-11 02:08:17 UTC (rev 204367)
+++ trunk/LayoutTests/imported/w3c/ChangeLog        2016-08-11 02:21:42 UTC (rev 204368)
</span><span class="lines">@@ -1,3 +1,14 @@
</span><ins>+2016-08-10  Chris Dumez  &lt;cdumez@apple.com&gt;
+
+        Optimization in Node.insertBefore() is not spec-compliant
+        https://bugs.webkit.org/show_bug.cgi?id=160746
+
+        Reviewed by Ryosuke Niwa.
+
+        Rebaseline W3C test now that more checks are passing.
+
+        * web-platform-tests/dom/ranges/Range-mutations-expected.txt:
+
</ins><span class="cx"> 2016-08-09  Chris Dumez  &lt;cdumez@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Optimization in Node.replaceChild() is not spec-compliant
</span></span></pre></div>
<a id="trunkLayoutTestsimportedw3cwebplatformtestsdomrangesRangemutationsexpectedtxt"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/imported/w3c/web-platform-tests/dom/ranges/Range-mutations-expected.txt (204367 => 204368)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/imported/w3c/web-platform-tests/dom/ranges/Range-mutations-expected.txt        2016-08-11 02:08:17 UTC (rev 204367)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/dom/ranges/Range-mutations-expected.txt        2016-08-11 02:21:42 UTC (rev 204368)
</span><span class="lines">@@ -5507,18 +5507,12 @@
</span><span class="cx"> FAIL detachedXmlComment.nodeValue += &quot;foo&quot;, with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) assert_equals: Sanity check: selection must have exactly one range after adding the range expected 1 but got 0
</span><span class="cx"> PASS detachedXmlComment.nodeValue += detachedXmlComment.nodeValue, with unselected range collapsed at (detachedXmlComment, detachedXmlComment.length) 
</span><span class="cx"> FAIL detachedXmlComment.nodeValue += detachedXmlComment.nodeValue, with selected range collapsed at (detachedXmlComment, detachedXmlComment.length) assert_equals: Sanity check: selection must have exactly one range after adding the range expected 1 but got 0
</span><del>-FAIL testDiv.insertBefore(paras[0], paras[1]), with unselected range collapsed at (paras[0], 0) assert_equals: Wrong start container expected Element node &lt;div id=&quot;test&quot;&gt;&lt;p id=&quot;a&quot;&gt;Äb̈c̈d̈ëf̈g̈ḧ
-&lt;/p&gt;&lt;p id=&quot;b&quot; s... but got Element node &lt;p id=&quot;a&quot;&gt;Äb̈c̈d̈ëf̈g̈ḧ
-&lt;/p&gt;
</del><ins>+PASS testDiv.insertBefore(paras[0], paras[1]), with unselected range collapsed at (paras[0], 0) 
</ins><span class="cx"> FAIL testDiv.insertBefore(paras[0], paras[1]), with selected range collapsed at (paras[0], 0) assert_equals: Sanity check: selection's range must initially be the same as the range we added expected object &quot;&quot; but got object &quot;&quot;
</span><del>-FAIL testDiv.insertBefore(paras[0], paras[1]), with unselected range on paras[0] from 0 to 1 assert_equals: Wrong start container expected Element node &lt;div id=&quot;test&quot;&gt;&lt;p id=&quot;a&quot;&gt;Äb̈c̈d̈ëf̈g̈ḧ
-&lt;/p&gt;&lt;p id=&quot;b&quot; s... but got Element node &lt;p id=&quot;a&quot;&gt;Äb̈c̈d̈ëf̈g̈ḧ
-&lt;/p&gt;
</del><ins>+PASS testDiv.insertBefore(paras[0], paras[1]), with unselected range on paras[0] from 0 to 1 
</ins><span class="cx"> FAIL testDiv.insertBefore(paras[0], paras[1]), with selected range on paras[0] from 0 to 1 assert_equals: Sanity check: selection's range must initially be the same as the range we added expected object &quot;Äb̈c̈d̈ëf̈g̈ḧ
</span><span class="cx"> &quot; but got object &quot;Äb̈c̈d̈ëf̈g̈ḧ&quot;
</span><del>-FAIL testDiv.insertBefore(paras[0], paras[1]), with unselected range collapsed at (paras[0], 1) assert_equals: Wrong start container expected Element node &lt;div id=&quot;test&quot;&gt;&lt;p id=&quot;a&quot;&gt;Äb̈c̈d̈ëf̈g̈ḧ
-&lt;/p&gt;&lt;p id=&quot;b&quot; s... but got Element node &lt;p id=&quot;a&quot;&gt;Äb̈c̈d̈ëf̈g̈ḧ
-&lt;/p&gt;
</del><ins>+PASS testDiv.insertBefore(paras[0], paras[1]), with unselected range collapsed at (paras[0], 1) 
</ins><span class="cx"> FAIL testDiv.insertBefore(paras[0], paras[1]), with selected range collapsed at (paras[0], 1) assert_equals: Sanity check: selection's range must initially be the same as the range we added expected object &quot;&quot; but got object &quot;&quot;
</span><span class="cx"> PASS testDiv.insertBefore(paras[0], paras[1]), with unselected range on testDiv from 0 to 2 
</span><span class="cx"> FAIL testDiv.insertBefore(paras[0], paras[1]), with selected range on testDiv from 0 to 2 assert_equals: Sanity check: selection's range must initially be the same as the range we added expected object &quot;Äb̈c̈d̈ëf̈g̈ḧ
</span><span class="lines">@@ -5526,9 +5520,9 @@
</span><span class="cx"> &quot; but got object &quot;Äb̈c̈d̈ëf̈g̈ḧ
</span><span class="cx"> Ijklmnop
</span><span class="cx"> &quot;
</span><del>-FAIL testDiv.insertBefore(paras[0], paras[1]), with unselected range collapsed at (testDiv, 1) assert_equals: Wrong start offset expected 0 but got 1
</del><ins>+PASS testDiv.insertBefore(paras[0], paras[1]), with unselected range collapsed at (testDiv, 1) 
</ins><span class="cx"> FAIL testDiv.insertBefore(paras[0], paras[1]), with selected range collapsed at (testDiv, 1) assert_equals: Sanity check: selection's range must initially be the same as the range we added expected object &quot;&quot; but got object &quot;&quot;
</span><del>-FAIL testDiv.insertBefore(paras[0], paras[1]), with unselected range on testDiv from 1 to 2 assert_equals: Wrong start offset expected 0 but got 1
</del><ins>+PASS testDiv.insertBefore(paras[0], paras[1]), with unselected range on testDiv from 1 to 2 
</ins><span class="cx"> FAIL testDiv.insertBefore(paras[0], paras[1]), with selected range on testDiv from 1 to 2 assert_equals: Sanity check: selection's range must initially be the same as the range we added expected object &quot;Ijklmnop
</span><span class="cx"> &quot; but got object &quot;&quot;
</span><span class="cx"> PASS testDiv.insertBefore(paras[0], paras[1]), with unselected range collapsed at (testDiv, 2) 
</span></span></pre></div>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (204367 => 204368)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2016-08-11 02:08:17 UTC (rev 204367)
+++ trunk/Source/WebCore/ChangeLog        2016-08-11 02:21:42 UTC (rev 204368)
</span><span class="lines">@@ -1,3 +1,40 @@
</span><ins>+2016-08-10  Chris Dumez  &lt;cdumez@apple.com&gt;
+
+        Optimization in Node.insertBefore() is not spec-compliant
+        https://bugs.webkit.org/show_bug.cgi?id=160746
+
+        Reviewed by Ryosuke Niwa.
+
+        We have an optimization in Node.insertBefore(newNode, refChild) to avoid
+        doing any work when newNode == refChild or newNode.nextSibling == refChild.
+
+        This optimization is not in the specification:
+        - https://dom.spec.whatwg.org/#concept-node-replace
+
+        The issue is that this optimization is observable with DOM mutation
+        observers / listeners or DOM ranges.
+
+        This patch addresses the issue by dropping the optimization. This case
+        does not seem common enough to be worth optimizing for. However, if it
+        turns out to regress the performance of things we care about, we could
+        fallback to doing the optimization only when it is not observable.
+
+        Test: fast/dom/Node/insertBefore-no-op-mutationobserver.html
+
+        * dom/ContainerNode.cpp:
+        (WebCore::checkAcceptChild):
+        Move refChild-&gt;parent() == parent check from insertBefore() to our
+        pre-insertion check function, right after checking if newNode contains
+        parent. This was done in order to match more closely the specification
+        and to make sure that exception are thrown in the correct order:
+        - https://dom.spec.whatwg.org/#concept-node-ensure-pre-insertion-validity (steps 2 and 3)
+
+        (WebCore::ContainerNode::insertBefore):
+        1. Drop the (refChild-&gt;previousSibling() == &amp;newChild || refChild == &amp;newChild)
+           optimization as it is not spc-compliant.
+        2. If refChild is newNode, then set refChild to newChild.nextSibling as per:
+           - https://dom.spec.whatwg.org/#concept-node-pre-insert (step 3)
+
</ins><span class="cx"> 2016-08-10  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
</span><span class="cx"> 
</span><span class="cx">         Move document.defineElement to customElements.define
</span></span></pre></div>
<a id="trunkSourceWebCoredomContainerNodecpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/ContainerNode.cpp (204367 => 204368)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/ContainerNode.cpp        2016-08-11 02:08:17 UTC (rev 204367)
+++ trunk/Source/WebCore/dom/ContainerNode.cpp        2016-08-11 02:21:42 UTC (rev 204368)
</span><span class="lines">@@ -183,6 +183,8 @@
</span><span class="cx">         ASSERT(isChildTypeAllowed(newParent, newChild));
</span><span class="cx">         if (containsConsideringHostElements(newChild, newParent))
</span><span class="cx">             return HIERARCHY_REQUEST_ERR;
</span><ins>+        if (operation == Document::AcceptChildOperation::InsertOrAdd &amp;&amp; refChild &amp;&amp; refChild-&gt;parentNode() != &amp;newParent)
+            return NOT_FOUND_ERR;
</ins><span class="cx">         return 0;
</span><span class="cx">     }
</span><span class="cx"> 
</span><span class="lines">@@ -194,6 +196,9 @@
</span><span class="cx">     if (containsConsideringHostElements(newChild, newParent))
</span><span class="cx">         return HIERARCHY_REQUEST_ERR;
</span><span class="cx"> 
</span><ins>+    if (operation == Document::AcceptChildOperation::InsertOrAdd &amp;&amp; refChild &amp;&amp; refChild-&gt;parentNode() != &amp;newParent)
+        return NOT_FOUND_ERR;
+
</ins><span class="cx">     if (is&lt;Document&gt;(newParent)) {
</span><span class="cx">         if (!downcast&lt;Document&gt;(newParent).canAcceptChild(newChild, refChild, operation))
</span><span class="cx">             return HIERARCHY_REQUEST_ERR;
</span><span class="lines">@@ -235,27 +240,20 @@
</span><span class="cx">     // If it is, it can be deleted as a side effect of sending mutation events.
</span><span class="cx">     ASSERT(refCount() || parentOrShadowHostNode());
</span><span class="cx"> 
</span><del>-    Ref&lt;ContainerNode&gt; protectedThis(*this);
-
</del><span class="cx">     ec = 0;
</span><span class="cx"> 
</span><del>-    // insertBefore(node, 0) is equivalent to appendChild(node)
-    if (!refChild)
-        return appendChild(newChild, ec);
-
</del><span class="cx">     // Make sure adding the new child is OK.
</span><span class="cx">     if (!ensurePreInsertionValidity(newChild, refChild, ec))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><del>-    // NOT_FOUND_ERR: Raised if refChild is not a child of this node
-    if (refChild-&gt;parentNode() != this) {
-        ec = NOT_FOUND_ERR;
-        return false;
-    }
</del><ins>+    if (refChild == &amp;newChild)
+        refChild = newChild.nextSibling();
</ins><span class="cx"> 
</span><del>-    if (refChild-&gt;previousSibling() == &amp;newChild || refChild == &amp;newChild) // nothing to do
-        return true;
</del><ins>+    // insertBefore(node, null) is equivalent to appendChild(node)
+    if (!refChild)
+        return appendChildWithoutPreInsertionValidityCheck(newChild, ec);
</ins><span class="cx"> 
</span><ins>+    Ref&lt;ContainerNode&gt; protectedThis(*this);
</ins><span class="cx">     Ref&lt;Node&gt; next(*refChild);
</span><span class="cx"> 
</span><span class="cx">     NodeVector targets;
</span><span class="lines">@@ -640,8 +638,6 @@
</span><span class="cx"> 
</span><span class="cx"> bool ContainerNode::appendChild(Node&amp; newChild, ExceptionCode&amp; ec)
</span><span class="cx"> {
</span><del>-    Ref&lt;ContainerNode&gt; protectedThis(*this);
-
</del><span class="cx">     // Check that this node is not &quot;floating&quot;.
</span><span class="cx">     // If it is, it can be deleted as a side effect of sending mutation events.
</span><span class="cx">     ASSERT(refCount() || parentOrShadowHostNode());
</span><span class="lines">@@ -652,6 +648,13 @@
</span><span class="cx">     if (!ensurePreInsertionValidity(newChild, nullptr, ec))
</span><span class="cx">         return false;
</span><span class="cx"> 
</span><ins>+    return appendChildWithoutPreInsertionValidityCheck(newChild, ec);
+}
+
+bool ContainerNode::appendChildWithoutPreInsertionValidityCheck(Node&amp; newChild, ExceptionCode&amp; ec)
+{
+    Ref&lt;ContainerNode&gt; protectedThis(*this);
+
</ins><span class="cx">     NodeVector targets;
</span><span class="cx">     collectChildrenAndRemoveFromOldParent(newChild, targets, ec);
</span><span class="cx">     if (ec)
</span></span></pre></div>
<a id="trunkSourceWebCoredomContainerNodeh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/ContainerNode.h (204367 => 204368)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/ContainerNode.h        2016-08-11 02:08:17 UTC (rev 204367)
+++ trunk/Source/WebCore/dom/ContainerNode.h        2016-08-11 02:21:42 UTC (rev 204368)
</span><span class="lines">@@ -117,6 +117,7 @@
</span><span class="cx"> 
</span><span class="cx"> private:
</span><span class="cx">     void removeBetween(Node* previousChild, Node* nextChild, Node&amp; oldChild);
</span><ins>+    bool appendChildWithoutPreInsertionValidityCheck(Node&amp;, ExceptionCode&amp;);
</ins><span class="cx">     void insertBeforeCommon(Node&amp; nextChild, Node&amp; oldChild);
</span><span class="cx">     void appendChildCommon(Node&amp;);
</span><span class="cx"> 
</span></span></pre>
</div>
</div>

</body>
</html>