<!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>[181465] 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/181465">181465</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2015-03-12 17:57:10 -0700 (Thu, 12 Mar 2015)</dd>
</dl>

<h3>Log Message</h3>
<pre>REGRESSION(<a href="http://trac.webkit.org/projects/webkit/changeset/180726">r180726</a>): Removing an empty line at the end of textarea clears the entire texture
https://bugs.webkit.org/show_bug.cgi?id=142646

Reviewed by Darin Adler.

Source/WebCore:

The bug was caused by TypingCommand::deleteKeyPressed erroneously determining the editable root to be empty because
Position::atStartOfTree returns true when it's anchored at a BR that is immediately below the root editable element.

Fixed the bug by replacing the use of the deprecated atFirstEditingPositionForNode by a code that understands modern
position types such as PositionIsBeforeAnchor in atStartOfTree and atEndOfTree. These two functions will no longer
return true when anchored before or after BR after this patch.

Test: editing/deleting/delete-empty-line-breaks-at-end-of-textarea.html

* dom/Position.cpp:
(WebCore::Position::atStartOfTree):
(WebCore::Position::atEndOfTree):

LayoutTests:

Added a regression test for deleting empty lines at the end of a textarea element.

* editing/deleting/delete-empty-line-breaks-at-end-of-textarea-expected.txt: Added.
* editing/deleting/delete-empty-line-breaks-at-end-of-textarea.html: Added.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkLayoutTestsChangeLog">trunk/LayoutTests/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCoredomPositioncpp">trunk/Source/WebCore/dom/Position.cpp</a></li>
</ul>

<h3>Added Paths</h3>
<ul>
<li><a href="#trunkLayoutTestseditingdeletingdeleteemptylinebreaksatendoftextareaexpectedtxt">trunk/LayoutTests/editing/deleting/delete-empty-line-breaks-at-end-of-textarea-expected.txt</a></li>
<li><a href="#trunkLayoutTestseditingdeletingdeleteemptylinebreaksatendoftextareahtml">trunk/LayoutTests/editing/deleting/delete-empty-line-breaks-at-end-of-textarea.html</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkLayoutTestsChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/LayoutTests/ChangeLog (181464 => 181465)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/ChangeLog        2015-03-13 00:55:09 UTC (rev 181464)
+++ trunk/LayoutTests/ChangeLog        2015-03-13 00:57:10 UTC (rev 181465)
</span><span class="lines">@@ -1,3 +1,15 @@
</span><ins>+2015-03-12  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        REGRESSION(r180726): Removing an empty line at the end of textarea clears the entire texture
+        https://bugs.webkit.org/show_bug.cgi?id=142646
+
+        Reviewed by Darin Adler.
+
+        Added a regression test for deleting empty lines at the end of a textarea element.
+
+        * editing/deleting/delete-empty-line-breaks-at-end-of-textarea-expected.txt: Added.
+        * editing/deleting/delete-empty-line-breaks-at-end-of-textarea.html: Added.
+
</ins><span class="cx"> 2015-03-12  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Integrate MapData into JSMap and JSSet
</span></span></pre></div>
<a id="trunkLayoutTestseditingdeletingdeleteemptylinebreaksatendoftextareaexpectedtxt"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/editing/deleting/delete-empty-line-breaks-at-end-of-textarea-expected.txt (0 => 181465)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/deleting/delete-empty-line-breaks-at-end-of-textarea-expected.txt                                (rev 0)
+++ trunk/LayoutTests/editing/deleting/delete-empty-line-breaks-at-end-of-textarea-expected.txt        2015-03-13 00:57:10 UTC (rev 181465)
</span><span class="lines">@@ -0,0 +1,20 @@
</span><ins>+This tests removing empty lines at the end of an textarea.
+
+On success, you will see a series of &quot;PASS&quot; messages, followed by &quot;TEST COMPLETE&quot;.
+
+
+textarea.focus();
+textarea.selectionStart = textarea.selectionEnd = textarea.value.length
+PASS textarea.value is &quot;hello\n\n&quot;
+PASS textarea.selectionStart is 7
+PASS textarea.selectionEnd is 7
+PASS document.execCommand(&quot;delete&quot;, false, null); textarea.value is &quot;hello\n&quot;
+PASS textarea.selectionStart is 6
+PASS textarea.selectionEnd is 6
+PASS document.execCommand(&quot;delete&quot;, false, null); textarea.value is &quot;hello&quot;
+PASS textarea.selectionStart is 5
+PASS textarea.selectionEnd is 5
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
</ins></span></pre></div>
<a id="trunkLayoutTestseditingdeletingdeleteemptylinebreaksatendoftextareahtml"></a>
<div class="addfile"><h4>Added: trunk/LayoutTests/editing/deleting/delete-empty-line-breaks-at-end-of-textarea.html (0 => 181465)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/LayoutTests/editing/deleting/delete-empty-line-breaks-at-end-of-textarea.html                                (rev 0)
+++ trunk/LayoutTests/editing/deleting/delete-empty-line-breaks-at-end-of-textarea.html        2015-03-13 00:57:10 UTC (rev 181465)
</span><span class="lines">@@ -0,0 +1,35 @@
</span><ins>+&lt;!DOCTYPE html&gt;
+&lt;html&gt;
+&lt;body&gt;
+&lt;textarea cols=5 rows=5&gt;
+hello
+
+&lt;/textarea&gt;
+&lt;script src=&quot;../../resources/js-test-pre.js&quot;&gt;&lt;/script&gt;
+&lt;script&gt;
+
+description('This tests removing empty lines at the end of an textarea.');
+
+var textarea = document.querySelector('textarea');
+evalAndLog('textarea.focus();');
+evalAndLog('textarea.selectionStart = textarea.selectionEnd = textarea.value.length');
+shouldBe('textarea.value' ,'&quot;hello\\n\\n&quot;');
+shouldBe('textarea.selectionStart' ,'7');
+shouldBe('textarea.selectionEnd' ,'7');
+
+shouldBe('document.execCommand(&quot;delete&quot;, false, null); textarea.value', '&quot;hello\\n&quot;');
+shouldBe('textarea.selectionStart', '6');
+shouldBe('textarea.selectionEnd', '6');
+
+shouldBe('document.execCommand(&quot;delete&quot;, false, null); textarea.value', '&quot;hello&quot;');
+shouldBe('textarea.selectionStart', '5');
+shouldBe('textarea.selectionEnd', '5');
+
+textarea.style.display = 'none';
+
+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="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (181464 => 181465)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2015-03-13 00:55:09 UTC (rev 181464)
+++ trunk/Source/WebCore/ChangeLog        2015-03-13 00:57:10 UTC (rev 181465)
</span><span class="lines">@@ -1,3 +1,23 @@
</span><ins>+2015-03-12  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        REGRESSION(r180726): Removing an empty line at the end of textarea clears the entire texture
+        https://bugs.webkit.org/show_bug.cgi?id=142646
+
+        Reviewed by Darin Adler.
+
+        The bug was caused by TypingCommand::deleteKeyPressed erroneously determining the editable root to be empty because
+        Position::atStartOfTree returns true when it's anchored at a BR that is immediately below the root editable element.
+
+        Fixed the bug by replacing the use of the deprecated atFirstEditingPositionForNode by a code that understands modern
+        position types such as PositionIsBeforeAnchor in atStartOfTree and atEndOfTree. These two functions will no longer
+        return true when anchored before or after BR after this patch.
+
+        Test: editing/deleting/delete-empty-line-breaks-at-end-of-textarea.html
+
+        * dom/Position.cpp:
+        (WebCore::Position::atStartOfTree):
+        (WebCore::Position::atEndOfTree):
+
</ins><span class="cx"> 2015-03-12  Yusuke Suzuki  &lt;utatane.tea@gmail.com&gt;
</span><span class="cx"> 
</span><span class="cx">         Integrate MapData into JSMap and JSSet
</span></span></pre></div>
<a id="trunkSourceWebCoredomPositioncpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/dom/Position.cpp (181464 => 181465)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/dom/Position.cpp        2015-03-13 00:55:09 UTC (rev 181464)
+++ trunk/Source/WebCore/dom/Position.cpp        2015-03-13 00:57:10 UTC (rev 181465)
</span><span class="lines">@@ -476,14 +476,46 @@
</span><span class="cx"> {
</span><span class="cx">     if (isNull())
</span><span class="cx">         return true;
</span><del>-    return !findParent(containerNode()) &amp;&amp; atFirstEditingPositionForNode();
</del><ins>+    if (findParent(containerNode()))
+        return false;
+
+    switch (m_anchorType) {
+    case PositionIsOffsetInAnchor:
+        return m_offset &lt;= 0;
+    case PositionIsBeforeAnchor:
+        return !m_anchorNode-&gt;previousSibling();
+    case PositionIsAfterAnchor:
+        return false;
+    case PositionIsBeforeChildren:
+        return true;
+    case PositionIsAfterChildren:
+        return !lastOffsetForEditing(m_anchorNode.get());
+    }
+    ASSERT_NOT_REACHED();
+    return false;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> bool Position::atEndOfTree() const
</span><span class="cx"> {
</span><span class="cx">     if (isNull())
</span><span class="cx">         return true;
</span><del>-    return !findParent(containerNode()) &amp;&amp; atLastEditingPositionForNode();
</del><ins>+    if (findParent(containerNode()))
+        return false;
+
+    switch (m_anchorType) {
+    case PositionIsOffsetInAnchor:
+        return m_offset &gt;= lastOffsetForEditing(m_anchorNode.get());
+    case PositionIsBeforeAnchor:
+        return false;
+    case PositionIsAfterAnchor:
+        return !m_anchorNode-&gt;nextSibling();
+    case PositionIsBeforeChildren:
+        return !lastOffsetForEditing(m_anchorNode.get());
+    case PositionIsAfterChildren:
+        return true;
+    }
+    ASSERT_NOT_REACHED();
+    return false;
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> // return first preceding DOM position rendered at a different location, or &quot;this&quot;
</span></span></pre>
</div>
</div>

</body>
</html>