visible_units.cpp revision cad810f21b803229eb11403f9209855525a25d57
18e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project/*
2635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
38e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
48e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * Redistribution and use in source and binary forms, with or without
58e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * modification, are permitted provided that the following conditions
68e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * are met:
78e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 1. Redistributions of source code must retain the above copyright
88e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer.
98e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * 2. Redistributions in binary form must reproduce the above copyright
108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    notice, this list of conditions and the following disclaimer in the
118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *    documentation and/or other materials provided with the distribution.
128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project *
138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project */
258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "config.h"
278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "visible_units.h"
288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Document.h"
308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "Element.h"
318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "HTMLNames.h"
32e14391e94c850b8bd03680c23b38978db68687a8John Reck#include "Position.h"
338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderBlock.h"
348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "RenderLayer.h"
35dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block#include "RenderObject.h"
368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "TextBoundaries.h"
378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "TextBreakIterator.h"
388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "TextIterator.h"
39635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "VisiblePosition.h"
408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "htmlediting.h"
418f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian#include <wtf/unicode/Unicode.h>
428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore {
448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace HTMLNames;
468f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qianusing namespace WTF::Unicode;
478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianenum BoundarySearchContextAvailability { DontHaveMoreContext, MayHaveMoreContext };
495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qiantypedef unsigned (*BoundarySearchFunction)(const UChar*, unsigned length, unsigned offset, BoundarySearchContextAvailability, bool& needMoreContext);
515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction)
538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position pos = c.deepEquivalent();
55dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch    Node* boundary = pos.parentEditingBoundary();
568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!boundary)
578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
59dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch    Document* d = boundary->document();
608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position start = rangeCompliantEquivalent(Position(boundary, 0));
618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position end = rangeCompliantEquivalent(pos);
628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RefPtr<Range> searchRange = Range::create(d);
638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
648f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    Vector<UChar, 1024> string;
658f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    unsigned suffixLength = 0;
668f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
678f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    ExceptionCode ec = 0;
685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (requiresContextForWordBoundary(c.characterBefore())) {
698f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        RefPtr<Range> forwardsScanRange(d->createRange());
708f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        forwardsScanRange->setEndAfter(boundary, ec);
715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        forwardsScanRange->setStart(end.node(), end.deprecatedEditingOffset(), ec);
728f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        TextIterator forwardsIterator(forwardsScanRange.get());
738f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        while (!forwardsIterator.atEnd()) {
748f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            const UChar* characters = forwardsIterator.characters();
758f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            int length = forwardsIterator.length();
765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            int i = endOfFirstWordBoundaryContext(characters, length);
778f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            string.append(characters, i);
788f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            suffixLength += i;
798f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            if (i < length)
808f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                break;
818f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            forwardsIterator.advance();
828f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        }
838f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    }
848f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    searchRange->setStart(start.node(), start.deprecatedEditingOffset(), ec);
865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    searchRange->setEnd(end.node(), end.deprecatedEditingOffset(), ec);
878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
888f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    ASSERT(!ec);
898f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    if (ec)
908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
918f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
92dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch    SimplifiedBackwardsTextIterator it(searchRange.get(), TextIteratorEndsAtEditingBoundary);
938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned next = 0;
948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool inTextSecurityMode = start.node() && start.node()->renderer() && start.node()->renderer()->style()->textSecurity() != TSNONE;
955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    bool needMoreContext = false;
968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (!it.atEnd()) {
978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // iterate to get chunks until the searchFunction returns a non-zero value.
988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!inTextSecurityMode)
998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            string.prepend(it.characters(), it.length());
1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else {
1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Treat bullets used in the text security mode as regular characters when looking for boundaries
1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            String iteratorString(it.characters(), it.length());
1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            iteratorString = iteratorString.impl()->secure('x');
1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            string.prepend(iteratorString.characters(), iteratorString.length());
1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
1065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        next = searchFunction(string.data(), string.size(), string.size() - suffixLength, MayHaveMoreContext, needMoreContext);
1078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (next != 0)
1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        it.advance();
1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (needMoreContext) {
1125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // The last search returned the beginning of the buffer and asked for more context,
1135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // but there is no earlier text. Force a search with what's available.
1145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        next = searchFunction(string.data(), string.size(), string.size() - suffixLength, DontHaveMoreContext, needMoreContext);
1155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        ASSERT(!needMoreContext);
1165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
1175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (it.atEnd() && next == 0) {
1198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pos = it.range()->startPosition();
1208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else if (next != 0) {
1218f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        Node *node = it.range()->startContainer(ec);
1228f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        if ((node->isTextNode() && static_cast<int>(next) <= node->maxCharacterOffset()) || (node->renderer() && node->renderer()->isBR() && !next))
1238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // The next variable contains a usable index into a text node
1248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            pos = Position(node, next);
1258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else {
1268f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            // Use the character iterator to translate the next value into a DOM position.
127dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch            BackwardsCharacterIterator charIt(searchRange.get(), TextIteratorEndsAtEditingBoundary);
1288f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            charIt.advance(string.size() - suffixLength - next);
1298f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            pos = charIt.range()->endPosition();
1308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
1318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePosition(pos, DOWNSTREAM);
1348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic VisiblePosition nextBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction)
1378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position pos = c.deepEquivalent();
139dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch    Node* boundary = pos.parentEditingBoundary();
1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!boundary)
1418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
143dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch    Document* d = boundary->document();
1448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RefPtr<Range> searchRange(d->createRange());
1458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position start(rangeCompliantEquivalent(pos));
1468f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
1478f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    Vector<UChar, 1024> string;
1488f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    unsigned prefixLength = 0;
1498f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
1508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ExceptionCode ec = 0;
1515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (requiresContextForWordBoundary(c.characterAfter())) {
1528f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        RefPtr<Range> backwardsScanRange(d->createRange());
1535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        backwardsScanRange->setEnd(start.node(), start.deprecatedEditingOffset(), ec);
1548f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        SimplifiedBackwardsTextIterator backwardsIterator(backwardsScanRange.get());
1558f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        while (!backwardsIterator.atEnd()) {
1568f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            const UChar* characters = backwardsIterator.characters();
1578f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            int length = backwardsIterator.length();
1585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            int i = startOfLastWordBoundaryContext(characters, length);
1595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            string.prepend(characters + i, length - i);
1605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            prefixLength += length - i;
1615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            if (i > 0)
1628f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian                break;
1638f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            backwardsIterator.advance();
1648f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        }
1658f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    }
1668f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian
1678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    searchRange->selectNodeContents(boundary, ec);
1685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    searchRange->setStart(start.node(), start.deprecatedEditingOffset(), ec);
16921939df44de1705786c545cd1bf519d47250322dBen Murdoch    TextIterator it(searchRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions);
1708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    unsigned next = 0;
1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool inTextSecurityMode = start.node() && start.node()->renderer() && start.node()->renderer()->style()->textSecurity() != TSNONE;
1725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    bool needMoreContext = false;
1738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (!it.atEnd()) {
1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Keep asking the iterator for chunks until the search function
1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // returns an end value not equal to the length of the string passed to it.
1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!inTextSecurityMode)
1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            string.append(it.characters(), it.length());
1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        else {
1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            // Treat bullets used in the text security mode as regular characters when looking for boundaries
1808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            String iteratorString(it.characters(), it.length());
1818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            iteratorString = iteratorString.impl()->secure('x');
1828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            string.append(iteratorString.characters(), iteratorString.length());
1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
1845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        next = searchFunction(string.data(), string.size(), prefixLength, MayHaveMoreContext, needMoreContext);
1858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (next != string.size())
1868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
1878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        it.advance();
1888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
1895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (needMoreContext) {
1905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // The last search returned the end of the buffer and asked for more context,
1915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // but there is no further text. Force a search with what's available.
1925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        next = searchFunction(string.data(), string.size(), prefixLength, DontHaveMoreContext, needMoreContext);
1935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        ASSERT(!needMoreContext);
1945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
1968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (it.atEnd() && next == string.size()) {
1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pos = it.range()->startPosition();
1988f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    } else if (next != prefixLength) {
1998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Use the character iterator to translate the next value into a DOM position.
20021939df44de1705786c545cd1bf519d47250322dBen Murdoch        CharacterIterator charIt(searchRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions);
2018f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        charIt.advance(next - prefixLength - 1);
202bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        RefPtr<Range> characterRange = charIt.range();
203bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        pos = characterRange->endPosition();
2048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2058f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        if (*charIt.characters() == '\n') {
2068f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            // FIXME: workaround for collapsed range (where only start position is correct) emitted for some emitted newlines (see rdar://5192593)
2078f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            VisiblePosition visPos = VisiblePosition(pos);
208bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen            if (visPos == VisiblePosition(characterRange->startPosition())) {
209bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen                charIt.advance(1);
210bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen                pos = charIt.range()->startPosition();
211bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen            }
2128f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        }
2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // generate VisiblePosition, use UPSTREAM affinity if possible
2168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE);
2178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
219dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockstatic bool canHaveCursor(RenderObject* o)
220dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{
221dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block    return (o->isText() && toRenderText(o)->linesBoundingBox().height())
222dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        || (o->isBox() && toRenderBox(o)->borderBoundingBox().height());
223dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block}
224dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
2258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// ---------
2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned startWordBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
2288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2298f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    ASSERT(offset);
2305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (mayHaveMoreContext && !startOfLastWordBoundaryContext(characters, offset)) {
2315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        needMoreContext = true;
2328f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        return 0;
2335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
2345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    needMoreContext = false;
2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int start, end;
2368f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    findWordBoundary(characters, length, offset - 1, &start, &end);
2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return start;
2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition startOfWord(const VisiblePosition &c, EWordSide side)
2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: This returns a null VP for c at the start of the document
2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // and side == LeftWordIfOnBoundary
2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition p = c;
2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (side == RightWordIfOnBoundary) {
2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // at paragraph end, the startofWord is the current position
2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (isEndOfParagraph(c))
2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return c;
2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        p = c.next();
2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (p.isNull())
2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return c;
2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return previousBoundary(p, startWordBoundary);
2558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned endWordBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
2588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2598f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    ASSERT(offset <= length);
2605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (mayHaveMoreContext && endOfFirstWordBoundaryContext(characters + offset, length - offset) == static_cast<int>(length - offset)) {
2615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        needMoreContext = true;
2628f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        return length;
2635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
2645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    needMoreContext = false;
2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int start, end;
2668f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    findWordBoundary(characters, length, offset, &start, &end);
2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return end;
2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition endOfWord(const VisiblePosition &c, EWordSide side)
2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition p = c;
2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (side == LeftWordIfOnBoundary) {
2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (isStartOfParagraph(c))
2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return c;
2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        p = c.previous();
2788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (p.isNull())
2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return c;
2808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else if (isEndOfParagraph(c))
2818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return c;
2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return nextBoundary(p, endWordBoundary);
2848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned previousWordPositionBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
2878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (mayHaveMoreContext && !startOfLastWordBoundaryContext(characters, offset)) {
2895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        needMoreContext = true;
2908f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        return 0;
2915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
2925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    needMoreContext = false;
2938f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    return findNextWordFromIndex(characters, length, offset, false);
2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
2958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
2968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition previousWordPosition(const VisiblePosition &c)
2978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
2988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition prev = previousBoundary(c, previousWordPositionBoundary);
2998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return c.honorEditableBoundaryAtOrAfter(prev);
3008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned nextWordPositionBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext)
3038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (mayHaveMoreContext && endOfFirstWordBoundaryContext(characters + offset, length - offset) == static_cast<int>(length - offset)) {
3055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        needMoreContext = true;
3068f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        return length;
3075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
3085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    needMoreContext = false;
3098f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    return findNextWordFromIndex(characters, length, offset, true);
3108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition nextWordPosition(const VisiblePosition &c)
3138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition next = nextBoundary(c, nextWordPositionBoundary);
3158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return c.honorEditableBoundaryAtOrBefore(next);
3168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// ---------
3198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic RootInlineBox *rootBoxForLine(const VisiblePosition &c)
3218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position p = c.deepEquivalent();
3238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *node = p.node();
3248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!node)
3258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return 0;
3268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RenderObject *renderer = node->renderer();
3288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!renderer)
3298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return 0;
3308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    InlineBox* box;
3328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int offset;
3338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    c.getInlineBoxAndOffset(box, offset);
3348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return box ? box->root() : 0;
3368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic VisiblePosition positionAvoidingFirstPositionInTable(const VisiblePosition& c)
3398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // return table offset 0 instead of the first VisiblePosition inside the table
3418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition previous = c.previous();
3420617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen    if (isLastPositionBeforeTable(previous) && isEditablePosition(previous.deepEquivalent()))
3438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return previous;
3440617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen
3458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return c;
3468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic VisiblePosition startPositionForLine(const VisiblePosition& c)
3498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (c.isNull())
3518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
3528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RootInlineBox *rootBox = rootBoxForLine(c);
3548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!rootBox) {
3558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // There are VisiblePositions at offset 0 in blocks without
3568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // RootInlineBoxes, like empty editable blocks and bordered blocks.
3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Position p = c.deepEquivalent();
3585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && p.deprecatedEditingOffset() == 0)
3598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return positionAvoidingFirstPositionInTable(c);
3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
3628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Generated content (e.g. list markers and CSS :before and :after
3658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // pseudoelements) have no corresponding DOM element, and so cannot be
3668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // represented by a VisiblePosition.  Use whatever follows instead.
3678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    InlineBox *startBox = rootBox->firstLeafChild();
3688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *startNode;
3698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (1) {
3708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!startBox)
3718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return VisiblePosition();
3728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3738f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        RenderObject *startRenderer = startBox->renderer();
3748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!startRenderer)
3758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return VisiblePosition();
3768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3778f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        startNode = startRenderer->node();
3788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (startNode)
3798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
3808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        startBox = startBox->nextLeafChild();
3828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int startOffset = 0;
3858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (startBox->isInlineTextBox()) {
3868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        InlineTextBox *startTextBox = static_cast<InlineTextBox *>(startBox);
387635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        startOffset = startTextBox->start();
3888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
3898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition visPos = VisiblePosition(startNode, startOffset, DOWNSTREAM);
3918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return positionAvoidingFirstPositionInTable(visPos);
3928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
3938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition startOfLine(const VisiblePosition& c)
3958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
3968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition visPos = startPositionForLine(c);
3978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
3988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return c.honorEditableBoundaryAtOrAfter(visPos);
3998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic VisiblePosition endPositionForLine(const VisiblePosition& c)
4028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (c.isNull())
4048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
4058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RootInlineBox *rootBox = rootBoxForLine(c);
4078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!rootBox) {
4088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // There are VisiblePositions at offset 0 in blocks without
4098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // RootInlineBoxes, like empty editable blocks and bordered blocks.
4108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Position p = c.deepEquivalent();
4115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && p.deprecatedEditingOffset() == 0)
4128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return c;
4138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
4148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Generated content (e.g. list markers and CSS :before and :after
4178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // pseudoelements) have no corresponding DOM element, and so cannot be
4188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // represented by a VisiblePosition.  Use whatever precedes instead.
4198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *endNode;
4208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    InlineBox *endBox = rootBox->lastLeafChild();
4218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (1) {
4228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!endBox)
4238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return VisiblePosition();
4248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4258f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        RenderObject *endRenderer = endBox->renderer();
4268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!endRenderer)
4278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return VisiblePosition();
4288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4298f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        endNode = endRenderer->node();
4308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (endNode)
4318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
4328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        endBox = endBox->prevLeafChild();
4348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int endOffset = 1;
4378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (endNode->hasTagName(brTag)) {
4388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        endOffset = 0;
4398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } else if (endBox->isInlineTextBox()) {
4408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        InlineTextBox *endTextBox = static_cast<InlineTextBox *>(endBox);
441635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        endOffset = endTextBox->start();
4428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!endTextBox->isLineBreak())
443635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            endOffset += endTextBox->len();
4448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePosition(endNode, endOffset, VP_UPSTREAM_IF_POSSIBLE);
4478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition endOfLine(const VisiblePosition& c)
4508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition visPos = endPositionForLine(c);
4528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Make sure the end of line is at the same line as the given input position.  Else use the previous position to
4548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // obtain end of line.  This condition happens when the input position is before the space character at the end
4558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // of a soft-wrapped non-editable line. In this scenario, endPositionForLine would incorrectly hand back a position
4568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // in the next line instead. This fix is to account for the discrepancy between lines with webkit-line-break:after-white-space style
4578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // versus lines without that style, which would break before a space by default.
4588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!inSameLine(c, visPos)) {
4598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        visPos = c.previous();
4608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (visPos.isNull())
4618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return VisiblePosition();
4628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        visPos = endPositionForLine(visPos);
4638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return c.honorEditableBoundaryAtOrBefore(visPos);
4668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool inSameLine(const VisiblePosition &a, const VisiblePosition &b)
4698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return a.isNotNull() && startOfLine(a) == startOfLine(b);
4718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool isStartOfLine(const VisiblePosition &p)
4748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return p.isNotNull() && p == startOfLine(p);
4768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool isEndOfLine(const VisiblePosition &p)
4798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return p.isNotNull() && p == endOfLine(p);
4818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// The first leaf before node that has the same editability as node.
4848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic Node* previousLeafWithSameEditability(Node* node)
4858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
4868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool editable = node->isContentEditable();
4878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node* n = node->previousLeafNode();
4888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (n) {
4898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (editable == n->isContentEditable())
4908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return n;
4918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        n = n->previousLeafNode();
4928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
4938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return 0;
4948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
4958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
4965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic Node* enclosingNodeWithNonInlineRenderer(Node* n)
4975f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
4985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (Node* p = n; p; p = p->parentNode()) {
4995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (p->renderer() && !p->renderer()->isInline())
5005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            return p;
5015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
5025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return 0;
5035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
5045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
5058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int x)
5068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position p = visiblePosition.deepEquivalent();
5088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *node = p.node();
5098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node* highestRoot = highestEditableRoot(p);
5108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!node)
5118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
5128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    node->document()->updateLayoutIgnorePendingStylesheets();
5148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RenderObject *renderer = node->renderer();
5168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!renderer)
5178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
5188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RenderBlock *containingBlock = 0;
5208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RootInlineBox *root = 0;
5218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    InlineBox* box;
5228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int ignoredCaretOffset;
5238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
5248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (box) {
5258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        root = box->root()->prevRootBox();
526dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // We want to skip zero height boxes.
527dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // This could happen in case it is a TrailingFloatsRootInlineBox.
528bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        if (root && root->logicalHeight())
5298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            containingBlock = renderer->containingBlock();
530dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        else
531dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            root = 0;
5328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!root) {
5358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // This containing editable block does not have a previous line.
5368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Need to move back to previous containing editable block in this root editable
5378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // block and find the last root line box in that block.
5385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        Node* startBlock = enclosingNodeWithNonInlineRenderer(node);
5398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        Node* n = previousLeafWithSameEditability(node);
5405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        while (n && startBlock == enclosingNodeWithNonInlineRenderer(n))
5418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            n = previousLeafWithSameEditability(n);
5428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (n) {
5438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (highestEditableRoot(Position(n, 0)) != highestRoot)
5448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                break;
5458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            Position pos(n, caretMinOffset(n));
5468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (pos.isCandidate()) {
547dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                RenderObject* o = n->renderer();
548dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                ASSERT(o);
549dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                if (canHaveCursor(o)) {
550dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                    Position maxPos(n, caretMaxOffset(n));
551dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                    maxPos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
552dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                    if (box) {
553dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                        // previous root line box found
554dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                        root = box->root();
555dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                        containingBlock = n->renderer()->containingBlock();
556dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                        break;
557dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                    }
558dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block
559dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block                    return VisiblePosition(pos, DOWNSTREAM);
5608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                }
5618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
5628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            n = previousLeafWithSameEditability(n);
5638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
5648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (root) {
567635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // FIXME: Can be wrong for multi-column layout and with transforms.
568635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        FloatPoint absPos = containingBlock->localToAbsolute(FloatPoint());
5698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (containingBlock->hasOverflowClip())
570635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            absPos -= containingBlock->layer()->scrolledContentOffset();
5716b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        RenderObject* renderer = root->closestLeafChildForLogicalLeftPosition(x - absPos.x(), isEditablePosition(p))->renderer();
572635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        Node* node = renderer->node();
5735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (node && editingIgnoresContent(node))
5746b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            return Position(node->parentNode(), node->nodeIndex());
575231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return renderer->positionForPoint(IntPoint(x - absPos.x(), root->lineTop()));
5768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Could not find a previous line. This means we must already be on the first line.
5798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Move to the start of the content in this block, which effectively moves us
5808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // to the start of the line we're on.
5815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Element* rootElement = node->isContentEditable() ? node->rootEditableElement() : node->document()->documentElement();
5828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePosition(rootElement, 0, DOWNSTREAM);
5838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic Node* nextLeafWithSameEditability(Node* node, int offset)
5868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
5878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool editable = node->isContentEditable();
5888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    ASSERT(offset >= 0);
5898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node* child = node->childNode(offset);
5908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node* n = child ? child->nextLeafNode() : node->nextLeafNode();
5918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (n) {
5928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (editable == n->isContentEditable())
5938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return n;
5948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        n = n->nextLeafNode();
5958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
5968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return 0;
5978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
5988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
5998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic Node* nextLeafWithSameEditability(Node* node)
6008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!node)
6028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return 0;
6038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    bool editable = node->isContentEditable();
6058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node* n = node->nextLeafNode();
6068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (n) {
6078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (editable == n->isContentEditable())
6088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            return n;
6098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        n = n->nextLeafNode();
6108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
6118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return 0;
6128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x)
6158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position p = visiblePosition.deepEquivalent();
6178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *node = p.node();
6188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node* highestRoot = highestEditableRoot(p);
6198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!node)
6208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
6218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    node->document()->updateLayoutIgnorePendingStylesheets();
6238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RenderObject *renderer = node->renderer();
6258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!renderer)
6268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
6278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RenderBlock *containingBlock = 0;
6298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    RootInlineBox *root = 0;
6308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    InlineBox* box;
6318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    int ignoredCaretOffset;
6328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset);
6338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (box) {
6348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        root = box->root()->nextRootBox();
635dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // We want to skip zero height boxes.
636dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        // This could happen in case it is a TrailingFloatsRootInlineBox.
637bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen        if (root && root->logicalHeight())
6388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            containingBlock = renderer->containingBlock();
639dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block        else
640dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block            root = 0;
6418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
6428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!root) {
6448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // This containing editable block does not have a next line.
6458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // Need to move forward to next containing editable block in this root editable
6468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // block and find the first root line box in that block.
6475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        Node* startBlock = enclosingNodeWithNonInlineRenderer(node);
6485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        Node* n = nextLeafWithSameEditability(node, p.deprecatedEditingOffset());
6495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        while (n && startBlock == enclosingNodeWithNonInlineRenderer(n))
6508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            n = nextLeafWithSameEditability(n);
6518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        while (n) {
6528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (highestEditableRoot(Position(n, 0)) != highestRoot)
6538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                break;
6548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            Position pos(n, caretMinOffset(n));
6558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (pos.isCandidate()) {
6568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                ASSERT(n->renderer());
6578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                pos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset);
6588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (box) {
6598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    // next root line box found
6608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    root = box->root();
6618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    containingBlock = n->renderer()->containingBlock();
6628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    break;
6638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                }
6648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                return VisiblePosition(pos, DOWNSTREAM);
6668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
6678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            n = nextLeafWithSameEditability(n);
6688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
6698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
6708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (root) {
672635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        // FIXME: Can be wrong for multi-column layout and with transforms.
673635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        FloatPoint absPos = containingBlock->localToAbsolute(FloatPoint());
6748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (containingBlock->hasOverflowClip())
675635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            absPos -= containingBlock->layer()->scrolledContentOffset();
6766b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner        RenderObject* renderer = root->closestLeafChildForLogicalLeftPosition(x - absPos.x(), isEditablePosition(p))->renderer();
677635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        Node* node = renderer->node();
6785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (node && editingIgnoresContent(node))
6796b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner            return Position(node->parentNode(), node->nodeIndex());
680231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block        return renderer->positionForPoint(IntPoint(x - absPos.x(), root->lineTop()));
6818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
6828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Could not find a next line. This means we must already be on the last line.
6848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // Move to the end of the content in this block, which effectively moves us
6858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // to the end of the line we're on.
6868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Element* rootElement = node->isContentEditable() ? node->rootEditableElement() : node->document()->documentElement();
6878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePosition(rootElement, rootElement ? rootElement->childNodeCount() : 0, DOWNSTREAM);
6888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// ---------
6918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned startSentenceBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&)
6938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
6948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
6958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: The following function can return -1; we don't handle that.
6968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return textBreakPreceding(iterator, length);
6978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
6988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
6998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition startOfSentence(const VisiblePosition &c)
7008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return previousBoundary(c, startSentenceBoundary);
7028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned endSentenceBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&)
7058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
7078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return textBreakNext(iterator);
7088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// FIXME: This includes the space after the punctuation that marks the end of the sentence.
7118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition endOfSentence(const VisiblePosition &c)
7128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return nextBoundary(c, endSentenceBoundary);
7148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned previousSentencePositionBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&)
7178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: This is identical to startSentenceBoundary. I'm pretty sure that's not right.
7198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
7208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: The following function can return -1; we don't handle that.
7218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return textBreakPreceding(iterator, length);
7228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition previousSentencePosition(const VisiblePosition &c)
7258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition prev = previousBoundary(c, previousSentencePositionBoundary);
7278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return c.honorEditableBoundaryAtOrAfter(prev);
7288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned nextSentencePositionBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&)
7318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // FIXME: This is identical to endSentenceBoundary.  This isn't right, it needs to
7338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // move to the equivlant position in the following sentence.
7348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    TextBreakIterator* iterator = sentenceBreakIterator(characters, length);
7358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return textBreakFollowing(iterator, 0);
7368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition nextSentencePosition(const VisiblePosition &c)
7398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition next = nextBoundary(c, nextSentencePositionBoundary);
7418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return c.honorEditableBoundaryAtOrBefore(next);
7428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
7438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7444576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) WangVisiblePosition startOfParagraph(const VisiblePosition& c, EditingBoundaryCrossingRule boundaryCrossingRule)
7458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
7468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position p = c.deepEquivalent();
7478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *startNode = p.node();
7488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!startNode)
7508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
7518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
752643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (isRenderedAsNonInlineTableImageOrHR(startNode))
7538f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        return firstDeepEditingPositionForNode(startNode);
7548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node* startBlock = enclosingBlock(startNode);
7568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *node = startNode;
7585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int offset = p.deprecatedEditingOffset();
7598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *n = startNode;
7618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (n) {
7624576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        if (boundaryCrossingRule == CannotCrossEditingBoundary && n->isContentEditable() != startNode->isContentEditable())
7638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
7648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        RenderObject *r = n->renderer();
7658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!r) {
7668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            n = n->traversePreviousNodePostOrder(startBlock);
7678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            continue;
7688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
7698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        RenderStyle *style = r->style();
7708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (style->visibility() != VISIBLE) {
7718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            n = n->traversePreviousNodePostOrder(startBlock);
7728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            continue;
7738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
7748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
7758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (r->isBR() || isBlock(n))
7768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
777e14391e94c850b8bd03680c23b38978db68687a8John Reck
778e14391e94c850b8bd03680c23b38978db68687a8John Reck        if (r->isText() && r->caretMaxRenderedOffset() > 0) {
7798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (style->preserveNewline()) {
780635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                const UChar* chars = toRenderText(r)->characters();
781635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                int i = toRenderText(r)->textLength();
7828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                int o = offset;
7838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                if (n == startNode && o < i)
7848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    i = max(0, o);
7858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                while (--i >= 0)
7868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    if (chars[i] == '\n')
7878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        return VisiblePosition(n, i + 1, DOWNSTREAM);
7888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
7898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            node = n;
7908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            offset = 0;
7918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            n = n->traversePreviousNodePostOrder(startBlock);
7928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else if (editingIgnoresContent(n) || isTableElement(n)) {
7938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            node = n;
7948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            offset = 0;
7958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            n = n->previousSibling() ? n->previousSibling() : n->traversePreviousNodePostOrder(startBlock);
7968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else
7978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            n = n->traversePreviousNodePostOrder(startBlock);
7988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
7998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePosition(node, offset, DOWNSTREAM);
8018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8034576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) WangVisiblePosition endOfParagraph(const VisiblePosition &c, EditingBoundaryCrossingRule boundaryCrossingRule)
8048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (c.isNull())
8068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
8078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position p = c.deepEquivalent();
8098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node* startNode = p.node();
8108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
811643ca7872b450ea4efacab6188849e5aac2ba161Steve Block    if (isRenderedAsNonInlineTableImageOrHR(startNode))
8128f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian        return lastDeepEditingPositionForNode(startNode);
8138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node* startBlock = enclosingBlock(startNode);
8158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *stayInsideBlock = startBlock;
8168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *node = startNode;
8185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int offset = p.deprecatedEditingOffset();
8198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *n = startNode;
8218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    while (n) {
8224576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wang        if (boundaryCrossingRule == CannotCrossEditingBoundary && n->isContentEditable() != startNode->isContentEditable())
8238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
8248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        RenderObject *r = n->renderer();
8258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (!r) {
8268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            n = n->traverseNextNode(stayInsideBlock);
8278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            continue;
8288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
8298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        RenderStyle *style = r->style();
8308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (style->visibility() != VISIBLE) {
8318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            n = n->traverseNextNode(stayInsideBlock);
8328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            continue;
8338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        }
8348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (r->isBR() || isBlock(n))
8368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            break;
837e14391e94c850b8bd03680c23b38978db68687a8John Reck
8388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        // FIXME: We avoid returning a position where the renderer can't accept the caret.
8398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (r->isText() && r->caretMaxRenderedOffset() > 0) {
840635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project            int length = toRenderText(r)->textLength();
8418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            if (style->preserveNewline()) {
842635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project                const UChar* chars = toRenderText(r)->characters();
8438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                int o = n == startNode ? offset : 0;
8448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                for (int i = o; i < length; ++i)
8458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                    if (chars[i] == '\n')
8468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project                        return VisiblePosition(n, i, DOWNSTREAM);
8478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            }
8488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            node = n;
8498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            offset = r->caretMaxOffset();
8508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            n = n->traverseNextNode(stayInsideBlock);
8518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else if (editingIgnoresContent(n) || isTableElement(n)) {
8528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            node = n;
8538f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            offset = lastOffsetForEditing(n);
8548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            n = n->traverseNextSibling(stayInsideBlock);
8558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        } else
8568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project            n = n->traverseNextNode(stayInsideBlock);
8578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    }
8588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePosition(node, offset, DOWNSTREAM);
8608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition startOfNextParagraph(const VisiblePosition& visiblePosition)
8638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition paragraphEnd(endOfParagraph(visiblePosition));
8658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition afterParagraphEnd(paragraphEnd.next(true));
8668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // The position after the last position in the last cell of a table
8678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    // is not the start of the next paragraph.
8688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (isFirstPositionAfterTable(afterParagraphEnd))
8698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return afterParagraphEnd.next(true);
8708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return afterParagraphEnd;
8718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool inSameParagraph(const VisiblePosition &a, const VisiblePosition &b)
8748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return a.isNotNull() && startOfParagraph(a) == startOfParagraph(b);
8768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8784576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangbool isStartOfParagraph(const VisiblePosition &pos, EditingBoundaryCrossingRule boundaryCrossingRule)
8798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
880e14391e94c850b8bd03680c23b38978db68687a8John Reck    return pos.isNotNull() && pos == startOfParagraph(pos, boundaryCrossingRule);
8818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8834576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangbool isEndOfParagraph(const VisiblePosition &pos, EditingBoundaryCrossingRule boundaryCrossingRule)
8848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
885e14391e94c850b8bd03680c23b38978db68687a8John Reck    return pos.isNotNull() && pos == endOfParagraph(pos, boundaryCrossingRule);
8868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
8888f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng QianVisiblePosition previousParagraphPosition(const VisiblePosition& p, int x)
8898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
8908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition pos = p;
8918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    do {
8928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        VisiblePosition n = previousLinePosition(pos, x);
8938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (n.isNull() || n == pos)
8948f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            break;
8958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pos = n;
8968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } while (inSameParagraph(p, pos));
8978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return pos;
8988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
8998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9008f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng QianVisiblePosition nextParagraphPosition(const VisiblePosition& p, int x)
9018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    VisiblePosition pos = p;
9038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    do {
9048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        VisiblePosition n = nextLinePosition(pos, x);
9058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        if (n.isNull() || n == pos)
9068f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian            break;
9078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        pos = n;
9088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    } while (inSameParagraph(p, pos));
9098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return pos;
9108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// ---------
9138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition startOfBlock(const VisiblePosition &c)
9158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position p = c.deepEquivalent();
9178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *startNode = p.node();
9188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!startNode)
9198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
9208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePosition(Position(startNode->enclosingBlockFlowElement(), 0), DOWNSTREAM);
9218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition endOfBlock(const VisiblePosition &c)
9248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position p = c.deepEquivalent();
9268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *startNode = p.node();
9288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!startNode)
9298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
9308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *startBlock = startNode->enclosingBlockFlowElement();
9328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePosition(startBlock, startBlock->childNodeCount(), VP_DEFAULT_AFFINITY);
9348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool inSameBlock(const VisiblePosition &a, const VisiblePosition &b)
9378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return !a.isNull() && enclosingBlockFlowElement(a) == enclosingBlockFlowElement(b);
9398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool isStartOfBlock(const VisiblePosition &pos)
9428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return pos.isNotNull() && pos == startOfBlock(pos);
9448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool isEndOfBlock(const VisiblePosition &pos)
9478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return pos.isNotNull() && pos == endOfBlock(pos);
9498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// ---------
9528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition startOfDocument(const Node* node)
9548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!node)
9568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
9578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePosition(node->document()->documentElement(), 0, DOWNSTREAM);
9598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition startOfDocument(const VisiblePosition &c)
9628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return startOfDocument(c.deepEquivalent().node());
9648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition endOfDocument(const Node* node)
9678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
968dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch    if (!node || !node->document() || !node->document()->documentElement())
9698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
9708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Element* doc = node->document()->documentElement();
9728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return VisiblePosition(doc, doc->childNodeCount(), DOWNSTREAM);
9738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition endOfDocument(const VisiblePosition &c)
9768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return endOfDocument(c.deepEquivalent().node());
9788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool inSameDocument(const VisiblePosition &a, const VisiblePosition &b)
9818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position ap = a.deepEquivalent();
9838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *an = ap.node();
9848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!an)
9858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return false;
9868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Position bp = b.deepEquivalent();
9878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node *bn = bp.node();
9888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (an == bn)
9898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return true;
9908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return an->document() == bn->document();
9928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool isStartOfDocument(const VisiblePosition &p)
9958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
9968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return p.isNotNull() && p.previous().isNull();
9978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
9988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
9998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool isEndOfDocument(const VisiblePosition &p)
10008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    return p.isNotNull() && p.next().isNull();
10028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// ---------
10058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition startOfEditableContent(const VisiblePosition& visiblePosition)
10078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
10098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!highestRoot)
10108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
10118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10128f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    return firstDeepEditingPositionForNode(highestRoot);
10138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition endOfEditableContent(const VisiblePosition& visiblePosition)
10168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{
10178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
10188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project    if (!highestRoot)
10198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project        return VisiblePosition();
10208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10218f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian    return lastDeepEditingPositionForNode(highestRoot);
10228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
10238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project
10245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic void getLeafBoxesInLogicalOrder(RootInlineBox* rootBox, Vector<InlineBox*>& leafBoxesInLogicalOrder)
10255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
10265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    unsigned char minLevel = 128;
10275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    unsigned char maxLevel = 0;
10285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    unsigned count = 0;
10295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    InlineBox* r = rootBox->firstLeafChild();
10305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // First find highest and lowest levels,
10315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // and initialize leafBoxesInLogicalOrder with the leaf boxes in visual order.
10325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    while (r) {
10335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (r->bidiLevel() > maxLevel)
10345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            maxLevel = r->bidiLevel();
10355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (r->bidiLevel() < minLevel)
10365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            minLevel = r->bidiLevel();
10375f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        leafBoxesInLogicalOrder.append(r);
10385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        r = r->nextLeafChild();
10395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        ++count;
10405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
10415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
10425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (rootBox->renderer()->style()->visuallyOrdered())
10435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return;
10445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // Reverse of reordering of the line (L2 according to Bidi spec):
10455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // L2. From the highest level found in the text to the lowest odd level on each line,
10465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // reverse any contiguous sequence of characters that are at that level or higher.
10475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
10485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // Reversing the reordering of the line is only done up to the lowest odd level.
10495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!(minLevel % 2))
10505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        minLevel++;
10515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
10525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    InlineBox** end = leafBoxesInLogicalOrder.end();
10535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    while (minLevel <= maxLevel) {
10545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        InlineBox** iter = leafBoxesInLogicalOrder.begin();
10555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        while (iter != end) {
10565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            while (iter != end) {
10575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                if ((*iter)->bidiLevel() >= minLevel)
10585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                    break;
10595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                ++iter;
10605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            }
10615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            InlineBox** first = iter;
10625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            while (iter != end) {
10635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                if ((*iter)->bidiLevel() < minLevel)
10645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                    break;
10655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian                ++iter;
10665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            }
10675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            InlineBox** last = iter;
10685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            std::reverse(first, last);
10695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        }
10705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        ++minLevel;
10715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
10725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
10735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
10745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic void getLogicalStartBoxAndNode(RootInlineBox* rootBox, InlineBox*& startBox, Node*& startNode)
10755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
10765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Vector<InlineBox*> leafBoxesInLogicalOrder;
10775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    getLeafBoxesInLogicalOrder(rootBox, leafBoxesInLogicalOrder);
10785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    startBox = 0;
10795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    startNode = 0;
10805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (size_t i = 0; i < leafBoxesInLogicalOrder.size(); ++i) {
10815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        startBox = leafBoxesInLogicalOrder[i];
10825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        startNode = startBox->renderer()->node();
10835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (startNode)
10845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            return;
10855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
10865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
10875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
10885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic void getLogicalEndBoxAndNode(RootInlineBox* rootBox, InlineBox*& endBox, Node*& endNode)
10895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
10905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Vector<InlineBox*> leafBoxesInLogicalOrder;
10915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    getLeafBoxesInLogicalOrder(rootBox, leafBoxesInLogicalOrder);
10925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    endBox = 0;
10935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    endNode = 0;
10945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // Generated content (e.g. list markers and CSS :before and :after
10955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // pseudoelements) have no corresponding DOM element, and so cannot be
10965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // represented by a VisiblePosition.  Use whatever precedes instead.
10975f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (size_t i = leafBoxesInLogicalOrder.size(); i > 0; --i) {
10985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        endBox = leafBoxesInLogicalOrder[i - 1];
10995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        endNode = endBox->renderer()->node();
11005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (endNode)
11015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            return;
11025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
11035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
11045f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic VisiblePosition logicalStartPositionForLine(const VisiblePosition& c)
11065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
11075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (c.isNull())
11085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return VisiblePosition();
11095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11105f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    RootInlineBox* rootBox = rootBoxForLine(c);
11115f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!rootBox) {
11125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // There are VisiblePositions at offset 0 in blocks without
11135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // RootInlineBoxes, like empty editable blocks and bordered blocks.
11145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        Position p = c.deepEquivalent();
11155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset())
11165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            return positionAvoidingFirstPositionInTable(c);
11175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return VisiblePosition();
11195f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
11205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    InlineBox* logicalStartBox;
11225f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Node* logicalStartNode;
11235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    getLogicalStartBoxAndNode(rootBox, logicalStartBox, logicalStartNode);
11245f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!logicalStartNode)
11265f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return VisiblePosition();
11275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int startOffset = logicalStartBox->caretMinOffset();
11295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    VisiblePosition visPos = VisiblePosition(logicalStartNode, startOffset, DOWNSTREAM);
11315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return positionAvoidingFirstPositionInTable(visPos);
11325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
11335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11345f1ab04193ad0130ca8204aadaceae083aca9881Feng QianVisiblePosition logicalStartOfLine(const VisiblePosition& c)
11355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
1136cad810f21b803229eb11403f9209855525a25d57Steve Block    // TODO: this is the current behavior that might need to be fixed.
1137cad810f21b803229eb11403f9209855525a25d57Steve Block    // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
11385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    VisiblePosition visPos = logicalStartPositionForLine(c);
11395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return c.honorEditableBoundaryAtOrAfter(visPos);
11415f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
11425f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic VisiblePosition logicalEndPositionForLine(const VisiblePosition& c)
11445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
11455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (c.isNull())
11465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return VisiblePosition();
11475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    RootInlineBox* rootBox = rootBoxForLine(c);
11495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!rootBox) {
11505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // There are VisiblePositions at offset 0 in blocks without
11515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        // RootInlineBoxes, like empty editable blocks and bordered blocks.
11525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        Position p = c.deepEquivalent();
11535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset())
11545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            return c;
11555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return VisiblePosition();
11565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
11575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    InlineBox* logicalEndBox;
11595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Node* logicalEndNode;
11605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    getLogicalEndBoxAndNode(rootBox, logicalEndBox, logicalEndNode);
11615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!logicalEndNode)
11625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return VisiblePosition();
11635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int endOffset = 1;
11655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (logicalEndNode->hasTagName(brTag))
11665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        endOffset = 0;
11675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    else if (logicalEndBox->isInlineTextBox()) {
11685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        InlineTextBox* endTextBox = static_cast<InlineTextBox*>(logicalEndBox);
11695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        endOffset = endTextBox->start();
11705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (!endTextBox->isLineBreak())
11715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            endOffset += endTextBox->len();
11725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
11735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11745f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return VisiblePosition(logicalEndNode, endOffset, VP_UPSTREAM_IF_POSSIBLE);
11755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
11765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianbool inSameLogicalLine(const VisiblePosition& a, const VisiblePosition& b)
11785f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
11795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return a.isNotNull() && logicalStartOfLine(a) == logicalStartOfLine(b);
11805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
11815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11825f1ab04193ad0130ca8204aadaceae083aca9881Feng QianVisiblePosition logicalEndOfLine(const VisiblePosition& c)
11835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
1184cad810f21b803229eb11403f9209855525a25d57Steve Block    // TODO: this is the current behavior that might need to be fixed.
1185cad810f21b803229eb11403f9209855525a25d57Steve Block    // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
1186cad810f21b803229eb11403f9209855525a25d57Steve Block
11875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    VisiblePosition visPos = logicalEndPositionForLine(c);
11885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // Make sure the end of line is at the same line as the given input position. For a wrapping line, the logical end
11905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // position for the not-last-2-lines might incorrectly hand back the logical beginning of the next line.
11915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // For example, <div contenteditable dir="rtl" style="line-break:before-white-space">abcdefg abcdefg abcdefg
11925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // a abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg </div>
11935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // In this case, use the previous position of the computed logical end position.
11945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!inSameLogicalLine(c, visPos))
11955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        visPos = visPos.previous();
11965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
11975f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return c.honorEditableBoundaryAtOrBefore(visPos);
11985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
11995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
1200cad810f21b803229eb11403f9209855525a25d57Steve BlockVisiblePosition leftBoundaryOfLine(const VisiblePosition& c, TextDirection direction)
1201cad810f21b803229eb11403f9209855525a25d57Steve Block{
1202cad810f21b803229eb11403f9209855525a25d57Steve Block    return direction == LTR ? logicalStartOfLine(c) : logicalEndOfLine(c);
1203cad810f21b803229eb11403f9209855525a25d57Steve Block}
1204cad810f21b803229eb11403f9209855525a25d57Steve Block
1205cad810f21b803229eb11403f9209855525a25d57Steve BlockVisiblePosition rightBoundaryOfLine(const VisiblePosition& c, TextDirection direction)
1206cad810f21b803229eb11403f9209855525a25d57Steve Block{
1207cad810f21b803229eb11403f9209855525a25d57Steve Block    return direction == LTR ? logicalEndOfLine(c) : logicalStartOfLine(c);
1208cad810f21b803229eb11403f9209855525a25d57Steve Block}
1209cad810f21b803229eb11403f9209855525a25d57Steve Block
12108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project}
1211