Rename InlineBox::nextLeafChild to nextLeafOnLine
[WebKit-https.git] / Source / WebCore / editing / VisibleUnits.cpp
index ddecf29..97c622b 100644 (file)
@@ -27,6 +27,8 @@
 #include "VisibleUnits.h"
 
 #include "Document.h"
+#include "Editing.h"
+#include "HTMLBRElement.h"
 #include "HTMLElement.h"
 #include "HTMLNames.h"
 #include "InlineTextBox.h"
 #include "RenderedPosition.h"
 #include "Text.h"
 #include "TextBoundaries.h"
-#include "TextBreakIterator.h"
 #include "TextIterator.h"
 #include "VisibleSelection.h"
-#include "htmlediting.h"
+#include <unicode/ubrk.h>
+#include <wtf/text/TextBreakIterator.h>
 
 namespace WebCore {
 
@@ -48,25 +50,25 @@ using namespace WTF::Unicode;
 
 static Node* previousLeafWithSameEditability(Node* node, EditableType editableType)
 {
-    bool editable = node->hasEditableStyle(editableType);
+    bool editable = hasEditableStyle(*node, editableType);
     node = previousLeafNode(node);
     while (node) {
-        if (editable == node->hasEditableStyle(editableType))
+        if (editable == hasEditableStyle(*node, editableType))
             return node;
         node = previousLeafNode(node);
     }
     return nullptr;
 }
 
-static Node* nextLeafWithSameEditability(Node* node, EditableType editableType = ContentIsEditable)
+static Node* nextLeafWithSameEditability(Node* node, EditableType editableType)
 {
     if (!node)
         return nullptr;
     
-    bool editable = node->hasEditableStyle(editableType);
+    bool editable = hasEditableStyle(*node, editableType);
     node = nextLeafNode(node);
     while (node) {
-        if (editable == node->hasEditableStyle(editableType))
+        if (editable == hasEditableStyle(*node, editableType))
             return node;
         node = nextLeafNode(node);
     }
@@ -76,7 +78,7 @@ static Node* nextLeafWithSameEditability(Node* node, EditableType editableType =
 // FIXME: consolidate with code in previousLinePosition.
 static Position previousRootInlineBoxCandidatePosition(Node* node, const VisiblePosition& visiblePosition, EditableType editableType)
 {
-    Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent(), editableType);
+    auto* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent(), editableType);
     Node* previousNode = previousLeafWithSameEditability(node, editableType);
 
     while (previousNode && (!previousNode->renderer() || inSameLine(firstPositionInOrBeforeNode(previousNode), visiblePosition)))
@@ -87,7 +89,7 @@ static Position previousRootInlineBoxCandidatePosition(Node* node, const Visible
             break;
 
         Position pos = previousNode->hasTagName(brTag) ? positionBeforeNode(previousNode) :
-            createLegacyEditingPosition(previousNode, caretMaxOffset(previousNode));
+            createLegacyEditingPosition(previousNode, caretMaxOffset(*previousNode));
         
         if (pos.isCandidate())
             return pos;
@@ -99,7 +101,7 @@ static Position previousRootInlineBoxCandidatePosition(Node* node, const Visible
 
 static Position nextRootInlineBoxCandidatePosition(Node* node, const VisiblePosition& visiblePosition, EditableType editableType)
 {
-    Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent(), editableType);
+    auto* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent(), editableType);
     Node* nextNode = nextLeafWithSameEditability(node, editableType);
     while (nextNode && (!nextNode->renderer() || inSameLine(firstPositionInOrBeforeNode(nextNode), visiblePosition)))
         nextNode = nextLeafWithSameEditability(nextNode, ContentIsEditable);
@@ -109,7 +111,7 @@ static Position nextRootInlineBoxCandidatePosition(Node* node, const VisiblePosi
             break;
 
         Position pos;
-        pos = createLegacyEditingPosition(nextNode, caretMinOffset(nextNode));
+        pos = createLegacyEditingPosition(nextNode, caretMinOffset(*nextNode));
         
         if (pos.isCandidate())
             return pos;
@@ -123,23 +125,25 @@ class CachedLogicallyOrderedLeafBoxes {
 public:
     CachedLogicallyOrderedLeafBoxes();
 
-    const InlineBox* previousTextOrLineBreakBox(const RootInlineBox*, const InlineTextBox*);
-    const InlineBox* nextTextOrLineBreakBox(const RootInlineBox*, const InlineTextBox*);
+    const InlineBox* previousTextOrLineBreakBox(const RootInlineBox*, const InlineBox*);
+    const InlineBox* nextTextOrLineBreakBox(const RootInlineBox*, const InlineBox*);
 
     size_t size() const { return m_leafBoxes.size(); }
     const InlineBox* firstBox() const { return m_leafBoxes[0]; }
 
 private:
     const Vector<InlineBox*>& collectBoxes(const RootInlineBox*);
-    int boxIndexInLeaves(const InlineTextBox*) const;
+    int boxIndexInLeaves(const InlineBox*) const;
 
-    const RootInlineBox* m_rootInlineBox;
+    const RootInlineBox* m_rootInlineBox { nullptr };
     Vector<InlineBox*> m_leafBoxes;
 };
 
-CachedLogicallyOrderedLeafBoxes::CachedLogicallyOrderedLeafBoxes() : m_rootInlineBox(0) { };
+CachedLogicallyOrderedLeafBoxes::CachedLogicallyOrderedLeafBoxes()
+{
+}
 
-const InlineBox* CachedLogicallyOrderedLeafBoxes::previousTextOrLineBreakBox(const RootInlineBox* root, const InlineTextBox* box)
+const InlineBox* CachedLogicallyOrderedLeafBoxes::previousTextOrLineBreakBox(const RootInlineBox* root, const InlineBox* box)
 {
     if (!root)
         return nullptr;
@@ -160,7 +164,7 @@ const InlineBox* CachedLogicallyOrderedLeafBoxes::previousTextOrLineBreakBox(con
     return nullptr;
 }
 
-const InlineBox* CachedLogicallyOrderedLeafBoxes::nextTextOrLineBreakBox(const RootInlineBox* root, const InlineTextBox* box)
+const InlineBox* CachedLogicallyOrderedLeafBoxes::nextTextOrLineBreakBox(const RootInlineBox* root, const InlineBox* box)
 {
     if (!root)
         return nullptr;
@@ -192,7 +196,7 @@ const Vector<InlineBox*>& CachedLogicallyOrderedLeafBoxes::collectBoxes(const Ro
     return m_leafBoxes;
 }
 
-int CachedLogicallyOrderedLeafBoxes::boxIndexInLeaves(const InlineTextBox* box) const
+int CachedLogicallyOrderedLeafBoxes::boxIndexInLeaves(const InlineBox* box) const
 {
     for (size_t i = 0; i < m_leafBoxes.size(); ++i) {
         if (box == m_leafBoxes[i])
@@ -201,8 +205,8 @@ int CachedLogicallyOrderedLeafBoxes::boxIndexInLeaves(const InlineTextBox* box)
     return 0;
 }
 
-static const InlineBox* logicallyPreviousBox(const VisiblePosition& visiblePosition, const InlineTextBox* textBox,
-    bool& previousBoxInDifferentBlock, CachedLogicallyOrderedLeafBoxes& leafBoxes)
+static const InlineBox* logicallyPreviousBox(const VisiblePosition& visiblePosition, const InlineBox* textBox,
+    bool& previousBoxInDifferentLine, CachedLogicallyOrderedLeafBoxes& leafBoxes)
 {
     const InlineBox* startBox = textBox;
 
@@ -228,9 +232,9 @@ static const InlineBox* logicallyPreviousBox(const VisiblePosition& visiblePosit
         if (!previousRoot)
             break;
 
-        previousBox = leafBoxes.previousTextOrLineBreakBox(previousRoot, 0);
+        previousBox = leafBoxes.previousTextOrLineBreakBox(previousRoot, &startBox->root() == previousRoot ? startBox : nullptr);
         if (previousBox) {
-            previousBoxInDifferentBlock = true;
+            previousBoxInDifferentLine = true;
             return previousBox;
         }
 
@@ -242,8 +246,8 @@ static const InlineBox* logicallyPreviousBox(const VisiblePosition& visiblePosit
 }
 
 
-static const InlineBox* logicallyNextBox(const VisiblePosition& visiblePosition, const InlineTextBox* textBox,
-    bool& nextBoxInDifferentBlock, CachedLogicallyOrderedLeafBoxes& leafBoxes)
+static const InlineBox* logicallyNextBox(const VisiblePosition& visiblePosition, const InlineBox* textBox,
+    bool& nextBoxInDifferentLine, CachedLogicallyOrderedLeafBoxes& leafBoxes)
 {
     const InlineBox* startBox = textBox;
 
@@ -269,9 +273,9 @@ static const InlineBox* logicallyNextBox(const VisiblePosition& visiblePosition,
         if (!nextRoot)
             break;
 
-        nextBox = leafBoxes.nextTextOrLineBreakBox(nextRoot, 0);
+        nextBox = leafBoxes.nextTextOrLineBreakBox(nextRoot, &startBox->root() == nextRoot ? startBox : nullptr);
         if (nextBox) {
-            nextBoxInDifferentBlock = true;
+            nextBoxInDifferentLine = true;
             return nextBox;
         }
 
@@ -282,58 +286,66 @@ static const InlineBox* logicallyNextBox(const VisiblePosition& visiblePosition,
     return 0;
 }
 
-static TextBreakIterator* wordBreakIteratorForMinOffsetBoundary(const VisiblePosition& visiblePosition, const InlineTextBox* textBox,
-    int& previousBoxLength, bool& previousBoxInDifferentBlock, Vector<UChar, 1024>& string, CachedLogicallyOrderedLeafBoxes& leafBoxes)
+static UBreakIterator* wordBreakIteratorForMinOffsetBoundary(const VisiblePosition& visiblePosition, const InlineTextBox* textBox,
+    int& previousBoxLength, bool& previousBoxInDifferentLine, Vector<UChar, 1024>& string, CachedLogicallyOrderedLeafBoxes& leafBoxes)
 {
-    previousBoxInDifferentBlock = false;
+    previousBoxInDifferentLine = false;
 
-    // FIXME: Handle the case when we don't have an inline text box.
-    const InlineBox* previousBox = logicallyPreviousBox(visiblePosition, textBox, previousBoxInDifferentBlock, leafBoxes);
+    const InlineBox* previousBox = logicallyPreviousBox(visiblePosition, textBox, previousBoxInDifferentLine, leafBoxes);
+    while (previousBox && !is<InlineTextBox>(previousBox)) {
+        ASSERT(previousBox->renderer().isBR());
+        previousBoxInDifferentLine = true;
+        previousBox = logicallyPreviousBox(visiblePosition, previousBox, previousBoxInDifferentLine, leafBoxes);
+    }
 
     string.clear();
 
-    if (previousBox && previousBox->isInlineTextBox()) {
-        const InlineTextBox* previousTextBox = toInlineTextBox(previousBox);
-        previousBoxLength = previousTextBox->len();
-        append(string, StringView(previousTextBox->renderer().text()).substring(previousTextBox->start(), previousBoxLength));
+    if (is<InlineTextBox>(previousBox)) {
+        const auto& previousTextBox = downcast<InlineTextBox>(*previousBox);
+        previousBoxLength = previousTextBox.len();
+        append(string, StringView(previousTextBox.renderer().text()).substring(previousTextBox.start(), previousBoxLength));
     }
     append(string, StringView(textBox->renderer().text()).substring(textBox->start(), textBox->len()));
 
     return wordBreakIterator(StringView(string.data(), string.size()));
 }
 
-static TextBreakIterator* wordBreakIteratorForMaxOffsetBoundary(const VisiblePosition& visiblePosition, const InlineTextBox* textBox,
-    bool& nextBoxInDifferentBlock, Vector<UChar, 1024>& string, CachedLogicallyOrderedLeafBoxes& leafBoxes)
+static UBreakIterator* wordBreakIteratorForMaxOffsetBoundary(const VisiblePosition& visiblePosition, const InlineTextBox* textBox,
+    bool& nextBoxInDifferentLine, Vector<UChar, 1024>& string, CachedLogicallyOrderedLeafBoxes& leafBoxes)
 {
-    nextBoxInDifferentBlock = false;
+    nextBoxInDifferentLine = false;
 
-    // FIXME: Handle the case when we don't have an inline text box.
-    const InlineBox* nextBox = logicallyNextBox(visiblePosition, textBox, nextBoxInDifferentBlock, leafBoxes);
+    const InlineBox* nextBox = logicallyNextBox(visiblePosition, textBox, nextBoxInDifferentLine, leafBoxes);
+    while (nextBox && !is<InlineTextBox>(nextBox)) {
+        ASSERT(nextBox->renderer().isBR());
+        nextBoxInDifferentLine = true;
+        nextBox = logicallyNextBox(visiblePosition, nextBox, nextBoxInDifferentLine, leafBoxes);
+    }
 
     string.clear();
     append(string, StringView(textBox->renderer().text()).substring(textBox->start(), textBox->len()));
-    if (nextBox && nextBox->isInlineTextBox()) {
-        const InlineTextBox* nextTextBox = toInlineTextBox(nextBox);
-        append(string, StringView(nextTextBox->renderer().text()).substring(nextTextBox->start(), nextTextBox->len()));
+    if (is<InlineTextBox>(nextBox)) {
+        const auto& nextTextBox = downcast<InlineTextBox>(*nextBox);
+        append(string, StringView(nextTextBox.renderer().text()).substring(nextTextBox.start(), nextTextBox.len()));
     }
 
     return wordBreakIterator(StringView(string.data(), string.size()));
 }
 
-static bool isLogicalStartOfWord(TextBreakIterator* iter, int position, bool hardLineBreak)
+static bool isLogicalStartOfWord(UBreakIterator* iter, int position, bool hardLineBreak)
 {
-    bool boundary = hardLineBreak ? true : isTextBreak(iter, position);
+    bool boundary = hardLineBreak ? true : ubrk_isBoundary(iter, position);
     if (!boundary)
         return false;
 
-    textBreakFollowing(iter, position);
+    ubrk_following(iter, position);
     // isWordTextBreak returns true after moving across a word and false after moving across a punctuation/space.
     return isWordTextBreak(iter);
 }
 
-static bool islogicalEndOfWord(TextBreakIterator* iter, int position, bool hardLineBreak)
+static bool islogicalEndOfWord(UBreakIterator* iter, int position, bool hardLineBreak)
 {
-    bool boundary = isTextBreak(iter, position);
+    bool boundary = ubrk_isBoundary(iter, position);
     return (hardLineBreak || boundary) && isWordTextBreak(iter);
 }
 
@@ -346,9 +358,10 @@ static VisiblePosition visualWordPosition(const VisiblePosition& visiblePosition
         return VisiblePosition();
 
     TextDirection blockDirection = directionOfEnclosingBlock(visiblePosition.deepEquivalent());
-    InlineBox* previouslyVisitedBox = 0;
+    InlineBox* previouslyVisitedBox = nullptr;
     VisiblePosition current = visiblePosition;
-    TextBreakIterator* iter = 0;
+    Optional<VisiblePosition> previousPosition;
+    UBreakIterator* iter = nullptr;
 
     CachedLogicallyOrderedLeafBoxes leafBoxes;
     Vector<UChar, 1024> string;
@@ -357,6 +370,9 @@ static VisiblePosition visualWordPosition(const VisiblePosition& visiblePosition
         VisiblePosition adjacentCharacterPosition = direction == MoveRight ? current.right(true) : current.left(true); 
         if (adjacentCharacterPosition == current || adjacentCharacterPosition.isNull())
             return VisiblePosition();
+        // FIXME: This is a workaround for webkit.org/b/167138.
+        if (previousPosition && adjacentCharacterPosition == previousPosition.value())
+            return VisiblePosition();
     
         InlineBox* box;
         int offsetInBox;
@@ -364,47 +380,52 @@ static VisiblePosition visualWordPosition(const VisiblePosition& visiblePosition
     
         if (!box)
             break;
-        if (!box->isInlineTextBox()) {
+        if (!is<InlineTextBox>(*box)) {
             current = adjacentCharacterPosition;
             continue;
         }
 
-        InlineTextBox* textBox = toInlineTextBox(box);
+        InlineTextBox& textBox = downcast<InlineTextBox>(*box);
         int previousBoxLength = 0;
-        bool previousBoxInDifferentBlock = false;
-        bool nextBoxInDifferentBlock = false;
+        bool previousBoxInDifferentLine = false;
+        bool nextBoxInDifferentLine = false;
         bool movingIntoNewBox = previouslyVisitedBox != box;
 
         if (offsetInBox == box->caretMinOffset())
-            iter = wordBreakIteratorForMinOffsetBoundary(visiblePosition, textBox, previousBoxLength, previousBoxInDifferentBlock, string, leafBoxes);
+            iter = wordBreakIteratorForMinOffsetBoundary(adjacentCharacterPosition, &textBox, previousBoxLength, previousBoxInDifferentLine, string, leafBoxes);
         else if (offsetInBox == box->caretMaxOffset())
-            iter = wordBreakIteratorForMaxOffsetBoundary(visiblePosition, textBox, nextBoxInDifferentBlock, string, leafBoxes);
+            iter = wordBreakIteratorForMaxOffsetBoundary(adjacentCharacterPosition, &textBox, nextBoxInDifferentLine, string, leafBoxes);
         else if (movingIntoNewBox) {
-            iter = wordBreakIterator(StringView(textBox->renderer().text()).substring(textBox->start(), textBox->len()));
+            iter = wordBreakIterator(StringView(textBox.renderer().text()).substring(textBox.start(), textBox.len()));
             previouslyVisitedBox = box;
         }
 
         if (!iter)
             break;
 
-        textBreakFirst(iter);
-        int offsetInIterator = offsetInBox - textBox->start() + previousBoxLength;
+        ubrk_first(iter);
+        int offsetInIterator = offsetInBox - textBox.start() + previousBoxLength;
 
         bool isWordBreak;
         bool boxHasSameDirectionalityAsBlock = box->direction() == blockDirection;
-        bool movingBackward = (direction == MoveLeft && box->direction() == LTR) || (direction == MoveRight && box->direction() == RTL);
+        bool movingBackward = (direction == MoveLeft && box->direction() == TextDirection::LTR) || (direction == MoveRight && box->direction() == TextDirection::RTL);
         if ((skipsSpaceWhenMovingRight && boxHasSameDirectionalityAsBlock)
             || (!skipsSpaceWhenMovingRight && movingBackward)) {
-            bool logicalStartInRenderer = offsetInBox == static_cast<int>(textBox->start()) && previousBoxInDifferentBlock;
+            bool logicalStartInRenderer = offsetInBox == static_cast<int>(textBox.start()) && previousBoxInDifferentLine;
             isWordBreak = isLogicalStartOfWord(iter, offsetInIterator, logicalStartInRenderer);
+            if (isWordBreak && offsetInBox == box->caretMaxOffset() && nextBoxInDifferentLine)
+                isWordBreak = false;
         } else {
-            bool logicalEndInRenderer = offsetInBox == static_cast<int>(textBox->start() + textBox->len()) && nextBoxInDifferentBlock;
+            bool logicalEndInRenderer = offsetInBox == static_cast<int>(textBox.start() + textBox.len()) && nextBoxInDifferentLine;
             isWordBreak = islogicalEndOfWord(iter, offsetInIterator, logicalEndInRenderer);
+            if (isWordBreak && offsetInBox == box->caretMinOffset() && previousBoxInDifferentLine)
+                isWordBreak = false;
         }      
 
         if (isWordBreak)
             return adjacentCharacterPosition;
     
+        previousPosition = current;
         current = adjacentCharacterPosition;
     }
     return VisiblePosition();
@@ -418,7 +439,7 @@ VisiblePosition leftWordPosition(const VisiblePosition& visiblePosition, bool sk
     // FIXME: How should we handle a non-editable position?
     if (leftWordBreak.isNull() && isEditablePosition(visiblePosition.deepEquivalent())) {
         TextDirection blockDirection = directionOfEnclosingBlock(visiblePosition.deepEquivalent());
-        leftWordBreak = blockDirection == LTR ? startOfEditableContent(visiblePosition) : endOfEditableContent(visiblePosition);
+        leftWordBreak = blockDirection == TextDirection::LTR ? startOfEditableContent(visiblePosition) : endOfEditableContent(visiblePosition);
     }
     return leftWordBreak;
 }
@@ -431,16 +452,12 @@ VisiblePosition rightWordPosition(const VisiblePosition& visiblePosition, bool s
     // FIXME: How should we handle a non-editable position?
     if (rightWordBreak.isNull() && isEditablePosition(visiblePosition.deepEquivalent())) {
         TextDirection blockDirection = directionOfEnclosingBlock(visiblePosition.deepEquivalent());
-        rightWordBreak = blockDirection == LTR ? endOfEditableContent(visiblePosition) : startOfEditableContent(visiblePosition);
+        rightWordBreak = blockDirection == TextDirection::LTR ? endOfEditableContent(visiblePosition) : startOfEditableContent(visiblePosition);
     }
     return rightWordBreak;
 }
 
 
-enum BoundarySearchContextAvailability { DontHaveMoreContext, MayHaveMoreContext };
-
-typedef unsigned (*BoundarySearchFunction)(StringView, unsigned offset, BoundarySearchContextAvailability, bool& needMoreContext);
-
 static void prepend(Vector<UChar, 1024>& buffer, StringView string)
 {
     unsigned oldSize = buffer.size();
@@ -468,52 +485,46 @@ static void appendRepeatedCharacter(Vector<UChar, 1024>& buffer, UChar character
         buffer[oldSize + i] = character;
 }
 
-static VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction)
+unsigned suffixLengthForRange(const Range& forwardsScanRange, Vector<UChar, 1024>& string)
 {
-    Position pos = c.deepEquivalent();
-    Node* boundary = pos.parentEditingBoundary();
-    if (!boundary)
-        return VisiblePosition();
-
-    Document& boundaryDocument = boundary->document();
-    Position start = createLegacyEditingPosition(boundary, 0).parentAnchoredEquivalent();
-    Position end = pos.parentAnchoredEquivalent();
-    RefPtr<Range> searchRange = Range::create(boundaryDocument);
-    
-    Vector<UChar, 1024> string;
     unsigned suffixLength = 0;
-
-    ExceptionCode ec = 0;
-    if (requiresContextForWordBoundary(c.characterBefore())) {
-        RefPtr<Range> forwardsScanRange(boundaryDocument.createRange());
-        forwardsScanRange->setEndAfter(boundary, ec);
-        forwardsScanRange->setStart(end.deprecatedNode(), end.deprecatedEditingOffset(), ec);
-        TextIterator forwardsIterator(forwardsScanRange.get());
-        while (!forwardsIterator.atEnd()) {
-            StringView text = forwardsIterator.text();
-            unsigned i = endOfFirstWordBoundaryContext(text);
-            append(string, text.substring(0, i));
-            suffixLength += i;
-            if (i < text.length())
-                break;
-            forwardsIterator.advance();
-        }
+    TextIterator forwardsIterator(&forwardsScanRange);
+    while (!forwardsIterator.atEnd()) {
+        StringView text = forwardsIterator.text();
+        unsigned i = endOfFirstWordBoundaryContext(text);
+        append(string, text.substring(0, i));
+        suffixLength += i;
+        if (i < text.length())
+            break;
+        forwardsIterator.advance();
     }
+    return suffixLength;
+}
 
-    searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), ec);
-    searchRange->setEnd(end.deprecatedNode(), end.deprecatedEditingOffset(), ec);
-
-    ASSERT(!ec);
-    if (ec)
-        return VisiblePosition();
+unsigned prefixLengthForRange(const Range& backwardsScanRange, Vector<UChar, 1024>& string)
+{
+    unsigned prefixLength = 0;
+    SimplifiedBackwardsTextIterator backwardsIterator(backwardsScanRange);
+    while (!backwardsIterator.atEnd()) {
+        StringView text = backwardsIterator.text();
+        int i = startOfLastWordBoundaryContext(text);
+        prepend(string, text.substring(i));
+        prefixLength += text.length() - i;
+        if (i > 0)
+            break;
+        backwardsIterator.advance();
+    }
+    return prefixLength;
+}
 
-    SimplifiedBackwardsTextIterator it(*searchRange);
+unsigned backwardSearchForBoundaryWithTextIterator(SimplifiedBackwardsTextIterator& it, Vector<UChar, 1024>& string, unsigned suffixLength, BoundarySearchFunction searchFunction)
+{
     unsigned next = 0;
     bool needMoreContext = false;
     while (!it.atEnd()) {
-        bool inTextSecurityMode = it.node() && it.node()->renderer() && it.node()->renderer()->style().textSecurity() != TSNONE;
+        bool inTextSecurityMode = it.node() && it.node()->renderer() && it.node()->renderer()->style().textSecurity() != TextSecurity::None;
         // iterate to get chunks until the searchFunction returns a non-zero value.
-        if (!inTextSecurityMode) 
+        if (!inTextSecurityMode)
             prepend(string, it.text());
         else {
             // Treat bullets used in the text security mode as regular characters when looking for boundaries
@@ -532,58 +543,16 @@ static VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearch
         next = searchFunction(StringView(string.data(), string.size()), string.size() - suffixLength, DontHaveMoreContext, needMoreContext);
         ASSERT(!needMoreContext);
     }
-
-    if (!next)
-        return VisiblePosition(it.atEnd() ? searchRange->startPosition() : pos, DOWNSTREAM);
-
-    Node* node = it.atEnd() ? searchRange->startContainer() : it.range()->startContainer();
-    if ((node->isTextNode() && static_cast<int>(next) <= node->maxCharacterOffset()) || (node->renderer() && node->renderer()->isBR() && !next))
-        // The next variable contains a usable index into a text node
-        return VisiblePosition(createLegacyEditingPosition(node, next), DOWNSTREAM);
-
-    // Use the character iterator to translate the next value into a DOM position.
-    BackwardsCharacterIterator charIt(*searchRange);
-    charIt.advance(string.size() - suffixLength - next);
-    // FIXME: charIt can get out of shadow host.
-    return VisiblePosition(charIt.range()->endPosition(), DOWNSTREAM);
+    
+    return next;
 }
 
-static VisiblePosition nextBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction)
+unsigned forwardSearchForBoundaryWithTextIterator(TextIterator& it, Vector<UChar, 1024>& string, unsigned prefixLength, BoundarySearchFunction searchFunction)
 {
-    Position pos = c.deepEquivalent();
-    Node* boundary = pos.parentEditingBoundary();
-    if (!boundary)
-        return VisiblePosition();
-
-    Document& boundaryDocument = boundary->document();
-    RefPtr<Range> searchRange(boundaryDocument.createRange());
-    Position start(pos.parentAnchoredEquivalent());
-
-    Vector<UChar, 1024> string;
-    unsigned prefixLength = 0;
-
-    if (requiresContextForWordBoundary(c.characterAfter())) {
-        RefPtr<Range> backwardsScanRange(boundaryDocument.createRange());
-        backwardsScanRange->setEnd(start.deprecatedNode(), start.deprecatedEditingOffset(), IGNORE_EXCEPTION);
-        SimplifiedBackwardsTextIterator backwardsIterator(*backwardsScanRange);
-        while (!backwardsIterator.atEnd()) {
-            StringView text = backwardsIterator.text();
-            int i = startOfLastWordBoundaryContext(text);
-            prepend(string, text.substring(i));
-            prefixLength += text.length() - i;
-            if (i > 0)
-                break;
-            backwardsIterator.advance();
-        }
-    }
-
-    searchRange->selectNodeContents(boundary, IGNORE_EXCEPTION);
-    searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), IGNORE_EXCEPTION);
-    TextIterator it(searchRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions);
     unsigned next = 0;
     bool needMoreContext = false;
     while (!it.atEnd()) {
-        bool inTextSecurityMode = it.node() && it.node()->renderer() && it.node()->renderer()->style().textSecurity() != TSNONE;
+        bool inTextSecurityMode = it.node() && it.node()->renderer() && it.node()->renderer()->style().textSecurity() != TextSecurity::None;
         // Keep asking the iterator for chunks until the search function
         // returns an end value not equal to the length of the string passed to it.
         if (!inTextSecurityMode)
@@ -606,11 +575,112 @@ static VisiblePosition nextBoundary(const VisiblePosition& c, BoundarySearchFunc
         ASSERT(!needMoreContext);
     }
     
+    return next;
+}
+
+enum class NeedsContextAtParagraphStart { Yes, No };
+static VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction,
+    NeedsContextAtParagraphStart needsContextAtParagraphStart = NeedsContextAtParagraphStart::No)
+{
+    Position pos = c.deepEquivalent();
+    Node* boundary = pos.parentEditingBoundary();
+    if (!boundary)
+        return VisiblePosition();
+
+    Document& boundaryDocument = boundary->document();
+    Position start = createLegacyEditingPosition(boundary, 0).parentAnchoredEquivalent();
+    Position end = pos.parentAnchoredEquivalent();
+
+    if (start.isNull() || end.isNull())
+        return VisiblePosition();
+
+    Ref<Range> searchRange = Range::create(boundaryDocument);
+    
+    Vector<UChar, 1024> string;
+    unsigned suffixLength = 0;
+
+    if (needsContextAtParagraphStart == NeedsContextAtParagraphStart::Yes && isStartOfParagraph(c)) {
+        auto forwardsScanRange = boundaryDocument.createRange();
+        auto endOfCurrentParagraph = endOfParagraph(c);
+        auto result = forwardsScanRange->setEnd(endOfCurrentParagraph.deepEquivalent());
+        if (result.hasException())
+            return { };
+        result = forwardsScanRange->setStart(start);
+        if (result.hasException())
+            return { };
+        for (TextIterator forwardsIterator(forwardsScanRange.ptr()); !forwardsIterator.atEnd(); forwardsIterator.advance())
+            append(string, forwardsIterator.text());
+        suffixLength = string.size();
+    } else if (requiresContextForWordBoundary(c.characterBefore())) {
+        auto forwardsScanRange = boundaryDocument.createRange();
+        auto result = forwardsScanRange->setEndAfter(*boundary);
+        if (result.hasException())
+            return { };
+        result = forwardsScanRange->setStart(*end.deprecatedNode(), end.deprecatedEditingOffset());
+        if (result.hasException())
+            return { };
+        suffixLength = suffixLengthForRange(forwardsScanRange, string);
+    }
+
+    auto result = searchRange->setStart(*start.deprecatedNode(), start.deprecatedEditingOffset());
+    if (result.hasException())
+        return { };
+    result = searchRange->setEnd(*end.deprecatedNode(), end.deprecatedEditingOffset());
+    if (result.hasException())
+        return { };
+
+    SimplifiedBackwardsTextIterator it(searchRange);
+    unsigned next = backwardSearchForBoundaryWithTextIterator(it, string, suffixLength, searchFunction);
+
+    if (!next)
+        return VisiblePosition(it.atEnd() ? searchRange->startPosition() : pos, DOWNSTREAM);
+
+    Node& node = it.atEnd() ? searchRange->startContainer() : it.range()->startContainer();
+    if ((!suffixLength && node.isTextNode() && static_cast<int>(next) <= node.maxCharacterOffset()) || (node.renderer() && node.renderer()->isBR() && !next)) {
+        // The next variable contains a usable index into a text node
+        return VisiblePosition(createLegacyEditingPosition(&node, next), DOWNSTREAM);
+    }
+
+    // Use the character iterator to translate the next value into a DOM position.
+    BackwardsCharacterIterator charIt(searchRange);
+    if (next < string.size() - suffixLength)
+        charIt.advance(string.size() - suffixLength - next);
+    // FIXME: charIt can get out of shadow host.
+    return VisiblePosition(charIt.range()->endPosition(), DOWNSTREAM);
+}
+
+static VisiblePosition nextBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction)
+{
+    Position pos = c.deepEquivalent();
+    Node* boundary = pos.parentEditingBoundary();
+    if (!boundary)
+        return VisiblePosition();
+
+    Document& boundaryDocument = boundary->document();
+    Ref<Range> searchRange = boundaryDocument.createRange();
+    Position start(pos.parentAnchoredEquivalent());
+
+    Vector<UChar, 1024> string;
+    unsigned prefixLength = 0;
+
+    if (requiresContextForWordBoundary(c.characterAfter())) {
+        auto backwardsScanRange = boundaryDocument.createRange();
+        if (start.deprecatedNode())
+            backwardsScanRange->setEnd(*start.deprecatedNode(), start.deprecatedEditingOffset());
+        prefixLength = prefixLengthForRange(backwardsScanRange, string);
+    }
+
+    searchRange->selectNodeContents(*boundary);
+    if (start.deprecatedNode())
+        searchRange->setStart(*start.deprecatedNode(), start.deprecatedEditingOffset());
+    TextIterator it(searchRange.ptr(), TextIteratorEmitsCharactersBetweenAllVisiblePositions);
+    unsigned next = forwardSearchForBoundaryWithTextIterator(it, string, prefixLength, searchFunction);
+    
     if (it.atEnd() && next == string.size())
         pos = searchRange->endPosition();
     else if (next > prefixLength) {
         // Use the character iterator to translate the next value into a DOM position.
-        CharacterIterator charIt(*searchRange, TextIteratorEmitsCharactersBetweenAllVisiblePositions);
+        CharacterIterator charIt(searchRange, TextIteratorEmitsCharactersBetweenAllVisiblePositions);
         charIt.advance(next - prefixLength - 1);
         RefPtr<Range> characterRange = charIt.range();
         pos = characterRange->endPosition();
@@ -631,7 +701,7 @@ static VisiblePosition nextBoundary(const VisiblePosition& c, BoundarySearchFunc
 
 // ---------
 
-static unsigned startWordBoundary(StringView text, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
+unsigned startWordBoundary(StringView text, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
 {
     ASSERT(offset);
     if (mayHaveMoreContext && !startOfLastWordBoundaryContext(text.substring(0, offset))) {
@@ -662,7 +732,7 @@ VisiblePosition startOfWord(const VisiblePosition& c, EWordSide side)
     return previousBoundary(p, startWordBoundary);
 }
 
-static unsigned endWordBoundary(StringView text, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
+unsigned endWordBoundary(StringView text, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
 {
     ASSERT(offset <= text.length());
     if (mayHaveMoreContext && endOfFirstWordBoundaryContext(text.substring(offset)) == text.length() - offset) {
@@ -754,7 +824,7 @@ static VisiblePosition startPositionForLine(const VisiblePosition& c, LineEndpoi
     } else {
         // Generated content (e.g. list markers and CSS :before and :after pseudoelements) have no corresponding DOM element,
         // and so cannot be represented by a VisiblePosition. Use whatever follows instead.
-        startBox = rootBox->firstLeafChild();
+        startBox = rootBox->firstLeafDescendant();
         while (true) {
             if (!startBox)
                 return VisiblePosition();
@@ -763,39 +833,45 @@ static VisiblePosition startPositionForLine(const VisiblePosition& c, LineEndpoi
             if (startNode)
                 break;
 
-            startBox = startBox->nextLeafChild();
+            startBox = startBox->nextLeafOnLine();
         }
     }
 
-    return is<Text>(*startNode) ? Position(downcast<Text>(startNode), toInlineTextBox(startBox)->start())
+    return is<Text>(*startNode) ? Position(downcast<Text>(startNode), downcast<InlineTextBox>(*startBox).start())
         : positionBeforeNode(startNode);
 }
 
-static VisiblePosition startOfLine(const VisiblePosition& c, LineEndpointComputationMode mode)
+static VisiblePosition startOfLine(const VisiblePosition& c, LineEndpointComputationMode mode, bool* reachedBoundary)
 {
+    if (reachedBoundary)
+        *reachedBoundary = false;
     // TODO: this is the current behavior that might need to be fixed.
     // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
     VisiblePosition visPos = startPositionForLine(c, mode);
 
     if (mode == UseLogicalOrdering) {
         if (Node* editableRoot = highestEditableRoot(c.deepEquivalent())) {
-            if (!editableRoot->contains(visPos.deepEquivalent().containerNode()))
-                return firstPositionInNode(editableRoot);
+            if (!editableRoot->contains(visPos.deepEquivalent().containerNode())) {
+                VisiblePosition newPosition = firstPositionInNode(editableRoot);
+                if (reachedBoundary)
+                    *reachedBoundary = c == newPosition;
+                return newPosition;
+            }
         }
     }
 
-    return c.honorEditingBoundaryAtOrBefore(visPos);
+    return c.honorEditingBoundaryAtOrBefore(visPos, reachedBoundary);
 }
 
 // FIXME: Rename this function to reflect the fact it ignores bidi levels.
 VisiblePosition startOfLine(const VisiblePosition& currentPosition)
 {
-    return startOfLine(currentPosition, UseInlineBoxOrdering);
+    return startOfLine(currentPosition, UseInlineBoxOrdering, nullptr);
 }
 
-VisiblePosition logicalStartOfLine(const VisiblePosition& currentPosition)
+VisiblePosition logicalStartOfLine(const VisiblePosition& currentPosition, bool* reachedBoundary)
 {
-    return startOfLine(currentPosition, UseLogicalOrdering);
+    return startOfLine(currentPosition, UseLogicalOrdering, reachedBoundary);
 }
 
 static VisiblePosition endPositionForLine(const VisiblePosition& c, LineEndpointComputationMode mode)
@@ -822,7 +898,7 @@ static VisiblePosition endPositionForLine(const VisiblePosition& c, LineEndpoint
     } else {
         // Generated content (e.g. list markers and CSS :before and :after pseudoelements) have no corresponding DOM element,
         // and so cannot be represented by a VisiblePosition. Use whatever precedes instead.
-        endBox = rootBox->lastLeafChild();
+        endBox = rootBox->lastLeafDescendant();
         while (true) {
             if (!endBox)
                 return VisiblePosition();
@@ -831,18 +907,18 @@ static VisiblePosition endPositionForLine(const VisiblePosition& c, LineEndpoint
             if (endNode)
                 break;
             
-            endBox = endBox->prevLeafChild();
+            endBox = endBox->previousLeafOnLine();
         }
     }
 
     Position pos;
-    if (endNode->hasTagName(brTag))
+    if (is<HTMLBRElement>(*endNode))
         pos = positionBeforeNode(endNode);
-    else if (endBox->isInlineTextBox() && is<Text>(*endNode)) {
-        InlineTextBox* endTextBox = toInlineTextBox(endBox);
-        int endOffset = endTextBox->start();
-        if (!endTextBox->isLineBreak())
-            endOffset += endTextBox->len();
+    else if (is<InlineTextBox>(*endBox) && is<Text>(*endNode)) {
+        auto& endTextBox = downcast<InlineTextBox>(*endBox);
+        int endOffset = endTextBox.start();
+        if (!endTextBox.isLineBreak())
+            endOffset += endTextBox.len();
         pos = Position(downcast<Text>(endNode), endOffset);
     } else
         pos = positionAfterNode(endNode);
@@ -855,8 +931,10 @@ static bool inSameLogicalLine(const VisiblePosition& a, const VisiblePosition& b
     return a.isNotNull() && logicalStartOfLine(a) == logicalStartOfLine(b);
 }
 
-static VisiblePosition endOfLine(const VisiblePosition& c, LineEndpointComputationMode mode)
+static VisiblePosition endOfLine(const VisiblePosition& c, LineEndpointComputationMode mode, bool* reachedBoundary)
 {
+    if (reachedBoundary)
+        *reachedBoundary = false;
     // TODO: this is the current behavior that might need to be fixed.
     // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
     VisiblePosition visPos = endPositionForLine(c, mode);
@@ -871,11 +949,15 @@ static VisiblePosition endOfLine(const VisiblePosition& c, LineEndpointComputati
             visPos = visPos.previous();
 
         if (Node* editableRoot = highestEditableRoot(c.deepEquivalent())) {
-            if (!editableRoot->contains(visPos.deepEquivalent().containerNode()))
-                return lastPositionInNode(editableRoot);
+            if (!editableRoot->contains(visPos.deepEquivalent().containerNode())) {
+                VisiblePosition newPosition = lastPositionInNode(editableRoot);
+                if (reachedBoundary)
+                    *reachedBoundary = c == newPosition;
+                return newPosition;
+            }
         }
 
-        return c.honorEditingBoundaryAtOrAfter(visPos);
+        return c.honorEditingBoundaryAtOrAfter(visPos, reachedBoundary);
     }
 
     // Make sure the end of line is at the same line as the given input position. Else use the previous position to 
@@ -890,18 +972,18 @@ static VisiblePosition endOfLine(const VisiblePosition& c, LineEndpointComputati
         visPos = endPositionForLine(visPos, UseInlineBoxOrdering);
     }
     
-    return c.honorEditingBoundaryAtOrAfter(visPos);
+    return c.honorEditingBoundaryAtOrAfter(visPos, reachedBoundary);
 }
 
 // FIXME: Rename this function to reflect the fact it ignores bidi levels.
 VisiblePosition endOfLine(const VisiblePosition& currentPosition)
 {
-    return endOfLine(currentPosition, UseInlineBoxOrdering);
+    return endOfLine(currentPosition, UseInlineBoxOrdering, nullptr);
 }
 
-VisiblePosition logicalEndOfLine(const VisiblePosition& currentPosition)
+VisiblePosition logicalEndOfLine(const VisiblePosition& currentPosition, bool* reachedBoundary)
 {
-    return endOfLine(currentPosition, UseLogicalOrdering);
+    return endOfLine(currentPosition, UseLogicalOrdering, reachedBoundary);
 }
 
 bool inSameLine(const VisiblePosition& a, const VisiblePosition& b)
@@ -927,7 +1009,7 @@ bool isLogicalEndOfLine(const VisiblePosition &p)
 static inline IntPoint absoluteLineDirectionPointToLocalPointInBlock(RootInlineBox& root, int lineDirectionPoint)
 {
     RenderBlockFlow& containingBlock = root.blockFlow();
-    FloatPoint absoluteBlockPoint = containingBlock.localToAbsolute(FloatPoint()) - containingBlock.scrolledContentOffset();
+    FloatPoint absoluteBlockPoint = containingBlock.localToAbsolute(FloatPoint()) - toFloatSize(containingBlock.scrollPosition());
 
     if (containingBlock.isHorizontalWritingMode())
         return IntPoint(lineDirectionPoint - absoluteBlockPoint.x(), root.blockDirectionPointInLine());
@@ -935,6 +1017,13 @@ static inline IntPoint absoluteLineDirectionPointToLocalPointInBlock(RootInlineB
     return IntPoint(root.blockDirectionPointInLine(), lineDirectionPoint - absoluteBlockPoint.y());
 }
 
+static Element* rootEditableOrDocumentElement(Node& node, EditableType editableType)
+{
+    if (hasEditableStyle(node, editableType))
+        return editableRootForPosition(firstPositionInOrBeforeNode(&node), editableType);
+    return node.document().documentElement();
+}
+
 VisiblePosition previousLinePosition(const VisiblePosition& visiblePosition, int lineDirectionPoint, EditableType editableType)
 {
     Position p = visiblePosition.deepEquivalent();
@@ -949,7 +1038,7 @@ VisiblePosition previousLinePosition(const VisiblePosition& visiblePosition, int
     if (!renderer)
         return VisiblePosition();
 
-    RootInlineBox* root = 0;
+    RootInlineBox* root = nullptr;
     InlineBox* box;
     int ignoredCaretOffset;
     visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
@@ -957,8 +1046,8 @@ VisiblePosition previousLinePosition(const VisiblePosition& visiblePosition, int
         root = box->root().prevRootBox();
         // We want to skip zero height boxes.
         // This could happen in case it is a TrailingFloatsRootInlineBox.
-        if (!root || !root->logicalHeight() || !root->firstLeafChild())
-            root = 0;
+        if (!root || !root->logicalHeight() || !root->firstLeafDescendant())
+            root = nullptr;
     }
 
     if (!root) {
@@ -976,7 +1065,7 @@ VisiblePosition previousLinePosition(const VisiblePosition& visiblePosition, int
         IntPoint pointInLine = absoluteLineDirectionPointToLocalPointInBlock(*root, lineDirectionPoint);
         RenderObject& renderer = root->closestLeafChildForPoint(pointInLine, isEditablePosition(p))->renderer();
         Node* node = renderer.node();
-        if (node && editingIgnoresContent(node))
+        if (node && editingIgnoresContent(*node))
             return positionInParentBeforeNode(node);
         return renderer.positionForPoint(pointInLine, nullptr);
     }
@@ -984,7 +1073,7 @@ VisiblePosition previousLinePosition(const VisiblePosition& visiblePosition, int
     // Could not find a previous line. This means we must already be on the first line.
     // Move to the start of the content in this block, which effectively moves us
     // to the start of the line we're on.
-    Element* rootElement = node->hasEditableStyle(editableType) ? node->rootEditableElement(editableType) : node->document().documentElement();
+    Element* rootElement = rootEditableOrDocumentElement(*node, editableType);
     if (!rootElement)
         return VisiblePosition();
     return VisiblePosition(firstPositionInNode(rootElement), DOWNSTREAM);
@@ -1004,7 +1093,7 @@ VisiblePosition nextLinePosition(const VisiblePosition& visiblePosition, int lin
     if (!renderer)
         return VisiblePosition();
 
-    RootInlineBox* root = 0;
+    RootInlineBox* root = nullptr;
     InlineBox* box;
     int ignoredCaretOffset;
     visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
@@ -1012,8 +1101,8 @@ VisiblePosition nextLinePosition(const VisiblePosition& visiblePosition, int lin
         root = box->root().nextRootBox();
         // We want to skip zero height boxes.
         // This could happen in case it is a TrailingFloatsRootInlineBox.
-        if (!root || !root->logicalHeight() || !root->firstLeafChild())
-            root = 0;
+        if (!root || !root->logicalHeight() || !root->firstLeafDescendant())
+            root = nullptr;
     }
 
     if (!root) {
@@ -1034,7 +1123,7 @@ VisiblePosition nextLinePosition(const VisiblePosition& visiblePosition, int lin
         IntPoint pointInLine = absoluteLineDirectionPointToLocalPointInBlock(*root, lineDirectionPoint);
         RenderObject& renderer = root->closestLeafChildForPoint(pointInLine, isEditablePosition(p))->renderer();
         Node* node = renderer.node();
-        if (node && editingIgnoresContent(node))
+        if (node && editingIgnoresContent(*node))
             return positionInParentBeforeNode(node);
         return renderer.positionForPoint(pointInLine, nullptr);
     }
@@ -1042,7 +1131,7 @@ VisiblePosition nextLinePosition(const VisiblePosition& visiblePosition, int lin
     // Could not find a next line. This means we must already be on the last line.
     // Move to the end of the content in this block, which effectively moves us
     // to the end of the line we're on.
-    Element* rootElement = node->hasEditableStyle(editableType) ? node->rootEditableElement(editableType) : node->document().documentElement();
+    Element* rootElement = rootEditableOrDocumentElement(*node, editableType);
     if (!rootElement)
         return VisiblePosition();
     return VisiblePosition(lastPositionInNode(rootElement), DOWNSTREAM);
@@ -1050,20 +1139,20 @@ VisiblePosition nextLinePosition(const VisiblePosition& visiblePosition, int lin
 
 // ---------
 
-static unsigned startSentenceBoundary(StringView text, unsigned, BoundarySearchContextAvailability, bool&)
+unsigned startSentenceBoundary(StringView text, unsigned, BoundarySearchContextAvailability, bool&)
 {
     // FIXME: The following function can return -1; we don't handle that.
-    return textBreakPreceding(sentenceBreakIterator(text), text.length());
+    return ubrk_preceding(sentenceBreakIterator(text), text.length());
 }
 
 VisiblePosition startOfSentence(const VisiblePosition& position)
 {
-    return previousBoundary(position, startSentenceBoundary);
+    return previousBoundary(position, startSentenceBoundary, NeedsContextAtParagraphStart::Yes);
 }
 
-static unsigned endSentenceBoundary(StringView text, unsigned, BoundarySearchContextAvailability, bool&)
+unsigned endSentenceBoundary(StringView text, unsigned, BoundarySearchContextAvailability, bool&)
 {
-    return textBreakNext(sentenceBreakIterator(text));
+    return ubrk_next(sentenceBreakIterator(text));
 }
 
 VisiblePosition endOfSentence(const VisiblePosition& position)
@@ -1076,7 +1165,7 @@ static unsigned previousSentencePositionBoundary(StringView text, unsigned, Boun
 {
     // FIXME: This is identical to startSentenceBoundary. I'm pretty sure that's not right.
     // FIXME: The following function can return -1; we don't handle that.
-    return textBreakPreceding(sentenceBreakIterator(text), text.length());
+    return ubrk_preceding(sentenceBreakIterator(text), text.length());
 }
 
 VisiblePosition previousSentencePosition(const VisiblePosition& position)
@@ -1088,7 +1177,7 @@ static unsigned nextSentencePositionBoundary(StringView text, unsigned, Boundary
 {
     // FIXME: This is identical to endSentenceBoundary.
     // That isn't right. This function needs to move to the equivalent position in the following sentence.
-    return textBreakFollowing(sentenceBreakIterator(text), 0);
+    return ubrk_following(sentenceBreakIterator(text), 0);
 }
 
 VisiblePosition nextSentencePosition(const VisiblePosition& position)
@@ -1096,24 +1185,9 @@ VisiblePosition nextSentencePosition(const VisiblePosition& position)
     return position.honorEditingBoundaryAtOrAfter(nextBoundary(position, nextSentencePositionBoundary));
 }
 
-VisiblePosition startOfParagraph(const VisiblePosition& c, EditingBoundaryCrossingRule boundaryCrossingRule)
+Node* findStartOfParagraph(Node* startNode, Node* highestRoot, Node* startBlock, int& offset, Position::AnchorType& type, EditingBoundaryCrossingRule boundaryCrossingRule)
 {
-    Position p = c.deepEquivalent();
-    Node* startNode = p.deprecatedNode();
-
-    if (!startNode)
-        return VisiblePosition();
-    
-    if (isRenderedAsNonInlineTableImageOrHR(startNode))
-        return positionBeforeNode(startNode);
-
-    Node* startBlock = enclosingBlock(startNode);
-
     Node* node = startNode;
-    Node* highestRoot = highestEditableRoot(p);
-    int offset = p.deprecatedEditingOffset();
-    Position::AnchorType type = p.anchorType();
-
     Node* n = startNode;
     while (n) {
 #if ENABLE(USERSELECT_ALL)
@@ -1124,18 +1198,18 @@ VisiblePosition startOfParagraph(const VisiblePosition& c, EditingBoundaryCrossi
             break;
         if (boundaryCrossingRule == CanSkipOverEditingBoundary) {
             while (n && n->hasEditableStyle() != startNode->hasEditableStyle())
-                n = NodeTraversal::previousPostOrder(n, startBlock);
+                n = NodeTraversal::previousPostOrder(*n, startBlock);
             if (!n || !n->isDescendantOf(highestRoot))
                 break;
         }
         RenderObject* r = n->renderer();
         if (!r) {
-            n = NodeTraversal::previousPostOrder(n, startBlock);
+            n = NodeTraversal::previousPostOrder(*n, startBlock);
             continue;
         }
         const RenderStyle& style = r->style();
-        if (style.visibility() != VISIBLE) {
-            n = NodeTraversal::previousPostOrder(n, startBlock);
+        if (style.visibility() != Visibility::Visible) {
+            n = NodeTraversal::previousPostOrder(*n, startBlock);
             continue;
         }
         
@@ -1146,54 +1220,35 @@ VisiblePosition startOfParagraph(const VisiblePosition& c, EditingBoundaryCrossi
             ASSERT_WITH_SECURITY_IMPLICATION(is<Text>(*n));
             type = Position::PositionIsOffsetInAnchor;
             if (style.preserveNewline()) {
-                StringImpl& text = *downcast<RenderText>(*r).text();
+                StringImpl& text = downcast<RenderText>(*r).text();
                 int i = text.length();
                 int o = offset;
                 if (n == startNode && o < i)
                     i = std::max(0, o);
                 while (--i >= 0) {
-                    if (text[i] == '\n')
-                        return VisiblePosition(Position(downcast<Text>(n), i + 1), DOWNSTREAM);
+                    if (text[i] == '\n') {
+                        offset = i + 1;
+                        return n;
+                    }
                 }
             }
             node = n;
             offset = 0;
-            n = NodeTraversal::previousPostOrder(n, startBlock);
-        } else if (editingIgnoresContent(n) || isRenderedTable(n)) {
+            n = NodeTraversal::previousPostOrder(*n, startBlock);
+        } else if (editingIgnoresContent(*n) || isRenderedTable(n)) {
             node = n;
             type = Position::PositionIsBeforeAnchor;
-            n = n->previousSibling() ? n->previousSibling() : NodeTraversal::previousPostOrder(n, startBlock);
+            n = n->previousSibling() ? n->previousSibling() : NodeTraversal::previousPostOrder(*n, startBlock);
         } else
-            n = NodeTraversal::previousPostOrder(n, startBlock);
-    }
-
-    if (type == Position::PositionIsOffsetInAnchor) {
-        ASSERT(type == Position::PositionIsOffsetInAnchor || !offset);
-        return VisiblePosition(Position(node, offset, type), DOWNSTREAM);
+            n = NodeTraversal::previousPostOrder(*n, startBlock);
     }
 
-    return VisiblePosition(Position(node, type), DOWNSTREAM);
+    return node;
 }
 
-VisiblePosition endOfParagraph(const VisiblePosition& c, EditingBoundaryCrossingRule boundaryCrossingRule)
-{    
-    if (c.isNull())
-        return VisiblePosition();
-
-    Position p = c.deepEquivalent();
-    Node* startNode = p.deprecatedNode();
-
-    if (isRenderedAsNonInlineTableImageOrHR(startNode))
-        return positionAfterNode(startNode);
-    
-    Node* startBlock = enclosingBlock(startNode);
-    Node* stayInsideBlock = startBlock;
-    
+Node* findEndOfParagraph(Node* startNode, Node* highestRoot, Node* stayInsideBlock, int& offset, Position::AnchorType& type, EditingBoundaryCrossingRule boundaryCrossingRule)
+{
     Node* node = startNode;
-    Node* highestRoot = highestEditableRoot(p);
-    int offset = p.deprecatedEditingOffset();
-    Position::AnchorType type = p.anchorType();
-
     Node* n = startNode;
     while (n) {
 #if ENABLE(USERSELECT_ALL)
@@ -1204,19 +1259,19 @@ VisiblePosition endOfParagraph(const VisiblePosition& c, EditingBoundaryCrossing
             break;
         if (boundaryCrossingRule == CanSkipOverEditingBoundary) {
             while (n && n->hasEditableStyle() != startNode->hasEditableStyle())
-                n = NodeTraversal::next(n, stayInsideBlock);
+                n = NodeTraversal::next(*n, stayInsideBlock);
             if (!n || !n->isDescendantOf(highestRoot))
                 break;
         }
 
         RenderObject* r = n->renderer();
         if (!r) {
-            n = NodeTraversal::next(n, stayInsideBlock);
+            n = NodeTraversal::next(*n, stayInsideBlock);
             continue;
         }
         const RenderStyle& style = r->style();
-        if (style.visibility() != VISIBLE) {
-            n = NodeTraversal::next(n, stayInsideBlock);
+        if (style.visibility() != Visibility::Visible) {
+            n = NodeTraversal::next(*n, stayInsideBlock);
             continue;
         }
         
@@ -1229,25 +1284,82 @@ VisiblePosition endOfParagraph(const VisiblePosition& c, EditingBoundaryCrossing
             ASSERT_WITH_SECURITY_IMPLICATION(is<Text>(*n));
             type = Position::PositionIsOffsetInAnchor;
             if (style.preserveNewline()) {
-                StringImpl& text = *downcast<RenderText>(*r).text();
+                StringImpl& text = downcast<RenderText>(*r).text();
                 int o = n == startNode ? offset : 0;
                 int length = text.length();
                 for (int i = o; i < length; ++i) {
-                    if (text[i] == '\n')
-                        return VisiblePosition(Position(downcast<Text>(n), i), DOWNSTREAM);
+                    if (text[i] == '\n') {
+                        offset = i;
+                        return n;
+                    }
                 }
             }
             node = n;
             offset = r->caretMaxOffset();
-            n = NodeTraversal::next(n, stayInsideBlock);
-        } else if (editingIgnoresContent(n) || isRenderedTable(n)) {
+            n = NodeTraversal::next(*n, stayInsideBlock);
+        } else if (editingIgnoresContent(*n) || isRenderedTable(n)) {
             node = n;
             type = Position::PositionIsAfterAnchor;
-            n = NodeTraversal::nextSkippingChildren(n, stayInsideBlock);
+            n = NodeTraversal::nextSkippingChildren(*n, stayInsideBlock);
         } else
-            n = NodeTraversal::next(n, stayInsideBlock);
+            n = NodeTraversal::next(*n, stayInsideBlock);
     }
+    return node;
+}
 
+VisiblePosition startOfParagraph(const VisiblePosition& c, EditingBoundaryCrossingRule boundaryCrossingRule)
+{
+    Position p = c.deepEquivalent();
+    auto* startNode = p.deprecatedNode();
+    
+    if (!startNode)
+        return VisiblePosition();
+    
+    if (isRenderedAsNonInlineTableImageOrHR(startNode))
+        return positionBeforeNode(startNode);
+    
+    Node* startBlock = enclosingBlock(startNode);
+    
+    auto* highestRoot = highestEditableRoot(p);
+    int offset = p.deprecatedEditingOffset();
+    Position::AnchorType type = p.anchorType();
+    
+    auto* node = findStartOfParagraph(startNode, highestRoot, startBlock, offset, type, boundaryCrossingRule);
+    
+    if (is<Text>(node))
+        return VisiblePosition(Position(downcast<Text>(node), offset), DOWNSTREAM);
+    
+    if (type == Position::PositionIsOffsetInAnchor) {
+        ASSERT(type == Position::PositionIsOffsetInAnchor || !offset);
+        return VisiblePosition(Position(node, offset, type), DOWNSTREAM);
+    }
+    
+    return VisiblePosition(Position(node, type), DOWNSTREAM);
+}
+
+VisiblePosition endOfParagraph(const VisiblePosition& c, EditingBoundaryCrossingRule boundaryCrossingRule)
+{    
+    if (c.isNull())
+        return VisiblePosition();
+    
+    Position p = c.deepEquivalent();
+    auto* startNode = p.deprecatedNode();
+    
+    if (isRenderedAsNonInlineTableImageOrHR(startNode))
+        return positionAfterNode(startNode);
+    
+    auto* startBlock = enclosingBlock(startNode);
+    auto* stayInsideBlock = startBlock;
+    
+    auto* highestRoot = highestEditableRoot(p);
+    int offset = p.deprecatedEditingOffset();
+    Position::AnchorType type = p.anchorType();
+    
+    auto* node = findEndOfParagraph(startNode, highestRoot, stayInsideBlock, offset, type, boundaryCrossingRule);
+    
+    if (is<Text>(node))
+        return VisiblePosition(Position(downcast<Text>(node), offset), DOWNSTREAM);
+    
     if (type == Position::PositionIsOffsetInAnchor)
         return VisiblePosition(Position(node, offset, type), DOWNSTREAM);
 
@@ -1280,6 +1392,11 @@ bool isEndOfParagraph(const VisiblePosition& pos, EditingBoundaryCrossingRule bo
 {
     return pos.isNotNull() && pos == endOfParagraph(pos, boundaryCrossingRule);
 }
+    
+bool isBlankParagraph(const VisiblePosition& position)
+{
+    return isStartOfParagraph(position) && startOfParagraph(position.next()) != startOfParagraph(position);
+}
 
 VisiblePosition previousParagraphPosition(const VisiblePosition& p, int x)
 {
@@ -1409,18 +1526,18 @@ bool isEndOfDocument(const VisiblePosition& p)
 
 VisiblePosition startOfEditableContent(const VisiblePosition& visiblePosition)
 {
-    Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
+    auto* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
     if (!highestRoot)
-        return VisiblePosition();
+        return { };
 
     return firstPositionInNode(highestRoot);
 }
 
 VisiblePosition endOfEditableContent(const VisiblePosition& visiblePosition)
 {
-    Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
+    auto* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
     if (!highestRoot)
-        return VisiblePosition();
+        return { };
 
     return lastPositionInNode(highestRoot);
 }
@@ -1430,14 +1547,14 @@ bool isEndOfEditableOrNonEditableContent(const VisiblePosition& p)
     return p.isNotNull() && p.next().isNull();
 }
 
-VisiblePosition leftBoundaryOfLine(const VisiblePosition& c, TextDirection direction)
+VisiblePosition leftBoundaryOfLine(const VisiblePosition& c, TextDirection direction, bool* reachedBoundary)
 {
-    return direction == LTR ? logicalStartOfLine(c) : logicalEndOfLine(c);
+    return direction == TextDirection::LTR ? logicalStartOfLine(c, reachedBoundary) : logicalEndOfLine(c, reachedBoundary);
 }
 
-VisiblePosition rightBoundaryOfLine(const VisiblePosition& c, TextDirection direction)
+VisiblePosition rightBoundaryOfLine(const VisiblePosition& c, TextDirection direction, bool* reachedBoundary)
 {
-    return direction == LTR ? logicalEndOfLine(c) : logicalStartOfLine(c);
+    return direction == TextDirection::LTR ? logicalEndOfLine(c, reachedBoundary) : logicalStartOfLine(c, reachedBoundary);
 }
 
 static bool directionIsDownstream(SelectionDirection direction)
@@ -1561,9 +1678,9 @@ bool withinTextUnitOfGranularity(const VisiblePosition& vp, TextGranularity gran
     return (prevBoundary < vp && vp < nextBoundary);
 }
 
-static VisiblePosition nextCharacterBoundaryInDirection(const VisiblePosition& vp, SelectionDirection direction)
+static VisiblePosition nextCharacterBoundaryInDirection(const VisiblePosition& vp, SelectionDirection direction, EditingBoundaryCrossingRule rule)
 {
-    return directionIsDownstream(direction) ? vp.next() : vp.previous();
+    return directionIsDownstream(direction) ? vp.next(rule) : vp.previous(rule);
 }
 
 static VisiblePosition nextWordBoundaryInDirection(const VisiblePosition& vp, SelectionDirection direction)
@@ -1703,7 +1820,7 @@ VisiblePosition positionOfNextBoundaryOfGranularity(const VisiblePosition& vp, T
 {
     switch (granularity) {
     case CharacterGranularity:
-        return nextCharacterBoundaryInDirection(vp, direction);
+        return nextCharacterBoundaryInDirection(vp, direction, CanCrossEditingBoundary);
     case WordGranularity:
         return nextWordBoundaryInDirection(vp, direction);
     case SentenceGranularity:
@@ -1720,11 +1837,11 @@ VisiblePosition positionOfNextBoundaryOfGranularity(const VisiblePosition& vp, T
     }
 }
 
-PassRefPtr<Range> enclosingTextUnitOfGranularity(const VisiblePosition& vp, TextGranularity granularity, SelectionDirection direction)
+RefPtr<Range> enclosingTextUnitOfGranularity(const VisiblePosition& vp, TextGranularity granularity, SelectionDirection direction)
 {
     // This is particularly inefficient.  We could easily obtain the answer with the boundaries computed below.
     if (!withinTextUnitOfGranularity(vp, granularity, direction))
-        return 0;
+        return nullptr;
 
     VisiblePosition prevBoundary;
     VisiblePosition nextBoundary;
@@ -1776,18 +1893,16 @@ PassRefPtr<Range> enclosingTextUnitOfGranularity(const VisiblePosition& vp, Text
 
         default:
             ASSERT_NOT_REACHED();
-            return 0;
+            return nullptr;
     }
 
     if (prevBoundary.isNull() || nextBoundary.isNull())
-        return 0;
+        return nullptr;
 
     if (vp < prevBoundary || vp > nextBoundary)
-        return 0;
-
-    RefPtr<Range> range = Range::create(prevBoundary.deepEquivalent().deprecatedNode()->document(), prevBoundary, nextBoundary);
+        return nullptr;
 
-    return range;
+    return Range::create(prevBoundary.deepEquivalent().deprecatedNode()->document(), prevBoundary, nextBoundary);
 }
 
 int distanceBetweenPositions(const VisiblePosition& vp, const VisiblePosition& other)
@@ -1798,10 +1913,10 @@ int distanceBetweenPositions(const VisiblePosition& vp, const VisiblePosition& o
     bool thisIsStart = (vp < other);
 
     // Start must come first in the Range constructor.
-    RefPtr<Range> range = Range::create(vp.deepEquivalent().deprecatedNode()->document(),
+    auto range = Range::create(vp.deepEquivalent().deprecatedNode()->document(),
                                         (thisIsStart ? vp : other),
                                         (thisIsStart ? other : vp));
-    int distance = TextIterator::rangeLength(range.get());
+    int distance = TextIterator::rangeLength(range.ptr());
 
     return (thisIsStart ? -distance : distance);
 }
@@ -1809,7 +1924,7 @@ int distanceBetweenPositions(const VisiblePosition& vp, const VisiblePosition& o
 void charactersAroundPosition(const VisiblePosition& position, UChar32& oneAfter, UChar32& oneBefore, UChar32& twoBefore)
 {
     const int maxCharacters = 3;
-    Vector<UChar32> characters(maxCharacters);
+    UChar32 characters[maxCharacters] = { 0 };
 
     if (position.isNull() || isStartOfDocument(position))
         return;
@@ -1817,20 +1932,20 @@ void charactersAroundPosition(const VisiblePosition& position, UChar32& oneAfter
     VisiblePosition startPosition = position;
     VisiblePosition endPosition = position;
 
-    VisiblePosition nextPosition = nextCharacterBoundaryInDirection(position, DirectionForward);
+    VisiblePosition nextPosition = nextCharacterBoundaryInDirection(position, DirectionForward, CannotCrossEditingBoundary);
     if (nextPosition.isNotNull())
         endPosition = nextPosition;
 
-    VisiblePosition previousPosition = nextCharacterBoundaryInDirection(position, DirectionBackward);
+    VisiblePosition previousPosition = nextCharacterBoundaryInDirection(position, DirectionBackward, CannotCrossEditingBoundary);
     if (previousPosition.isNotNull()) {
         startPosition = previousPosition;
-        previousPosition = nextCharacterBoundaryInDirection(previousPosition, DirectionBackward);
+        previousPosition = nextCharacterBoundaryInDirection(previousPosition, DirectionBackward, CannotCrossEditingBoundary);
         if (previousPosition.isNotNull())
             startPosition = previousPosition;
     }
 
     if (startPosition != endPosition) {
-        String characterString = plainText(Range::create(position.deepEquivalent().anchorNode()->document(), startPosition, endPosition).get()).replace(noBreakSpace, ' ');
+        String characterString = plainText(Range::create(position.deepEquivalent().anchorNode()->document(), startPosition, endPosition).ptr()).replace(noBreakSpace, ' ');
         for (int i = characterString.length() - 1, index = 0; i >= 0 && index < maxCharacters; --i) {
             if (!index && nextPosition.isNull())
                 index++;
@@ -1842,7 +1957,7 @@ void charactersAroundPosition(const VisiblePosition& position, UChar32& oneAfter
     twoBefore = characters[2];
 }
 
-PassRefPtr<Range> wordRangeFromPosition(const VisiblePosition& position)
+RefPtr<Range> wordRangeFromPosition(const VisiblePosition& position)
 {
     // The selection could be in a non visible element and we don't have a VisiblePosition.
     if (position.isNull())
@@ -1854,6 +1969,7 @@ PassRefPtr<Range> wordRangeFromPosition(const VisiblePosition& position)
         // We could be at the start of a word, try forward.
         range = enclosingTextUnitOfGranularity(position, WordGranularity, DirectionForward);
     }
+
     if (range)
         return range;
 
@@ -1862,18 +1978,6 @@ PassRefPtr<Range> wordRangeFromPosition(const VisiblePosition& position)
         currentPosition = positionOfNextBoundaryOfGranularity(currentPosition, WordGranularity, DirectionBackward);
     } while (currentPosition.isNotNull() && !atBoundaryOfGranularity(currentPosition, WordGranularity, DirectionBackward));
 
-    // If the position is an empty paragraph and at the end of the document
-    // the word iterator could not pass the paragraph boundary, therefore iterating to
-    // the previous line is required.
-    if (currentPosition.isNull() && isEndOfDocument(position)) {
-        VisiblePosition previousLinePosition = positionOfNextBoundaryOfGranularity(position, LineGranularity, DirectionBackward);
-        if (previousLinePosition.isNotNull()) {
-            currentPosition = positionOfNextBoundaryOfGranularity(previousLinePosition, WordGranularity, DirectionBackward);
-            if (currentPosition.isNull())
-                currentPosition = previousLinePosition;
-        }
-    }
-
     if (currentPosition.isNull())
         currentPosition = positionOfNextBoundaryOfGranularity(position, WordGranularity, DirectionForward);
 
@@ -1881,6 +1985,7 @@ PassRefPtr<Range> wordRangeFromPosition(const VisiblePosition& position)
         range = Range::create(position.deepEquivalent().deprecatedNode()->document(), currentPosition, position);
         ASSERT(range);
     }
+
     return range;
 }
 
@@ -1888,7 +1993,7 @@ VisiblePosition closestWordBoundaryForPosition(const VisiblePosition& position)
 {
     VisiblePosition result;
 
-    // move the the position at the end of the word
+    // move the position at the end of the word
     if (atBoundaryOfGranularity(position, LineGranularity, DirectionForward)) {
         // Don't cross line boundaries.
         result = position;
@@ -1914,4 +2019,35 @@ VisiblePosition closestWordBoundaryForPosition(const VisiblePosition& position)
     return result;
 }
 
+RefPtr<Range> rangeExpandedByCharactersInDirectionAtWordBoundary(const VisiblePosition& position, int numberOfCharactersToExpand, SelectionDirection direction)
+{
+    Position start = position.deepEquivalent();
+    Position end = position.deepEquivalent();
+    for (int i = 0; i < numberOfCharactersToExpand; ++i) {
+        if (direction == DirectionBackward)
+            start = start.previous(Character);
+        else
+            end = end.next(Character);
+    }
+    
+    if (direction == DirectionBackward && !atBoundaryOfGranularity(start, WordGranularity, DirectionBackward))
+        start = startOfWord(start).deepEquivalent();
+    if (direction == DirectionForward && !atBoundaryOfGranularity(end, WordGranularity, DirectionForward))
+        end = endOfWord(end).deepEquivalent();
+
+    return makeRange(start, end);
+}    
+
+RefPtr<Range> rangeExpandedAroundPositionByCharacters(const VisiblePosition& position, int numberOfCharactersToExpand)
+{
+    Position start = position.deepEquivalent();
+    Position end = position.deepEquivalent();
+    for (int i = 0; i < numberOfCharactersToExpand; ++i) {
+        start = start.previous(Character);
+        end = end.next(Character);
+    }
+    
+    return makeRange(start, end);
+}    
+
 }