Home | History | Annotate | Download | only in editing
      1 /*
      2  * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
      3  *
      4  * Redistribution and use in source and binary forms, with or without
      5  * modification, are permitted provided that the following conditions
      6  * are met:
      7  * 1. Redistributions of source code must retain the above copyright
      8  *    notice, this list of conditions and the following disclaimer.
      9  * 2. Redistributions in binary form must reproduce the above copyright
     10  *    notice, this list of conditions and the following disclaimer in the
     11  *    documentation and/or other materials provided with the distribution.
     12  *
     13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
     14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
     17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
     18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
     19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
     20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
     21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     24  */
     25 
     26 #include "config.h"
     27 #include "visible_units.h"
     28 
     29 #include "Document.h"
     30 #include "Element.h"
     31 #include "HTMLNames.h"
     32 #include "RenderBlock.h"
     33 #include "RenderLayer.h"
     34 #include "TextBoundaries.h"
     35 #include "TextBreakIterator.h"
     36 #include "TextIterator.h"
     37 #include "VisiblePosition.h"
     38 #include "htmlediting.h"
     39 #include <wtf/unicode/Unicode.h>
     40 
     41 namespace WebCore {
     42 
     43 using namespace HTMLNames;
     44 using namespace WTF::Unicode;
     45 
     46 static int endOfFirstWordBoundaryContext(const UChar* characters, int length)
     47 {
     48     for (int i = 0; i < length; ) {
     49         int first = i;
     50         UChar32 ch;
     51         U16_NEXT(characters, i, length, ch);
     52         if (!requiresContextForWordBoundary(ch))
     53             return first;
     54     }
     55     return length;
     56 }
     57 
     58 static int startOfLastWordBoundaryContext(const UChar* characters, int length)
     59 {
     60     for (int i = length; i > 0; ) {
     61         int last = i;
     62         UChar32 ch;
     63         U16_PREV(characters, 0, i, ch);
     64         if (!requiresContextForWordBoundary(ch))
     65             return last;
     66     }
     67     return 0;
     68 }
     69 
     70 enum BoundarySearchContextAvailability { DontHaveMoreContext, MayHaveMoreContext };
     71 
     72 typedef unsigned (*BoundarySearchFunction)(const UChar*, unsigned length, unsigned offset, BoundarySearchContextAvailability, bool& needMoreContext);
     73 
     74 static VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction)
     75 {
     76     Position pos = c.deepEquivalent();
     77     Node *n = pos.node();
     78     if (!n)
     79         return VisiblePosition();
     80     Document *d = n->document();
     81     Node *de = d->documentElement();
     82     if (!de)
     83         return VisiblePosition();
     84     Node *boundary = n->enclosingBlockFlowElement();
     85     if (!boundary)
     86         return VisiblePosition();
     87     bool isContentEditable = boundary->isContentEditable();
     88     while (boundary && boundary != de && boundary->parentNode() && isContentEditable == boundary->parentNode()->isContentEditable())
     89         boundary = boundary->parentNode();
     90 
     91     Position start = rangeCompliantEquivalent(Position(boundary, 0));
     92     Position end = rangeCompliantEquivalent(pos);
     93     RefPtr<Range> searchRange = Range::create(d);
     94 
     95     Vector<UChar, 1024> string;
     96     unsigned suffixLength = 0;
     97 
     98     ExceptionCode ec = 0;
     99     if (requiresContextForWordBoundary(c.characterBefore())) {
    100         RefPtr<Range> forwardsScanRange(d->createRange());
    101         forwardsScanRange->setEndAfter(boundary, ec);
    102         forwardsScanRange->setStart(end.node(), end.deprecatedEditingOffset(), ec);
    103         TextIterator forwardsIterator(forwardsScanRange.get());
    104         while (!forwardsIterator.atEnd()) {
    105             const UChar* characters = forwardsIterator.characters();
    106             int length = forwardsIterator.length();
    107             int i = endOfFirstWordBoundaryContext(characters, length);
    108             string.append(characters, i);
    109             suffixLength += i;
    110             if (i < length)
    111                 break;
    112             forwardsIterator.advance();
    113         }
    114     }
    115 
    116     searchRange->setStart(start.node(), start.deprecatedEditingOffset(), ec);
    117     searchRange->setEnd(end.node(), end.deprecatedEditingOffset(), ec);
    118 
    119     ASSERT(!ec);
    120     if (ec)
    121         return VisiblePosition();
    122 
    123     SimplifiedBackwardsTextIterator it(searchRange.get());
    124     unsigned next = 0;
    125     bool inTextSecurityMode = start.node() && start.node()->renderer() && start.node()->renderer()->style()->textSecurity() != TSNONE;
    126     bool needMoreContext = false;
    127     while (!it.atEnd()) {
    128         // iterate to get chunks until the searchFunction returns a non-zero value.
    129         if (!inTextSecurityMode)
    130             string.prepend(it.characters(), it.length());
    131         else {
    132             // Treat bullets used in the text security mode as regular characters when looking for boundaries
    133             String iteratorString(it.characters(), it.length());
    134             iteratorString = iteratorString.impl()->secure('x');
    135             string.prepend(iteratorString.characters(), iteratorString.length());
    136         }
    137         next = searchFunction(string.data(), string.size(), string.size() - suffixLength, MayHaveMoreContext, needMoreContext);
    138         if (next != 0)
    139             break;
    140         it.advance();
    141     }
    142     if (needMoreContext) {
    143         // The last search returned the beginning of the buffer and asked for more context,
    144         // but there is no earlier text. Force a search with what's available.
    145         next = searchFunction(string.data(), string.size(), string.size() - suffixLength, DontHaveMoreContext, needMoreContext);
    146         ASSERT(!needMoreContext);
    147     }
    148 
    149     if (it.atEnd() && next == 0) {
    150         pos = it.range()->startPosition();
    151     } else if (next != 0) {
    152         Node *node = it.range()->startContainer(ec);
    153         if ((node->isTextNode() && static_cast<int>(next) <= node->maxCharacterOffset()) || (node->renderer() && node->renderer()->isBR() && !next))
    154             // The next variable contains a usable index into a text node
    155             pos = Position(node, next);
    156         else {
    157             // Use the character iterator to translate the next value into a DOM position.
    158             BackwardsCharacterIterator charIt(searchRange.get());
    159             charIt.advance(string.size() - suffixLength - next);
    160             pos = charIt.range()->endPosition();
    161         }
    162     }
    163 
    164     return VisiblePosition(pos, DOWNSTREAM);
    165 }
    166 
    167 static VisiblePosition nextBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction)
    168 {
    169     Position pos = c.deepEquivalent();
    170     Node *n = pos.node();
    171     if (!n)
    172         return VisiblePosition();
    173     Document *d = n->document();
    174     Node *de = d->documentElement();
    175     if (!de)
    176         return VisiblePosition();
    177     Node *boundary = n->enclosingBlockFlowElement();
    178     if (!boundary)
    179         return VisiblePosition();
    180     bool isContentEditable = boundary->isContentEditable();
    181     while (boundary && boundary != de && boundary->parentNode() && isContentEditable == boundary->parentNode()->isContentEditable())
    182         boundary = boundary->parentNode();
    183 
    184     RefPtr<Range> searchRange(d->createRange());
    185     Position start(rangeCompliantEquivalent(pos));
    186 
    187     Vector<UChar, 1024> string;
    188     unsigned prefixLength = 0;
    189 
    190     ExceptionCode ec = 0;
    191     if (requiresContextForWordBoundary(c.characterAfter())) {
    192         RefPtr<Range> backwardsScanRange(d->createRange());
    193         backwardsScanRange->setEnd(start.node(), start.deprecatedEditingOffset(), ec);
    194         SimplifiedBackwardsTextIterator backwardsIterator(backwardsScanRange.get());
    195         while (!backwardsIterator.atEnd()) {
    196             const UChar* characters = backwardsIterator.characters();
    197             int length = backwardsIterator.length();
    198             int i = startOfLastWordBoundaryContext(characters, length);
    199             string.prepend(characters + i, length - i);
    200             prefixLength += length - i;
    201             if (i > 0)
    202                 break;
    203             backwardsIterator.advance();
    204         }
    205     }
    206 
    207     searchRange->selectNodeContents(boundary, ec);
    208     searchRange->setStart(start.node(), start.deprecatedEditingOffset(), ec);
    209     TextIterator it(searchRange.get(), true);
    210     unsigned next = 0;
    211     bool inTextSecurityMode = start.node() && start.node()->renderer() && start.node()->renderer()->style()->textSecurity() != TSNONE;
    212     bool needMoreContext = false;
    213     while (!it.atEnd()) {
    214         // Keep asking the iterator for chunks until the search function
    215         // returns an end value not equal to the length of the string passed to it.
    216         if (!inTextSecurityMode)
    217             string.append(it.characters(), it.length());
    218         else {
    219             // Treat bullets used in the text security mode as regular characters when looking for boundaries
    220             String iteratorString(it.characters(), it.length());
    221             iteratorString = iteratorString.impl()->secure('x');
    222             string.append(iteratorString.characters(), iteratorString.length());
    223         }
    224         next = searchFunction(string.data(), string.size(), prefixLength, MayHaveMoreContext, needMoreContext);
    225         if (next != string.size())
    226             break;
    227         it.advance();
    228     }
    229     if (needMoreContext) {
    230         // The last search returned the end of the buffer and asked for more context,
    231         // but there is no further text. Force a search with what's available.
    232         next = searchFunction(string.data(), string.size(), prefixLength, DontHaveMoreContext, needMoreContext);
    233         ASSERT(!needMoreContext);
    234     }
    235 
    236     if (it.atEnd() && next == string.size()) {
    237         pos = it.range()->startPosition();
    238     } else if (next != prefixLength) {
    239         // Use the character iterator to translate the next value into a DOM position.
    240         CharacterIterator charIt(searchRange.get(), true);
    241         charIt.advance(next - prefixLength - 1);
    242         pos = charIt.range()->endPosition();
    243 
    244         if (*charIt.characters() == '\n') {
    245             // FIXME: workaround for collapsed range (where only start position is correct) emitted for some emitted newlines (see rdar://5192593)
    246             VisiblePosition visPos = VisiblePosition(pos);
    247             if (visPos == VisiblePosition(charIt.range()->startPosition()))
    248                 pos = visPos.next(true).deepEquivalent();
    249         }
    250     }
    251 
    252     // generate VisiblePosition, use UPSTREAM affinity if possible
    253     return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE);
    254 }
    255 
    256 // ---------
    257 
    258 static unsigned startWordBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
    259 {
    260     ASSERT(offset);
    261     if (mayHaveMoreContext && !startOfLastWordBoundaryContext(characters, offset)) {
    262         needMoreContext = true;
    263         return 0;
    264     }
    265     needMoreContext = false;
    266     int start, end;
    267     findWordBoundary(characters, length, offset - 1, &start, &end);
    268     return start;
    269 }
    270 
    271 VisiblePosition startOfWord(const VisiblePosition &c, EWordSide side)
    272 {
    273     // FIXME: This returns a null VP for c at the start of the document
    274     // and side == LeftWordIfOnBoundary
    275     VisiblePosition p = c;
    276     if (side == RightWordIfOnBoundary) {
    277         // at paragraph end, the startofWord is the current position
    278         if (isEndOfParagraph(c))
    279             return c;
    280 
    281         p = c.next();
    282         if (p.isNull())
    283             return c;
    284     }
    285     return previousBoundary(p, startWordBoundary);
    286 }
    287 
    288 static unsigned endWordBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
    289 {
    290     ASSERT(offset <= length);
    291     if (mayHaveMoreContext && endOfFirstWordBoundaryContext(characters + offset, length - offset) == static_cast<int>(length - offset)) {
    292         needMoreContext = true;
    293         return length;
    294     }
    295     needMoreContext = false;
    296     int start, end;
    297     findWordBoundary(characters, length, offset, &start, &end);
    298     return end;
    299 }
    300 
    301 VisiblePosition endOfWord(const VisiblePosition &c, EWordSide side)
    302 {
    303     VisiblePosition p = c;
    304     if (side == LeftWordIfOnBoundary) {
    305         if (isStartOfParagraph(c))
    306             return c;
    307 
    308         p = c.previous();
    309         if (p.isNull())
    310             return c;
    311     } else if (isEndOfParagraph(c))
    312         return c;
    313 
    314     return nextBoundary(p, endWordBoundary);
    315 }
    316 
    317 static unsigned previousWordPositionBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
    318 {
    319     if (mayHaveMoreContext && !startOfLastWordBoundaryContext(characters, offset)) {
    320         needMoreContext = true;
    321         return 0;
    322     }
    323     needMoreContext = false;
    324     return findNextWordFromIndex(characters, length, offset, false);
    325 }
    326 
    327 VisiblePosition previousWordPosition(const VisiblePosition &c)
    328 {
    329     VisiblePosition prev = previousBoundary(c, previousWordPositionBoundary);
    330     return c.honorEditableBoundaryAtOrAfter(prev);
    331 }
    332 
    333 static unsigned nextWordPositionBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
    334 {
    335     if (mayHaveMoreContext && endOfFirstWordBoundaryContext(characters + offset, length - offset) == static_cast<int>(length - offset)) {
    336         needMoreContext = true;
    337         return length;
    338     }
    339     needMoreContext = false;
    340     return findNextWordFromIndex(characters, length, offset, true);
    341 }
    342 
    343 VisiblePosition nextWordPosition(const VisiblePosition &c)
    344 {
    345     VisiblePosition next = nextBoundary(c, nextWordPositionBoundary);
    346     return c.honorEditableBoundaryAtOrBefore(next);
    347 }
    348 
    349 // ---------
    350 
    351 static RootInlineBox *rootBoxForLine(const VisiblePosition &c)
    352 {
    353     Position p = c.deepEquivalent();
    354     Node *node = p.node();
    355     if (!node)
    356         return 0;
    357 
    358     RenderObject *renderer = node->renderer();
    359     if (!renderer)
    360         return 0;
    361 
    362     InlineBox* box;
    363     int offset;
    364     c.getInlineBoxAndOffset(box, offset);
    365 
    366     return box ? box->root() : 0;
    367 }
    368 
    369 static VisiblePosition positionAvoidingFirstPositionInTable(const VisiblePosition& c)
    370 {
    371     // return table offset 0 instead of the first VisiblePosition inside the table
    372     VisiblePosition previous = c.previous();
    373     if (isLastPositionBeforeTable(previous))
    374         return previous;
    375 
    376     return c;
    377 }
    378 
    379 static VisiblePosition startPositionForLine(const VisiblePosition& c)
    380 {
    381     if (c.isNull())
    382         return VisiblePosition();
    383 
    384     RootInlineBox *rootBox = rootBoxForLine(c);
    385     if (!rootBox) {
    386         // There are VisiblePositions at offset 0 in blocks without
    387         // RootInlineBoxes, like empty editable blocks and bordered blocks.
    388         Position p = c.deepEquivalent();
    389         if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && p.deprecatedEditingOffset() == 0)
    390             return positionAvoidingFirstPositionInTable(c);
    391 
    392         return VisiblePosition();
    393     }
    394 
    395     // Generated content (e.g. list markers and CSS :before and :after
    396     // pseudoelements) have no corresponding DOM element, and so cannot be
    397     // represented by a VisiblePosition.  Use whatever follows instead.
    398     InlineBox *startBox = rootBox->firstLeafChild();
    399     Node *startNode;
    400     while (1) {
    401         if (!startBox)
    402             return VisiblePosition();
    403 
    404         RenderObject *startRenderer = startBox->renderer();
    405         if (!startRenderer)
    406             return VisiblePosition();
    407 
    408         startNode = startRenderer->node();
    409         if (startNode)
    410             break;
    411 
    412         startBox = startBox->nextLeafChild();
    413     }
    414 
    415     int startOffset = 0;
    416     if (startBox->isInlineTextBox()) {
    417         InlineTextBox *startTextBox = static_cast<InlineTextBox *>(startBox);
    418         startOffset = startTextBox->start();
    419     }
    420 
    421     VisiblePosition visPos = VisiblePosition(startNode, startOffset, DOWNSTREAM);
    422     return positionAvoidingFirstPositionInTable(visPos);
    423 }
    424 
    425 VisiblePosition startOfLine(const VisiblePosition& c)
    426 {
    427     VisiblePosition visPos = startPositionForLine(c);
    428 
    429     if (visPos.isNotNull()) {
    430         // Make sure the start of line is not greater than the given input position.  Else use the previous position to
    431         // obtain start of line.  This condition happens when the input position is before the space character at the end
    432         // of a soft-wrapped non-editable line. In this scenario, startPositionForLine would incorrectly hand back a position
    433         // greater than the input position.  This fix is to account for the discrepancy between lines with webkit-line-break:after-white-space
    434         // style versus lines without that style, which would break before a space by default.
    435         Position p = visPos.deepEquivalent();
    436         if (p.deprecatedEditingOffset() > c.deepEquivalent().deprecatedEditingOffset() && p.node()->isSameNode(c.deepEquivalent().node())) {
    437             visPos = c.previous();
    438             if (visPos.isNull())
    439                 return VisiblePosition();
    440             visPos = startPositionForLine(visPos);
    441         }
    442     }
    443 
    444     return c.honorEditableBoundaryAtOrAfter(visPos);
    445 }
    446 
    447 static VisiblePosition endPositionForLine(const VisiblePosition& c)
    448 {
    449     if (c.isNull())
    450         return VisiblePosition();
    451 
    452     RootInlineBox *rootBox = rootBoxForLine(c);
    453     if (!rootBox) {
    454         // There are VisiblePositions at offset 0 in blocks without
    455         // RootInlineBoxes, like empty editable blocks and bordered blocks.
    456         Position p = c.deepEquivalent();
    457         if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && p.deprecatedEditingOffset() == 0)
    458             return c;
    459         return VisiblePosition();
    460     }
    461 
    462     // Generated content (e.g. list markers and CSS :before and :after
    463     // pseudoelements) have no corresponding DOM element, and so cannot be
    464     // represented by a VisiblePosition.  Use whatever precedes instead.
    465     Node *endNode;
    466     InlineBox *endBox = rootBox->lastLeafChild();
    467     while (1) {
    468         if (!endBox)
    469             return VisiblePosition();
    470 
    471         RenderObject *endRenderer = endBox->renderer();
    472         if (!endRenderer)
    473             return VisiblePosition();
    474 
    475         endNode = endRenderer->node();
    476         if (endNode)
    477             break;
    478 
    479         endBox = endBox->prevLeafChild();
    480     }
    481 
    482     int endOffset = 1;
    483     if (endNode->hasTagName(brTag)) {
    484         endOffset = 0;
    485     } else if (endBox->isInlineTextBox()) {
    486         InlineTextBox *endTextBox = static_cast<InlineTextBox *>(endBox);
    487         endOffset = endTextBox->start();
    488         if (!endTextBox->isLineBreak())
    489             endOffset += endTextBox->len();
    490     }
    491 
    492     return VisiblePosition(endNode, endOffset, VP_UPSTREAM_IF_POSSIBLE);
    493 }
    494 
    495 VisiblePosition endOfLine(const VisiblePosition& c)
    496 {
    497     VisiblePosition visPos = endPositionForLine(c);
    498 
    499     // Make sure the end of line is at the same line as the given input position.  Else use the previous position to
    500     // obtain end of line.  This condition happens when the input position is before the space character at the end
    501     // of a soft-wrapped non-editable line. In this scenario, endPositionForLine would incorrectly hand back a position
    502     // in the next line instead. This fix is to account for the discrepancy between lines with webkit-line-break:after-white-space style
    503     // versus lines without that style, which would break before a space by default.
    504     if (!inSameLine(c, visPos)) {
    505         visPos = c.previous();
    506         if (visPos.isNull())
    507             return VisiblePosition();
    508         visPos = endPositionForLine(visPos);
    509     }
    510 
    511     return c.honorEditableBoundaryAtOrBefore(visPos);
    512 }
    513 
    514 bool inSameLine(const VisiblePosition &a, const VisiblePosition &b)
    515 {
    516     return a.isNotNull() && startOfLine(a) == startOfLine(b);
    517 }
    518 
    519 bool isStartOfLine(const VisiblePosition &p)
    520 {
    521     return p.isNotNull() && p == startOfLine(p);
    522 }
    523 
    524 bool isEndOfLine(const VisiblePosition &p)
    525 {
    526     return p.isNotNull() && p == endOfLine(p);
    527 }
    528 
    529 // The first leaf before node that has the same editability as node.
    530 static Node* previousLeafWithSameEditability(Node* node)
    531 {
    532     bool editable = node->isContentEditable();
    533     Node* n = node->previousLeafNode();
    534     while (n) {
    535         if (editable == n->isContentEditable())
    536             return n;
    537         n = n->previousLeafNode();
    538     }
    539     return 0;
    540 }
    541 
    542 static Node* enclosingNodeWithNonInlineRenderer(Node* n)
    543 {
    544     for (Node* p = n; p; p = p->parentNode()) {
    545         if (p->renderer() && !p->renderer()->isInline())
    546             return p;
    547     }
    548     return 0;
    549 }
    550 
    551 VisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int x)
    552 {
    553     Position p = visiblePosition.deepEquivalent();
    554     Node *node = p.node();
    555     Node* highestRoot = highestEditableRoot(p);
    556     if (!node)
    557         return VisiblePosition();
    558 
    559     node->document()->updateLayoutIgnorePendingStylesheets();
    560 
    561     RenderObject *renderer = node->renderer();
    562     if (!renderer)
    563         return VisiblePosition();
    564 
    565     RenderBlock *containingBlock = 0;
    566     RootInlineBox *root = 0;
    567     InlineBox* box;
    568     int ignoredCaretOffset;
    569     visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
    570     if (box) {
    571         root = box->root()->prevRootBox();
    572         if (root)
    573             containingBlock = renderer->containingBlock();
    574     }
    575 
    576     if (!root) {
    577         // This containing editable block does not have a previous line.
    578         // Need to move back to previous containing editable block in this root editable
    579         // block and find the last root line box in that block.
    580         Node* startBlock = enclosingNodeWithNonInlineRenderer(node);
    581         Node* n = previousLeafWithSameEditability(node);
    582         while (n && startBlock == enclosingNodeWithNonInlineRenderer(n))
    583             n = previousLeafWithSameEditability(n);
    584         while (n) {
    585             if (highestEditableRoot(Position(n, 0)) != highestRoot)
    586                 break;
    587             Position pos(n, caretMinOffset(n));
    588             if (pos.isCandidate()) {
    589                 ASSERT(n->renderer());
    590                 Position maxPos(n, caretMaxOffset(n));
    591                 maxPos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
    592                 if (box) {
    593                     // previous root line box found
    594                     root = box->root();
    595                     containingBlock = n->renderer()->containingBlock();
    596                     break;
    597                 }
    598 
    599                 return VisiblePosition(pos, DOWNSTREAM);
    600             }
    601             n = previousLeafWithSameEditability(n);
    602         }
    603     }
    604 
    605     if (root) {
    606         // FIXME: Can be wrong for multi-column layout and with transforms.
    607         FloatPoint absPos = containingBlock->localToAbsolute(FloatPoint());
    608         if (containingBlock->hasOverflowClip())
    609             absPos -= containingBlock->layer()->scrolledContentOffset();
    610         RenderObject* renderer = root->closestLeafChildForXPos(x - absPos.x(), isEditablePosition(p))->renderer();
    611         Node* node = renderer->node();
    612         if (node && editingIgnoresContent(node))
    613             return Position(node->parent(), node->nodeIndex());
    614         return renderer->positionForPoint(IntPoint(x - absPos.x(), root->lineTop()));
    615     }
    616 
    617     // Could not find a previous line. This means we must already be on the first line.
    618     // Move to the start of the content in this block, which effectively moves us
    619     // to the start of the line we're on.
    620     Element* rootElement = node->isContentEditable() ? node->rootEditableElement() : node->document()->documentElement();
    621     return VisiblePosition(rootElement, 0, DOWNSTREAM);
    622 }
    623 
    624 static Node* nextLeafWithSameEditability(Node* node, int offset)
    625 {
    626     bool editable = node->isContentEditable();
    627     ASSERT(offset >= 0);
    628     Node* child = node->childNode(offset);
    629     Node* n = child ? child->nextLeafNode() : node->nextLeafNode();
    630     while (n) {
    631         if (editable == n->isContentEditable())
    632             return n;
    633         n = n->nextLeafNode();
    634     }
    635     return 0;
    636 }
    637 
    638 static Node* nextLeafWithSameEditability(Node* node)
    639 {
    640     if (!node)
    641         return 0;
    642 
    643     bool editable = node->isContentEditable();
    644     Node* n = node->nextLeafNode();
    645     while (n) {
    646         if (editable == n->isContentEditable())
    647             return n;
    648         n = n->nextLeafNode();
    649     }
    650     return 0;
    651 }
    652 
    653 VisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
    654 {
    655     Position p = visiblePosition.deepEquivalent();
    656     Node *node = p.node();
    657     Node* highestRoot = highestEditableRoot(p);
    658     if (!node)
    659         return VisiblePosition();
    660 
    661     node->document()->updateLayoutIgnorePendingStylesheets();
    662 
    663     RenderObject *renderer = node->renderer();
    664     if (!renderer)
    665         return VisiblePosition();
    666 
    667     RenderBlock *containingBlock = 0;
    668     RootInlineBox *root = 0;
    669     InlineBox* box;
    670     int ignoredCaretOffset;
    671     visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
    672     if (box) {
    673         root = box->root()->nextRootBox();
    674         if (root)
    675             containingBlock = renderer->containingBlock();
    676     }
    677 
    678     if (!root) {
    679         // This containing editable block does not have a next line.
    680         // Need to move forward to next containing editable block in this root editable
    681         // block and find the first root line box in that block.
    682         Node* startBlock = enclosingNodeWithNonInlineRenderer(node);
    683         Node* n = nextLeafWithSameEditability(node, p.deprecatedEditingOffset());
    684         while (n && startBlock == enclosingNodeWithNonInlineRenderer(n))
    685             n = nextLeafWithSameEditability(n);
    686         while (n) {
    687             if (highestEditableRoot(Position(n, 0)) != highestRoot)
    688                 break;
    689             Position pos(n, caretMinOffset(n));
    690             if (pos.isCandidate()) {
    691                 ASSERT(n->renderer());
    692                 pos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
    693                 if (box) {
    694                     // next root line box found
    695                     root = box->root();
    696                     containingBlock = n->renderer()->containingBlock();
    697                     break;
    698                 }
    699 
    700                 return VisiblePosition(pos, DOWNSTREAM);
    701             }
    702             n = nextLeafWithSameEditability(n);
    703         }
    704     }
    705 
    706     if (root) {
    707         // FIXME: Can be wrong for multi-column layout and with transforms.
    708         FloatPoint absPos = containingBlock->localToAbsolute(FloatPoint());
    709         if (containingBlock->hasOverflowClip())
    710             absPos -= containingBlock->layer()->scrolledContentOffset();
    711         RenderObject* renderer = root->closestLeafChildForXPos(x - absPos.x(), isEditablePosition(p))->renderer();
    712         Node* node = renderer->node();
    713         if (node && editingIgnoresContent(node))
    714             return Position(node->parent(), node->nodeIndex());
    715         return renderer->positionForPoint(IntPoint(x - absPos.x(), root->lineTop()));
    716     }
    717 
    718     // Could not find a next line. This means we must already be on the last line.
    719     // Move to the end of the content in this block, which effectively moves us
    720     // to the end of the line we're on.
    721     Element* rootElement = node->isContentEditable() ? node->rootEditableElement() : node->document()->documentElement();
    722     return VisiblePosition(rootElement, rootElement ? rootElement->childNodeCount() : 0, DOWNSTREAM);
    723 }
    724 
    725 // ---------
    726 
    727 static unsigned startSentenceBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&)
    728 {
    729     TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
    730     // FIXME: The following function can return -1; we don't handle that.
    731     return textBreakPreceding(iterator, length);
    732 }
    733 
    734 VisiblePosition startOfSentence(const VisiblePosition &c)
    735 {
    736     return previousBoundary(c, startSentenceBoundary);
    737 }
    738 
    739 static unsigned endSentenceBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&)
    740 {
    741     TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
    742     return textBreakNext(iterator);
    743 }
    744 
    745 // FIXME: This includes the space after the punctuation that marks the end of the sentence.
    746 VisiblePosition endOfSentence(const VisiblePosition &c)
    747 {
    748     return nextBoundary(c, endSentenceBoundary);
    749 }
    750 
    751 static unsigned previousSentencePositionBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&)
    752 {
    753     // FIXME: This is identical to startSentenceBoundary. I'm pretty sure that's not right.
    754     TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
    755     // FIXME: The following function can return -1; we don't handle that.
    756     return textBreakPreceding(iterator, length);
    757 }
    758 
    759 VisiblePosition previousSentencePosition(const VisiblePosition &c)
    760 {
    761     VisiblePosition prev = previousBoundary(c, previousSentencePositionBoundary);
    762     return c.honorEditableBoundaryAtOrAfter(prev);
    763 }
    764 
    765 static unsigned nextSentencePositionBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&)
    766 {
    767     // FIXME: This is identical to endSentenceBoundary.  This isn't right, it needs to
    768     // move to the equivlant position in the following sentence.
    769     TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
    770     return textBreakFollowing(iterator, 0);
    771 }
    772 
    773 VisiblePosition nextSentencePosition(const VisiblePosition &c)
    774 {
    775     VisiblePosition next = nextBoundary(c, nextSentencePositionBoundary);
    776     return c.honorEditableBoundaryAtOrBefore(next);
    777 }
    778 
    779 VisiblePosition startOfParagraph(const VisiblePosition& c)
    780 {
    781     Position p = c.deepEquivalent();
    782     Node *startNode = p.node();
    783 
    784     if (!startNode)
    785         return VisiblePosition();
    786 
    787     if (isRenderedAsNonInlineTableImageOrHR(startNode))
    788         return firstDeepEditingPositionForNode(startNode);
    789 
    790     Node* startBlock = enclosingBlock(startNode);
    791 
    792     Node *node = startNode;
    793     int offset = p.deprecatedEditingOffset();
    794 
    795     Node *n = startNode;
    796     while (n) {
    797         if (n->isContentEditable() != startNode->isContentEditable())
    798             break;
    799         RenderObject *r = n->renderer();
    800         if (!r) {
    801             n = n->traversePreviousNodePostOrder(startBlock);
    802             continue;
    803         }
    804         RenderStyle *style = r->style();
    805         if (style->visibility() != VISIBLE) {
    806             n = n->traversePreviousNodePostOrder(startBlock);
    807             continue;
    808         }
    809 
    810         if (r->isBR() || isBlock(n))
    811             break;
    812 
    813         if (r->isText()) {
    814             if (style->preserveNewline()) {
    815                 const UChar* chars = toRenderText(r)->characters();
    816                 int i = toRenderText(r)->textLength();
    817                 int o = offset;
    818                 if (n == startNode && o < i)
    819                     i = max(0, o);
    820                 while (--i >= 0)
    821                     if (chars[i] == '\n')
    822                         return VisiblePosition(n, i + 1, DOWNSTREAM);
    823             }
    824             node = n;
    825             offset = 0;
    826             n = n->traversePreviousNodePostOrder(startBlock);
    827         } else if (editingIgnoresContent(n) || isTableElement(n)) {
    828             node = n;
    829             offset = 0;
    830             n = n->previousSibling() ? n->previousSibling() : n->traversePreviousNodePostOrder(startBlock);
    831         } else
    832             n = n->traversePreviousNodePostOrder(startBlock);
    833     }
    834 
    835     return VisiblePosition(node, offset, DOWNSTREAM);
    836 }
    837 
    838 VisiblePosition endOfParagraph(const VisiblePosition &c)
    839 {
    840     if (c.isNull())
    841         return VisiblePosition();
    842 
    843     Position p = c.deepEquivalent();
    844     Node* startNode = p.node();
    845 
    846     if (isRenderedAsNonInlineTableImageOrHR(startNode))
    847         return lastDeepEditingPositionForNode(startNode);
    848 
    849     Node* startBlock = enclosingBlock(startNode);
    850     Node *stayInsideBlock = startBlock;
    851 
    852     Node *node = startNode;
    853     int offset = p.deprecatedEditingOffset();
    854 
    855     Node *n = startNode;
    856     while (n) {
    857         if (n->isContentEditable() != startNode->isContentEditable())
    858             break;
    859         RenderObject *r = n->renderer();
    860         if (!r) {
    861             n = n->traverseNextNode(stayInsideBlock);
    862             continue;
    863         }
    864         RenderStyle *style = r->style();
    865         if (style->visibility() != VISIBLE) {
    866             n = n->traverseNextNode(stayInsideBlock);
    867             continue;
    868         }
    869 
    870         if (r->isBR() || isBlock(n))
    871             break;
    872 
    873         // FIXME: We avoid returning a position where the renderer can't accept the caret.
    874         // We should probably do this in other cases such as startOfParagraph.
    875         if (r->isText() && r->caretMaxRenderedOffset() > 0) {
    876             int length = toRenderText(r)->textLength();
    877             if (style->preserveNewline()) {
    878                 const UChar* chars = toRenderText(r)->characters();
    879                 int o = n == startNode ? offset : 0;
    880                 for (int i = o; i < length; ++i)
    881                     if (chars[i] == '\n')
    882                         return VisiblePosition(n, i, DOWNSTREAM);
    883             }
    884             node = n;
    885             offset = r->caretMaxOffset();
    886             n = n->traverseNextNode(stayInsideBlock);
    887         } else if (editingIgnoresContent(n) || isTableElement(n)) {
    888             node = n;
    889             offset = lastOffsetForEditing(n);
    890             n = n->traverseNextSibling(stayInsideBlock);
    891         } else
    892             n = n->traverseNextNode(stayInsideBlock);
    893     }
    894 
    895     return VisiblePosition(node, offset, DOWNSTREAM);
    896 }
    897 
    898 VisiblePosition startOfNextParagraph(const VisiblePosition& visiblePosition)
    899 {
    900     VisiblePosition paragraphEnd(endOfParagraph(visiblePosition));
    901     VisiblePosition afterParagraphEnd(paragraphEnd.next(true));
    902     // The position after the last position in the last cell of a table
    903     // is not the start of the next paragraph.
    904     if (isFirstPositionAfterTable(afterParagraphEnd))
    905         return afterParagraphEnd.next(true);
    906     return afterParagraphEnd;
    907 }
    908 
    909 bool inSameParagraph(const VisiblePosition &a, const VisiblePosition &b)
    910 {
    911     return a.isNotNull() && startOfParagraph(a) == startOfParagraph(b);
    912 }
    913 
    914 bool isStartOfParagraph(const VisiblePosition &pos)
    915 {
    916     return pos.isNotNull() && pos == startOfParagraph(pos);
    917 }
    918 
    919 bool isEndOfParagraph(const VisiblePosition &pos)
    920 {
    921     return pos.isNotNull() && pos == endOfParagraph(pos);
    922 }
    923 
    924 VisiblePosition previousParagraphPosition(const VisiblePosition& p, int x)
    925 {
    926     VisiblePosition pos = p;
    927     do {
    928         VisiblePosition n = previousLinePosition(pos, x);
    929         if (n.isNull() || n == pos)
    930             break;
    931         pos = n;
    932     } while (inSameParagraph(p, pos));
    933     return pos;
    934 }
    935 
    936 VisiblePosition nextParagraphPosition(const VisiblePosition& p, int x)
    937 {
    938     VisiblePosition pos = p;
    939     do {
    940         VisiblePosition n = nextLinePosition(pos, x);
    941         if (n.isNull() || n == pos)
    942             break;
    943         pos = n;
    944     } while (inSameParagraph(p, pos));
    945     return pos;
    946 }
    947 
    948 // ---------
    949 
    950 VisiblePosition startOfBlock(const VisiblePosition &c)
    951 {
    952     Position p = c.deepEquivalent();
    953     Node *startNode = p.node();
    954     if (!startNode)
    955         return VisiblePosition();
    956     return VisiblePosition(Position(startNode->enclosingBlockFlowElement(), 0), DOWNSTREAM);
    957 }
    958 
    959 VisiblePosition endOfBlock(const VisiblePosition &c)
    960 {
    961     Position p = c.deepEquivalent();
    962 
    963     Node *startNode = p.node();
    964     if (!startNode)
    965         return VisiblePosition();
    966 
    967     Node *startBlock = startNode->enclosingBlockFlowElement();
    968 
    969     return VisiblePosition(startBlock, startBlock->childNodeCount(), VP_DEFAULT_AFFINITY);
    970 }
    971 
    972 bool inSameBlock(const VisiblePosition &a, const VisiblePosition &b)
    973 {
    974     return !a.isNull() && enclosingBlockFlowElement(a) == enclosingBlockFlowElement(b);
    975 }
    976 
    977 bool isStartOfBlock(const VisiblePosition &pos)
    978 {
    979     return pos.isNotNull() && pos == startOfBlock(pos);
    980 }
    981 
    982 bool isEndOfBlock(const VisiblePosition &pos)
    983 {
    984     return pos.isNotNull() && pos == endOfBlock(pos);
    985 }
    986 
    987 // ---------
    988 
    989 VisiblePosition startOfDocument(const Node* node)
    990 {
    991     if (!node)
    992         return VisiblePosition();
    993 
    994     return VisiblePosition(node->document()->documentElement(), 0, DOWNSTREAM);
    995 }
    996 
    997 VisiblePosition startOfDocument(const VisiblePosition &c)
    998 {
    999     return startOfDocument(c.deepEquivalent().node());
   1000 }
   1001 
   1002 VisiblePosition endOfDocument(const Node* node)
   1003 {
   1004     if (!node || !node->document())
   1005         return VisiblePosition();
   1006 
   1007     Element* doc = node->document()->documentElement();
   1008     return VisiblePosition(doc, doc->childNodeCount(), DOWNSTREAM);
   1009 }
   1010 
   1011 VisiblePosition endOfDocument(const VisiblePosition &c)
   1012 {
   1013     return endOfDocument(c.deepEquivalent().node());
   1014 }
   1015 
   1016 bool inSameDocument(const VisiblePosition &a, const VisiblePosition &b)
   1017 {
   1018     Position ap = a.deepEquivalent();
   1019     Node *an = ap.node();
   1020     if (!an)
   1021         return false;
   1022     Position bp = b.deepEquivalent();
   1023     Node *bn = bp.node();
   1024     if (an == bn)
   1025         return true;
   1026 
   1027     return an->document() == bn->document();
   1028 }
   1029 
   1030 bool isStartOfDocument(const VisiblePosition &p)
   1031 {
   1032     return p.isNotNull() && p.previous().isNull();
   1033 }
   1034 
   1035 bool isEndOfDocument(const VisiblePosition &p)
   1036 {
   1037     return p.isNotNull() && p.next().isNull();
   1038 }
   1039 
   1040 // ---------
   1041 
   1042 VisiblePosition startOfEditableContent(const VisiblePosition& visiblePosition)
   1043 {
   1044     Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
   1045     if (!highestRoot)
   1046         return VisiblePosition();
   1047 
   1048     return firstDeepEditingPositionForNode(highestRoot);
   1049 }
   1050 
   1051 VisiblePosition endOfEditableContent(const VisiblePosition& visiblePosition)
   1052 {
   1053     Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
   1054     if (!highestRoot)
   1055         return VisiblePosition();
   1056 
   1057     return lastDeepEditingPositionForNode(highestRoot);
   1058 }
   1059 
   1060 static void getLeafBoxesInLogicalOrder(RootInlineBox* rootBox, Vector<InlineBox*>& leafBoxesInLogicalOrder)
   1061 {
   1062     unsigned char minLevel = 128;
   1063     unsigned char maxLevel = 0;
   1064     unsigned count = 0;
   1065     InlineBox* r = rootBox->firstLeafChild();
   1066     // First find highest and lowest levels,
   1067     // and initialize leafBoxesInLogicalOrder with the leaf boxes in visual order.
   1068     while (r) {
   1069         if (r->bidiLevel() > maxLevel)
   1070             maxLevel = r->bidiLevel();
   1071         if (r->bidiLevel() < minLevel)
   1072             minLevel = r->bidiLevel();
   1073         leafBoxesInLogicalOrder.append(r);
   1074         r = r->nextLeafChild();
   1075         ++count;
   1076     }
   1077 
   1078     if (rootBox->renderer()->style()->visuallyOrdered())
   1079         return;
   1080     // Reverse of reordering of the line (L2 according to Bidi spec):
   1081     // L2. From the highest level found in the text to the lowest odd level on each line,
   1082     // reverse any contiguous sequence of characters that are at that level or higher.
   1083 
   1084     // Reversing the reordering of the line is only done up to the lowest odd level.
   1085     if (!(minLevel % 2))
   1086         minLevel++;
   1087 
   1088     InlineBox** end = leafBoxesInLogicalOrder.end();
   1089     while (minLevel <= maxLevel) {
   1090         InlineBox** iter = leafBoxesInLogicalOrder.begin();
   1091         while (iter != end) {
   1092             while (iter != end) {
   1093                 if ((*iter)->bidiLevel() >= minLevel)
   1094                     break;
   1095                 ++iter;
   1096             }
   1097             InlineBox** first = iter;
   1098             while (iter != end) {
   1099                 if ((*iter)->bidiLevel() < minLevel)
   1100                     break;
   1101                 ++iter;
   1102             }
   1103             InlineBox** last = iter;
   1104             std::reverse(first, last);
   1105         }
   1106         ++minLevel;
   1107     }
   1108 }
   1109 
   1110 static void getLogicalStartBoxAndNode(RootInlineBox* rootBox, InlineBox*& startBox, Node*& startNode)
   1111 {
   1112     Vector<InlineBox*> leafBoxesInLogicalOrder;
   1113     getLeafBoxesInLogicalOrder(rootBox, leafBoxesInLogicalOrder);
   1114     startBox = 0;
   1115     startNode = 0;
   1116     for (size_t i = 0; i < leafBoxesInLogicalOrder.size(); ++i) {
   1117         startBox = leafBoxesInLogicalOrder[i];
   1118         startNode = startBox->renderer()->node();
   1119         if (startNode)
   1120             return;
   1121     }
   1122 }
   1123 
   1124 static void getLogicalEndBoxAndNode(RootInlineBox* rootBox, InlineBox*& endBox, Node*& endNode)
   1125 {
   1126     Vector<InlineBox*> leafBoxesInLogicalOrder;
   1127     getLeafBoxesInLogicalOrder(rootBox, leafBoxesInLogicalOrder);
   1128     endBox = 0;
   1129     endNode = 0;
   1130     // Generated content (e.g. list markers and CSS :before and :after
   1131     // pseudoelements) have no corresponding DOM element, and so cannot be
   1132     // represented by a VisiblePosition.  Use whatever precedes instead.
   1133     for (size_t i = leafBoxesInLogicalOrder.size(); i > 0; --i) {
   1134         endBox = leafBoxesInLogicalOrder[i - 1];
   1135         endNode = endBox->renderer()->node();
   1136         if (endNode)
   1137             return;
   1138     }
   1139 }
   1140 
   1141 static VisiblePosition logicalStartPositionForLine(const VisiblePosition& c)
   1142 {
   1143     if (c.isNull())
   1144         return VisiblePosition();
   1145 
   1146     RootInlineBox* rootBox = rootBoxForLine(c);
   1147     if (!rootBox) {
   1148         // There are VisiblePositions at offset 0 in blocks without
   1149         // RootInlineBoxes, like empty editable blocks and bordered blocks.
   1150         Position p = c.deepEquivalent();
   1151         if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset())
   1152             return positionAvoidingFirstPositionInTable(c);
   1153 
   1154         return VisiblePosition();
   1155     }
   1156 
   1157     InlineBox* logicalStartBox;
   1158     Node* logicalStartNode;
   1159     getLogicalStartBoxAndNode(rootBox, logicalStartBox, logicalStartNode);
   1160 
   1161     if (!logicalStartNode)
   1162         return VisiblePosition();
   1163 
   1164     int startOffset = logicalStartBox->caretMinOffset();
   1165 
   1166     VisiblePosition visPos = VisiblePosition(logicalStartNode, startOffset, DOWNSTREAM);
   1167     return positionAvoidingFirstPositionInTable(visPos);
   1168 }
   1169 
   1170 VisiblePosition logicalStartOfLine(const VisiblePosition& c)
   1171 {
   1172     VisiblePosition visPos = logicalStartPositionForLine(c);
   1173 
   1174     return c.honorEditableBoundaryAtOrAfter(visPos);
   1175 }
   1176 
   1177 static VisiblePosition logicalEndPositionForLine(const VisiblePosition& c)
   1178 {
   1179     if (c.isNull())
   1180         return VisiblePosition();
   1181 
   1182     RootInlineBox* rootBox = rootBoxForLine(c);
   1183     if (!rootBox) {
   1184         // There are VisiblePositions at offset 0 in blocks without
   1185         // RootInlineBoxes, like empty editable blocks and bordered blocks.
   1186         Position p = c.deepEquivalent();
   1187         if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset())
   1188             return c;
   1189         return VisiblePosition();
   1190     }
   1191 
   1192     InlineBox* logicalEndBox;
   1193     Node* logicalEndNode;
   1194     getLogicalEndBoxAndNode(rootBox, logicalEndBox, logicalEndNode);
   1195     if (!logicalEndNode)
   1196         return VisiblePosition();
   1197 
   1198     int endOffset = 1;
   1199     if (logicalEndNode->hasTagName(brTag))
   1200         endOffset = 0;
   1201     else if (logicalEndBox->isInlineTextBox()) {
   1202         InlineTextBox* endTextBox = static_cast<InlineTextBox*>(logicalEndBox);
   1203         endOffset = endTextBox->start();
   1204         if (!endTextBox->isLineBreak())
   1205             endOffset += endTextBox->len();
   1206     }
   1207 
   1208     return VisiblePosition(logicalEndNode, endOffset, VP_UPSTREAM_IF_POSSIBLE);
   1209 }
   1210 
   1211 bool inSameLogicalLine(const VisiblePosition& a, const VisiblePosition& b)
   1212 {
   1213     return a.isNotNull() && logicalStartOfLine(a) == logicalStartOfLine(b);
   1214 }
   1215 
   1216 VisiblePosition logicalEndOfLine(const VisiblePosition& c)
   1217 {
   1218     VisiblePosition visPos = logicalEndPositionForLine(c);
   1219 
   1220     // Make sure the end of line is at the same line as the given input position. For a wrapping line, the logical end
   1221     // position for the not-last-2-lines might incorrectly hand back the logical beginning of the next line.
   1222     // For example, <div contenteditable dir="rtl" style="line-break:before-white-space">abcdefg abcdefg abcdefg
   1223     // a abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg </div>
   1224     // In this case, use the previous position of the computed logical end position.
   1225     if (!inSameLogicalLine(c, visPos))
   1226         visPos = visPos.previous();
   1227 
   1228     return c.honorEditableBoundaryAtOrBefore(visPos);
   1229 }
   1230 
   1231 }
   1232