Title: [164180] trunk/Source/WebCore
Revision
164180
Author
[email protected]
Date
2014-02-15 14:32:05 -0800 (Sat, 15 Feb 2014)

Log Message

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:

Modified Paths

Diff

Modified: trunk/Source/WebCore/ChangeLog (164179 => 164180)


--- 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)
@@ -1,3 +1,29 @@
+2014-02-15  Ryosuke Niwa  <[email protected]>
+
+        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:
+
 2014-02-15  Brent Fulgham  <[email protected]>
 
         [Win] Avoid unnecessary asserts if "prepareToPlay" is called multiple times.

Modified: trunk/Source/WebCore/html/HTMLTextFormControlElement.cpp (164179 => 164180)


--- 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)
@@ -330,8 +330,7 @@
     TextControlInnerTextElement* innerText = innerTextElement();
     if (!innerText || !innerText->contains(position.deepEquivalent().anchorNode()))
         return 0;
-    bool forSelectionPreservation = false;
-    unsigned index = WebCore::indexForVisiblePosition(innerTextElement(), position, forSelectionPreservation);
+    unsigned index = indexForPosition(position.deepEquivalent());
     ASSERT(VisiblePosition(positionForIndex(innerTextElement(), index)) == position);
     return index;
 }
@@ -360,7 +359,7 @@
     if (!frame)
         return 0;
 
-    return indexForVisiblePosition(frame->selection().selection().start());
+    return indexForPosition(frame->selection().selection().start());
 }
 
 int HTMLTextFormControlElement::selectionEnd() const
@@ -379,7 +378,7 @@
     if (!frame)
         return 0;
 
-    return indexForVisiblePosition(frame->selection().selection().end());
+    return indexForPosition(frame->selection().selection().end());
 }
 
 static const AtomicString& directionString(TextFieldSelectionDirection direction)
@@ -537,7 +536,7 @@
 {
     // Remove one trailing newline; there's always one that's collapsed out by rendering.
     size_t size = result.length();
-    if (size && result[size - 1] == '\n')
+    if (size && result[size - 1] == newlineCharacter)
         result.resize(--size);
     return result.toString();
 }
@@ -579,6 +578,45 @@
     return lastPositionInNode(innerText);
 }
 
+unsigned HTMLTextFormControlElement::indexForPosition(const Position& passedPosition) const
+{
+    TextControlInnerTextElement* innerText = innerTextElement();
+    if (!innerText || !innerText->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->contains(startNode));
+
+    for (Node* node = startNode; node; node = NodeTraversal::previous(node, innerText)) {
+        if (node->isTextNode()) {
+            unsigned length = toText(*node).length();
+            if (node == passedPosition.containerNode())
+                index += std::min<unsigned>(length, passedPosition.offsetInContainerNode());
+            else
+                index += length;
+        } else if (node->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;
+}
+
 #if PLATFORM(IOS)
 void HTMLTextFormControlElement::hidePlaceholder()
 {

Modified: trunk/Source/WebCore/html/HTMLTextFormControlElement.h (164179 => 164180)


--- 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)
@@ -124,6 +124,8 @@
     virtual void dispatchBlurEvent(PassRefPtr<Element> newFocusedElement) override final;
     virtual bool childShouldCreateRenderer(const Node&) const override;
 
+    unsigned indexForPosition(const Position&) const;
+
     // Returns true if user-editable value is empty. Used to check placeholder visibility.
     virtual bool isEmptyValue() const = 0;
     // Returns true if suggested value is empty. Used to check placeholder visibility.
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to