<!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>[164180] trunk/Source/WebCore</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/164180">164180</a></dd>
<dt>Author</dt> <dd>rniwa@webkit.org</dd>
<dt>Date</dt> <dd>2014-02-15 14:32:05 -0800 (Sat, 15 Feb 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>computeSelectionStart and computeSelectionEnd shouldn't trigger synchronous layout
https://bugs.webkit.org/show_bug.cgi?id=128806

Reviewed by Darin Adler.

Added indexForPosition to HTMLTextFormControlElement. Like <a href="http://trac.webkit.org/projects/webkit/changeset/163825">r163825</a>, this patch traverses the DOM tree
instead of the render tree to compute the index for a given position.

We traverse the DOM Tree backwards starting at the specified Position all the way back to the beginning
of the inner text element. The index is computed as the number of characters we encountered during
this backwards DOM traversal.

It's worth noting that passedPosition.computeNodeBeforePosition() returns and only returns 0 when the
position is before the first node of its parent or inside a text node. In such cases, we call
passedPosition.containerNode() to find the parent or the text node.

* html/HTMLTextFormControlElement.cpp:
(WebCore::HTMLTextFormControlElement::indexForVisiblePosition): Use indexForPosition.
(WebCore::HTMLTextFormControlElement::computeSelectionStart): Ditto.
(WebCore::HTMLTextFormControlElement::computeSelectionEnd): Dotto.
(WebCore::finishText): Cleanup. Use newlineCharacter instead of hard-coding '\n'.
(WebCore::HTMLTextFormControlElement::indexForPosition): Added. See above for the description.
* html/HTMLTextFormControlElement.h:</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkSourceWebCoreChangeLog">trunk/Source/WebCore/ChangeLog</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLTextFormControlElementcpp">trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp</a></li>
<li><a href="#trunkSourceWebCorehtmlHTMLTextFormControlElementh">trunk/Source/WebCore/html/HTMLTextFormControlElement.h</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkSourceWebCoreChangeLog"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/ChangeLog (164179 => 164180)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/ChangeLog        2014-02-15 21:15:49 UTC (rev 164179)
+++ trunk/Source/WebCore/ChangeLog        2014-02-15 22:32:05 UTC (rev 164180)
</span><span class="lines">@@ -1,3 +1,29 @@
</span><ins>+2014-02-15  Ryosuke Niwa  &lt;rniwa@webkit.org&gt;
+
+        computeSelectionStart and computeSelectionEnd shouldn't trigger synchronous layout
+        https://bugs.webkit.org/show_bug.cgi?id=128806
+
+        Reviewed by Darin Adler.
+
+        Added indexForPosition to HTMLTextFormControlElement. Like r163825, this patch traverses the DOM tree
+        instead of the render tree to compute the index for a given position.
+
+        We traverse the DOM Tree backwards starting at the specified Position all the way back to the beginning
+        of the inner text element. The index is computed as the number of characters we encountered during
+        this backwards DOM traversal.
+
+        It's worth noting that passedPosition.computeNodeBeforePosition() returns and only returns 0 when the
+        position is before the first node of its parent or inside a text node. In such cases, we call
+        passedPosition.containerNode() to find the parent or the text node.
+
+        * html/HTMLTextFormControlElement.cpp:
+        (WebCore::HTMLTextFormControlElement::indexForVisiblePosition): Use indexForPosition.
+        (WebCore::HTMLTextFormControlElement::computeSelectionStart): Ditto.
+        (WebCore::HTMLTextFormControlElement::computeSelectionEnd): Dotto.
+        (WebCore::finishText): Cleanup. Use newlineCharacter instead of hard-coding '\n'.
+        (WebCore::HTMLTextFormControlElement::indexForPosition): Added. See above for the description.
+        * html/HTMLTextFormControlElement.h:
+
</ins><span class="cx"> 2014-02-15  Brent Fulgham  &lt;bfulgham@apple.com&gt;
</span><span class="cx"> 
</span><span class="cx">         [Win] Avoid unnecessary asserts if &quot;prepareToPlay&quot; is called multiple times.
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLTextFormControlElementcpp"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp (164179 => 164180)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp        2014-02-15 21:15:49 UTC (rev 164179)
+++ trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp        2014-02-15 22:32:05 UTC (rev 164180)
</span><span class="lines">@@ -330,8 +330,7 @@
</span><span class="cx">     TextControlInnerTextElement* innerText = innerTextElement();
</span><span class="cx">     if (!innerText || !innerText-&gt;contains(position.deepEquivalent().anchorNode()))
</span><span class="cx">         return 0;
</span><del>-    bool forSelectionPreservation = false;
-    unsigned index = WebCore::indexForVisiblePosition(innerTextElement(), position, forSelectionPreservation);
</del><ins>+    unsigned index = indexForPosition(position.deepEquivalent());
</ins><span class="cx">     ASSERT(VisiblePosition(positionForIndex(innerTextElement(), index)) == position);
</span><span class="cx">     return index;
</span><span class="cx"> }
</span><span class="lines">@@ -360,7 +359,7 @@
</span><span class="cx">     if (!frame)
</span><span class="cx">         return 0;
</span><span class="cx"> 
</span><del>-    return indexForVisiblePosition(frame-&gt;selection().selection().start());
</del><ins>+    return indexForPosition(frame-&gt;selection().selection().start());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> int HTMLTextFormControlElement::selectionEnd() const
</span><span class="lines">@@ -379,7 +378,7 @@
</span><span class="cx">     if (!frame)
</span><span class="cx">         return 0;
</span><span class="cx"> 
</span><del>-    return indexForVisiblePosition(frame-&gt;selection().selection().end());
</del><ins>+    return indexForPosition(frame-&gt;selection().selection().end());
</ins><span class="cx"> }
</span><span class="cx"> 
</span><span class="cx"> static const AtomicString&amp; directionString(TextFieldSelectionDirection direction)
</span><span class="lines">@@ -537,7 +536,7 @@
</span><span class="cx"> {
</span><span class="cx">     // Remove one trailing newline; there's always one that's collapsed out by rendering.
</span><span class="cx">     size_t size = result.length();
</span><del>-    if (size &amp;&amp; result[size - 1] == '\n')
</del><ins>+    if (size &amp;&amp; result[size - 1] == newlineCharacter)
</ins><span class="cx">         result.resize(--size);
</span><span class="cx">     return result.toString();
</span><span class="cx"> }
</span><span class="lines">@@ -579,6 +578,45 @@
</span><span class="cx">     return lastPositionInNode(innerText);
</span><span class="cx"> }
</span><span class="cx"> 
</span><ins>+unsigned HTMLTextFormControlElement::indexForPosition(const Position&amp; passedPosition) const
+{
+    TextControlInnerTextElement* innerText = innerTextElement();
+    if (!innerText || !innerText-&gt;contains(passedPosition.anchorNode()) || passedPosition.isNull())
+        return 0;
+
+    if (positionBeforeNode(innerText) == passedPosition)
+        return 0;
+
+    unsigned index = 0;
+    Node* startNode = passedPosition.computeNodeBeforePosition();
+    if (!startNode)
+        startNode = passedPosition.containerNode();
+    ASSERT(startNode);
+    ASSERT(innerText-&gt;contains(startNode));
+
+    for (Node* node = startNode; node; node = NodeTraversal::previous(node, innerText)) {
+        if (node-&gt;isTextNode()) {
+            unsigned length = toText(*node).length();
+            if (node == passedPosition.containerNode())
+                index += std::min&lt;unsigned&gt;(length, passedPosition.offsetInContainerNode());
+            else
+                index += length;
+        } else if (node-&gt;hasTagName(brTag))
+            index++;
+    }
+
+    unsigned length = innerTextValue().length();
+    index = std::min(index, length); // FIXME: We shouldn't have to call innerTextValue() just to ignore the last LF. See finishText.
+#ifndef ASSERT_DISABLED
+    VisiblePosition visiblePosition = passedPosition;
+    unsigned indexComputedByVisiblePosition = 0;
+    if (visiblePosition.isNotNull())
+        indexComputedByVisiblePosition = WebCore::indexForVisiblePosition(innerText, visiblePosition, false /* forSelectionPreservation */);
+    ASSERT(index == indexComputedByVisiblePosition);
+#endif
+    return index;
+}
+
</ins><span class="cx"> #if PLATFORM(IOS)
</span><span class="cx"> void HTMLTextFormControlElement::hidePlaceholder()
</span><span class="cx"> {
</span></span></pre></div>
<a id="trunkSourceWebCorehtmlHTMLTextFormControlElementh"></a>
<div class="modfile"><h4>Modified: trunk/Source/WebCore/html/HTMLTextFormControlElement.h (164179 => 164180)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/Source/WebCore/html/HTMLTextFormControlElement.h        2014-02-15 21:15:49 UTC (rev 164179)
+++ trunk/Source/WebCore/html/HTMLTextFormControlElement.h        2014-02-15 22:32:05 UTC (rev 164180)
</span><span class="lines">@@ -124,6 +124,8 @@
</span><span class="cx">     virtual void dispatchBlurEvent(PassRefPtr&lt;Element&gt; newFocusedElement) override final;
</span><span class="cx">     virtual bool childShouldCreateRenderer(const Node&amp;) const override;
</span><span class="cx"> 
</span><ins>+    unsigned indexForPosition(const Position&amp;) const;
+
</ins><span class="cx">     // Returns true if user-editable value is empty. Used to check placeholder visibility.
</span><span class="cx">     virtual bool isEmptyValue() const = 0;
</span><span class="cx">     // Returns true if suggested value is empty. Used to check placeholder visibility.
</span></span></pre>
</div>
</div>

</body>
</html>