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" 402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch#include "VisibleSelection.h" 418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project#include "htmlediting.h" 428f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian#include <wtf/unicode/Unicode.h> 438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectnamespace WebCore { 458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectusing namespace HTMLNames; 478f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qianusing namespace WTF::Unicode; 488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianenum BoundarySearchContextAvailability { DontHaveMoreContext, MayHaveMoreContext }; 505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qiantypedef unsigned (*BoundarySearchFunction)(const UChar*, unsigned length, unsigned offset, BoundarySearchContextAvailability, bool& needMoreContext); 525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic VisiblePosition previousBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction) 548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position pos = c.deepEquivalent(); 56dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch Node* boundary = pos.parentEditingBoundary(); 578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!boundary) 588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 60dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch Document* d = boundary->document(); 61ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch Position start = Position(boundary, 0).parentAnchoredEquivalent(); 62ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch Position end = pos.parentAnchoredEquivalent(); 638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RefPtr<Range> searchRange = Range::create(d); 648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 658f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian Vector<UChar, 1024> string; 668f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian unsigned suffixLength = 0; 678f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian 688f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian ExceptionCode ec = 0; 695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (requiresContextForWordBoundary(c.characterBefore())) { 708f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian RefPtr<Range> forwardsScanRange(d->createRange()); 718f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian forwardsScanRange->setEndAfter(boundary, ec); 7281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch forwardsScanRange->setStart(end.deprecatedNode(), end.deprecatedEditingOffset(), ec); 738f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian TextIterator forwardsIterator(forwardsScanRange.get()); 748f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian while (!forwardsIterator.atEnd()) { 758f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian const UChar* characters = forwardsIterator.characters(); 768f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian int length = forwardsIterator.length(); 775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int i = endOfFirstWordBoundaryContext(characters, length); 788f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian string.append(characters, i); 798f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian suffixLength += i; 808f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian if (i < length) 818f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian break; 828f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian forwardsIterator.advance(); 838f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian } 848f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian } 858f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian 8681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), ec); 8781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch searchRange->setEnd(end.deprecatedNode(), end.deprecatedEditingOffset(), ec); 888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 898f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian ASSERT(!ec); 908f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian if (ec) 918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 928f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian 9381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch SimplifiedBackwardsTextIterator it(searchRange.get()); 948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project unsigned next = 0; 9581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch bool inTextSecurityMode = start.deprecatedNode() && start.deprecatedNode()->renderer() && start.deprecatedNode()->renderer()->style()->textSecurity() != TSNONE; 965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian bool needMoreContext = false; 978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project while (!it.atEnd()) { 988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // iterate to get chunks until the searchFunction returns a non-zero value. 998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!inTextSecurityMode) 1008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project string.prepend(it.characters(), it.length()); 1018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project else { 1028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Treat bullets used in the text security mode as regular characters when looking for boundaries 1038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project String iteratorString(it.characters(), it.length()); 1048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project iteratorString = iteratorString.impl()->secure('x'); 1058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project string.prepend(iteratorString.characters(), iteratorString.length()); 1068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1075f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian next = searchFunction(string.data(), string.size(), string.size() - suffixLength, MayHaveMoreContext, needMoreContext); 1088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (next != 0) 1098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project break; 1108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project it.advance(); 1118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1125f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (needMoreContext) { 1135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // The last search returned the beginning of the buffer and asked for more context, 1145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // but there is no earlier text. Force a search with what's available. 1155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian next = searchFunction(string.data(), string.size(), string.size() - suffixLength, DontHaveMoreContext, needMoreContext); 1165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian ASSERT(!needMoreContext); 1175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 1185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 119ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if (!next) 120ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch return VisiblePosition(it.atEnd() ? it.range()->startPosition() : pos, DOWNSTREAM); 121ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch 122ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch Node* node = it.range()->startContainer(ec); 123ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch if ((node->isTextNode() && static_cast<int>(next) <= node->maxCharacterOffset()) || (node->renderer() && node->renderer()->isBR() && !next)) 124ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch // The next variable contains a usable index into a text node 125ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch return VisiblePosition(Position(node, next), DOWNSTREAM); 1268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 127ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch // Use the character iterator to translate the next value into a DOM position. 12881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch BackwardsCharacterIterator charIt(searchRange.get()); 129ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch charIt.advance(string.size() - suffixLength - next); 1302bde8e466a4451c7319e3a072d118917957d6554Steve Block // FIXME: charIt can get out of shadow host. 131ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch return VisiblePosition(charIt.range()->endPosition(), DOWNSTREAM); 1328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 1338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic VisiblePosition nextBoundary(const VisiblePosition& c, BoundarySearchFunction searchFunction) 1358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 1368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position pos = c.deepEquivalent(); 137dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch Node* boundary = pos.parentEditingBoundary(); 1388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!boundary) 1398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 1408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 141dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch Document* d = boundary->document(); 1428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RefPtr<Range> searchRange(d->createRange()); 143ab9e7a118cf1ea2e3a93dce683b2ded3e7291ddbBen Murdoch Position start(pos.parentAnchoredEquivalent()); 1448f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian 1458f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian Vector<UChar, 1024> string; 1468f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian unsigned prefixLength = 0; 1478f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian 1488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ExceptionCode ec = 0; 1495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (requiresContextForWordBoundary(c.characterAfter())) { 1508f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian RefPtr<Range> backwardsScanRange(d->createRange()); 15181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch backwardsScanRange->setEnd(start.deprecatedNode(), start.deprecatedEditingOffset(), ec); 1528f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian SimplifiedBackwardsTextIterator backwardsIterator(backwardsScanRange.get()); 1538f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian while (!backwardsIterator.atEnd()) { 1548f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian const UChar* characters = backwardsIterator.characters(); 1558f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian int length = backwardsIterator.length(); 1565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int i = startOfLastWordBoundaryContext(characters, length); 1575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian string.prepend(characters + i, length - i); 1585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian prefixLength += length - i; 1595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (i > 0) 1608f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian break; 1618f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian backwardsIterator.advance(); 1628f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian } 1638f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian } 1648f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian 1658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project searchRange->selectNodeContents(boundary, ec); 16681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch searchRange->setStart(start.deprecatedNode(), start.deprecatedEditingOffset(), ec); 16721939df44de1705786c545cd1bf519d47250322dBen Murdoch TextIterator it(searchRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions); 1688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project unsigned next = 0; 16981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch bool inTextSecurityMode = start.deprecatedNode() && start.deprecatedNode()->renderer() && start.deprecatedNode()->renderer()->style()->textSecurity() != TSNONE; 1705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian bool needMoreContext = false; 1718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project while (!it.atEnd()) { 1728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Keep asking the iterator for chunks until the search function 1738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // returns an end value not equal to the length of the string passed to it. 1748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!inTextSecurityMode) 1758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project string.append(it.characters(), it.length()); 1768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project else { 1778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Treat bullets used in the text security mode as regular characters when looking for boundaries 1788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project String iteratorString(it.characters(), it.length()); 1798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project iteratorString = iteratorString.impl()->secure('x'); 1808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project string.append(iteratorString.characters(), iteratorString.length()); 1818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian next = searchFunction(string.data(), string.size(), prefixLength, MayHaveMoreContext, needMoreContext); 1838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (next != string.size()) 1848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project break; 1858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project it.advance(); 1868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 1875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (needMoreContext) { 1885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // The last search returned the end of the buffer and asked for more context, 1895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // but there is no further text. Force a search with what's available. 1905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian next = searchFunction(string.data(), string.size(), prefixLength, DontHaveMoreContext, needMoreContext); 1915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian ASSERT(!needMoreContext); 1925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 1938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 1948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (it.atEnd() && next == string.size()) { 1958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project pos = it.range()->startPosition(); 1968f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian } else if (next != prefixLength) { 1978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Use the character iterator to translate the next value into a DOM position. 19821939df44de1705786c545cd1bf519d47250322dBen Murdoch CharacterIterator charIt(searchRange.get(), TextIteratorEmitsCharactersBetweenAllVisiblePositions); 1998f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian charIt.advance(next - prefixLength - 1); 200bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen RefPtr<Range> characterRange = charIt.range(); 201bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen pos = characterRange->endPosition(); 2028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2038f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian if (*charIt.characters() == '\n') { 2048f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian // FIXME: workaround for collapsed range (where only start position is correct) emitted for some emitted newlines (see rdar://5192593) 2058f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian VisiblePosition visPos = VisiblePosition(pos); 206bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen if (visPos == VisiblePosition(characterRange->startPosition())) { 207bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen charIt.advance(1); 208bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen pos = charIt.range()->startPosition(); 209bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen } 2108f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian } 2118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 2128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // generate VisiblePosition, use UPSTREAM affinity if possible 2148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE); 2158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 2168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 217dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Blockstatic bool canHaveCursor(RenderObject* o) 218dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block{ 219dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return (o->isText() && toRenderText(o)->linesBoundingBox().height()) 220dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block || (o->isBox() && toRenderBox(o)->borderBoundingBox().height()); 221dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block} 222dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 2238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// --------- 2248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2255f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned startWordBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext) 2268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 2278f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian ASSERT(offset); 2285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (mayHaveMoreContext && !startOfLastWordBoundaryContext(characters, offset)) { 2295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian needMoreContext = true; 2308f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian return 0; 2315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 2325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian needMoreContext = false; 2338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project int start, end; 2348f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian findWordBoundary(characters, length, offset - 1, &start, &end); 2358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return start; 2368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 2378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition startOfWord(const VisiblePosition &c, EWordSide side) 2398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 2408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // FIXME: This returns a null VP for c at the start of the document 2418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // and side == LeftWordIfOnBoundary 2428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project VisiblePosition p = c; 2438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (side == RightWordIfOnBoundary) { 2448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // at paragraph end, the startofWord is the current position 2458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (isEndOfParagraph(c)) 2468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return c; 2478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project p = c.next(); 2498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (p.isNull()) 2508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return c; 2518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 2528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return previousBoundary(p, startWordBoundary); 2538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 2548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned endWordBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext) 2568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 2578f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian ASSERT(offset <= length); 2585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (mayHaveMoreContext && endOfFirstWordBoundaryContext(characters + offset, length - offset) == static_cast<int>(length - offset)) { 2595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian needMoreContext = true; 2608f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian return length; 2615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 2625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian needMoreContext = false; 2638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project int start, end; 2648f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian findWordBoundary(characters, length, offset, &start, &end); 2658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return end; 2668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 2678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition endOfWord(const VisiblePosition &c, EWordSide side) 2698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 2708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project VisiblePosition p = c; 2718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (side == LeftWordIfOnBoundary) { 2728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (isStartOfParagraph(c)) 2738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return c; 2748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project p = c.previous(); 2768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (p.isNull()) 2778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return c; 2788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } else if (isEndOfParagraph(c)) 2798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return c; 2808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return nextBoundary(p, endWordBoundary); 2828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 2838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned previousWordPositionBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext) 2858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 2865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (mayHaveMoreContext && !startOfLastWordBoundaryContext(characters, offset)) { 2875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian needMoreContext = true; 2888f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian return 0; 2895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 2905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian needMoreContext = false; 2918f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian return findNextWordFromIndex(characters, length, offset, false); 2928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 2938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 2948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition previousWordPosition(const VisiblePosition &c) 2958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 2968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project VisiblePosition prev = previousBoundary(c, previousWordPositionBoundary); 2972fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return c.honorEditableBoundaryAtOrBefore(prev); 2988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 2998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned nextWordPositionBoundary(const UChar* characters, unsigned length, unsigned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreContext) 3018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 3025f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (mayHaveMoreContext && endOfFirstWordBoundaryContext(characters + offset, length - offset) == static_cast<int>(length - offset)) { 3035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian needMoreContext = true; 3048f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian return length; 3055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 3065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian needMoreContext = false; 3078f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian return findNextWordFromIndex(characters, length, offset, true); 3088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 3098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition nextWordPosition(const VisiblePosition &c) 3118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 3128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project VisiblePosition next = nextBoundary(c, nextWordPositionBoundary); 3132fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return c.honorEditableBoundaryAtOrAfter(next); 3148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 3158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// --------- 3178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic RootInlineBox *rootBoxForLine(const VisiblePosition &c) 3198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 3208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position p = c.deepEquivalent(); 32181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch Node* node = p.deprecatedNode(); 3228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!node) 3238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return 0; 3248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RenderObject *renderer = node->renderer(); 3268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!renderer) 3278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return 0; 3288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project InlineBox* box; 3308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project int offset; 3318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project c.getInlineBoxAndOffset(box, offset); 3328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return box ? box->root() : 0; 3348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 3358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic VisiblePosition positionAvoidingFirstPositionInTable(const VisiblePosition& c) 3378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 3388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // return table offset 0 instead of the first VisiblePosition inside the table 3398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project VisiblePosition previous = c.previous(); 3400617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen if (isLastPositionBeforeTable(previous) && isEditablePosition(previous.deepEquivalent())) 3418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return previous; 3420617145a89917ae7735fe1c9538688ab9a577df5Kristian Monsen 3438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return c; 3448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 3458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic VisiblePosition startPositionForLine(const VisiblePosition& c) 3478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 3488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (c.isNull()) 3498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 3508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RootInlineBox *rootBox = rootBoxForLine(c); 3528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!rootBox) { 3538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // There are VisiblePositions at offset 0 in blocks without 3548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // RootInlineBoxes, like empty editable blocks and bordered blocks. 3558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position p = c.deepEquivalent(); 35681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (p.deprecatedNode()->renderer() && p.deprecatedNode()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset()) 3578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return positionAvoidingFirstPositionInTable(c); 3588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 3608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 3618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Generated content (e.g. list markers and CSS :before and :after 3638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // pseudoelements) have no corresponding DOM element, and so cannot be 3648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // represented by a VisiblePosition. Use whatever follows instead. 3658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project InlineBox *startBox = rootBox->firstLeafChild(); 3668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Node *startNode; 3678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project while (1) { 3688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!startBox) 3698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 3708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3718f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian RenderObject *startRenderer = startBox->renderer(); 3728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!startRenderer) 3738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 3748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3758f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian startNode = startRenderer->node(); 3768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (startNode) 3778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project break; 3788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project startBox = startBox->nextLeafChild(); 3808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 3818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3822bde8e466a4451c7319e3a072d118917957d6554Steve Block VisiblePosition visPos = startNode->isTextNode() ? VisiblePosition(Position(startNode, static_cast<InlineTextBox *>(startBox)->start(), Position::PositionIsOffsetInAnchor), DOWNSTREAM) 3832bde8e466a4451c7319e3a072d118917957d6554Steve Block : VisiblePosition(positionBeforeNode(startNode), DOWNSTREAM); 3848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return positionAvoidingFirstPositionInTable(visPos); 3858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 3868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition startOfLine(const VisiblePosition& c) 3888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 3898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project VisiblePosition visPos = startPositionForLine(c); 3908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3912fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return c.honorEditableBoundaryAtOrBefore(visPos); 3928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 3938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic VisiblePosition endPositionForLine(const VisiblePosition& c) 3958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 3968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (c.isNull()) 3978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 3988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 3998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RootInlineBox *rootBox = rootBoxForLine(c); 4008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!rootBox) { 4018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // There are VisiblePositions at offset 0 in blocks without 4028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // RootInlineBoxes, like empty editable blocks and bordered blocks. 4038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position p = c.deepEquivalent(); 40481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (p.deprecatedNode()->renderer() && p.deprecatedNode()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset()) 4058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return c; 4068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 4078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 4088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 4098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Generated content (e.g. list markers and CSS :before and :after 4108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // pseudoelements) have no corresponding DOM element, and so cannot be 4118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // represented by a VisiblePosition. Use whatever precedes instead. 4128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Node *endNode; 4138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project InlineBox *endBox = rootBox->lastLeafChild(); 4148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project while (1) { 4158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!endBox) 4168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 4178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 4188f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian RenderObject *endRenderer = endBox->renderer(); 4198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!endRenderer) 4208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 4218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 4228f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian endNode = endRenderer->node(); 4238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (endNode) 4248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project break; 4258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 4268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project endBox = endBox->prevLeafChild(); 4278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 4288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 42981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch Position pos; 4308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (endNode->hasTagName(brTag)) { 43181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch pos = positionBeforeNode(endNode); 4328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } else if (endBox->isInlineTextBox()) { 4338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project InlineTextBox *endTextBox = static_cast<InlineTextBox *>(endBox); 43481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch int endOffset = endTextBox->start(); 4358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!endTextBox->isLineBreak()) 436635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project endOffset += endTextBox->len(); 43781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch pos = Position(endNode, endOffset, Position::PositionIsOffsetInAnchor); 43881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch } else 43981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch pos = positionAfterNode(endNode); 4408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 44181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE); 4428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 4438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 4448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition endOfLine(const VisiblePosition& c) 4458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 4468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project VisiblePosition visPos = endPositionForLine(c); 4478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 4488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The 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 4498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // obtain end of line. This condition happens when the input position is before the space character at the end 4508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // of a soft-wrapped non-editable line. In this scenario, endPositionForLine would incorrectly hand back a position 4518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The 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 4528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // versus lines without that style, which would break before a space by default. 4538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!inSameLine(c, visPos)) { 4548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project visPos = c.previous(); 4558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (visPos.isNull()) 4568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 4578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project visPos = endPositionForLine(visPos); 4588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 4598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 4602fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return c.honorEditableBoundaryAtOrAfter(visPos); 4618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 4628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 4638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool inSameLine(const VisiblePosition &a, const VisiblePosition &b) 4648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 4658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return a.isNotNull() && startOfLine(a) == startOfLine(b); 4668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 4678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 4688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool isStartOfLine(const VisiblePosition &p) 4698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 4708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return p.isNotNull() && p == startOfLine(p); 4718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 4728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 4738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool isEndOfLine(const VisiblePosition &p) 4748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 4758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return p.isNotNull() && p == endOfLine(p); 4768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 4778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 4788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// The first leaf before node that has the same editability as node. 4798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic Node* previousLeafWithSameEditability(Node* node) 4808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 4812bde8e466a4451c7319e3a072d118917957d6554Steve Block bool editable = node->rendererIsEditable(); 4828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Node* n = node->previousLeafNode(); 4838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project while (n) { 4842bde8e466a4451c7319e3a072d118917957d6554Steve Block if (editable == n->rendererIsEditable()) 4858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return n; 4868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = n->previousLeafNode(); 4878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 4888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return 0; 4898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 4908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 4915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic Node* enclosingNodeWithNonInlineRenderer(Node* n) 4925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 4935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian for (Node* p = n; p; p = p->parentNode()) { 4945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (p->renderer() && !p->renderer()->isInline()) 4955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return p; 4965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 4975f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return 0; 4985f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 4995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 5008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition previousLinePosition(const VisiblePosition &visiblePosition, int x) 5018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 5028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position p = visiblePosition.deepEquivalent(); 50381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch Node* node = p.deprecatedNode(); 5048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Node* highestRoot = highestEditableRoot(p); 5058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!node) 5068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 5078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 5088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project node->document()->updateLayoutIgnorePendingStylesheets(); 5098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 5108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RenderObject *renderer = node->renderer(); 5118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!renderer) 5128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 5138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 5148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RenderBlock *containingBlock = 0; 5158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RootInlineBox *root = 0; 5168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project InlineBox* box; 5178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project int ignoredCaretOffset; 5188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset); 5198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (box) { 5208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project root = box->root()->prevRootBox(); 521dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // We want to skip zero height boxes. 522dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // This could happen in case it is a TrailingFloatsRootInlineBox. 523bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen if (root && root->logicalHeight()) 5248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project containingBlock = renderer->containingBlock(); 525dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block else 526dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block root = 0; 5278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 5288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 5298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!root) { 5308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // This containing editable block does not have a previous line. 5318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Need to move back to previous containing editable block in this root editable 5328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // block and find the last root line box in that block. 5335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Node* startBlock = enclosingNodeWithNonInlineRenderer(node); 5348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Node* n = previousLeafWithSameEditability(node); 5355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian while (n && startBlock == enclosingNodeWithNonInlineRenderer(n)) 5368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = previousLeafWithSameEditability(n); 5378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project while (n) { 5382fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (highestEditableRoot(firstPositionInOrBeforeNode(n)) != highestRoot) 5398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project break; 5408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position pos(n, caretMinOffset(n)); 5418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (pos.isCandidate()) { 542dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block RenderObject* o = n->renderer(); 543dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block ASSERT(o); 544dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (canHaveCursor(o)) { 545dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block Position maxPos(n, caretMaxOffset(n)); 546dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block maxPos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset); 547dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block if (box) { 548dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // previous root line box found 549dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block root = box->root(); 550dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block containingBlock = n->renderer()->containingBlock(); 551dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block break; 552dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block } 553dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block 554dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block return VisiblePosition(pos, DOWNSTREAM); 5558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 5568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 5578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = previousLeafWithSameEditability(n); 5588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 5598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 5608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 5618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (root) { 562635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // FIXME: Can be wrong for multi-column layout and with transforms. 563635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project FloatPoint absPos = containingBlock->localToAbsolute(FloatPoint()); 5648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (containingBlock->hasOverflowClip()) 565635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project absPos -= containingBlock->layer()->scrolledContentOffset(); 5666b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner RenderObject* renderer = root->closestLeafChildForLogicalLeftPosition(x - absPos.x(), isEditablePosition(p))->renderer(); 567635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project Node* node = renderer->node(); 5685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (node && editingIgnoresContent(node)) 5692fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return positionInParentBeforeNode(node); 570231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return renderer->positionForPoint(IntPoint(x - absPos.x(), root->lineTop())); 5718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 5728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 5738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Could not find a previous line. This means we must already be on the first line. 5748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Move to the start of the content in this block, which effectively moves us 5758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // to the start of the line we're on. 5762bde8e466a4451c7319e3a072d118917957d6554Steve Block Element* rootElement = node->rendererIsEditable() ? node->rootEditableElement() : node->document()->documentElement(); 5772bde8e466a4451c7319e3a072d118917957d6554Steve Block if (!rootElement) 5782bde8e466a4451c7319e3a072d118917957d6554Steve Block return VisiblePosition(); 57981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return VisiblePosition(firstPositionInNode(rootElement), DOWNSTREAM); 5808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 5818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 5828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic Node* nextLeafWithSameEditability(Node* node, int offset) 5838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 5842bde8e466a4451c7319e3a072d118917957d6554Steve Block bool editable = node->rendererIsEditable(); 5858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ASSERT(offset >= 0); 5868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Node* child = node->childNode(offset); 5872fc2651226baac27029e38c9d6ef883fa32084dbSteve Block Node* n = child ? child->nextLeafNode() : node->lastDescendant()->nextLeafNode(); 5888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project while (n) { 5892bde8e466a4451c7319e3a072d118917957d6554Steve Block if (editable == n->rendererIsEditable()) 5908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return n; 5918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = n->nextLeafNode(); 5928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 5938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return 0; 5948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 5958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 5968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectstatic Node* nextLeafWithSameEditability(Node* node) 5978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 5988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!node) 5998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return 0; 6008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 6012bde8e466a4451c7319e3a072d118917957d6554Steve Block bool editable = node->rendererIsEditable(); 6028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Node* n = node->nextLeafNode(); 6038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project while (n) { 6042bde8e466a4451c7319e3a072d118917957d6554Steve Block if (editable == n->rendererIsEditable()) 6058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return n; 6068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = n->nextLeafNode(); 6078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 6088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return 0; 6098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 6108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 6118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition nextLinePosition(const VisiblePosition &visiblePosition, int x) 6128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 6138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position p = visiblePosition.deepEquivalent(); 61481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch Node* node = p.deprecatedNode(); 6158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Node* highestRoot = highestEditableRoot(p); 6168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!node) 6178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 6188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 6198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project node->document()->updateLayoutIgnorePendingStylesheets(); 6208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 6218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RenderObject *renderer = node->renderer(); 6228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!renderer) 6238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 6248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 6258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RenderBlock *containingBlock = 0; 6268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RootInlineBox *root = 0; 6278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project InlineBox* box; 6288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project int ignoredCaretOffset; 6298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project visiblePosition.getInlineBoxAndOffset(box, ignoredCaretOffset); 6308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (box) { 6318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project root = box->root()->nextRootBox(); 632dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // We want to skip zero height boxes. 633dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block // This could happen in case it is a TrailingFloatsRootInlineBox. 634bec39347bb3bb5bf1187ccaf471d26247f28b585Kristian Monsen if (root && root->logicalHeight()) 6358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project containingBlock = renderer->containingBlock(); 636dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block else 637dcc8cf2e65d1aa555cce12431a16547e66b469eeSteve Block root = 0; 6388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 6398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 6408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!root) { 6418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // This containing editable block does not have a next line. 6428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Need to move forward to next containing editable block in this root editable 6438e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // block and find the first root line box in that block. 6445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Node* startBlock = enclosingNodeWithNonInlineRenderer(node); 6455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Node* n = nextLeafWithSameEditability(node, p.deprecatedEditingOffset()); 6465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian while (n && startBlock == enclosingNodeWithNonInlineRenderer(n)) 6478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = nextLeafWithSameEditability(n); 6488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project while (n) { 6492fc2651226baac27029e38c9d6ef883fa32084dbSteve Block if (highestEditableRoot(firstPositionInOrBeforeNode(n)) != highestRoot) 6508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project break; 6518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position pos(n, caretMinOffset(n)); 6528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (pos.isCandidate()) { 6538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project ASSERT(n->renderer()); 6548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project pos.getInlineBoxAndOffset(DOWNSTREAM, box, ignoredCaretOffset); 6558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (box) { 6568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // next root line box found 6578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project root = box->root(); 6588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project containingBlock = n->renderer()->containingBlock(); 6598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project break; 6608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 6618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 6628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(pos, DOWNSTREAM); 6638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 6648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = nextLeafWithSameEditability(n); 6658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 6668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 6678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 6688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (root) { 669635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project // FIXME: Can be wrong for multi-column layout and with transforms. 670635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project FloatPoint absPos = containingBlock->localToAbsolute(FloatPoint()); 6718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (containingBlock->hasOverflowClip()) 672635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project absPos -= containingBlock->layer()->scrolledContentOffset(); 6736b70adc33054f8aee8c54d0f460458a9df11b8a5Russell Brenner RenderObject* renderer = root->closestLeafChildForLogicalLeftPosition(x - absPos.x(), isEditablePosition(p))->renderer(); 674635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project Node* node = renderer->node(); 6755f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (node && editingIgnoresContent(node)) 6762fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return positionInParentBeforeNode(node); 677231d4e3152a9c27a73b6ac7badbe6be673aa3ddfSteve Block return renderer->positionForPoint(IntPoint(x - absPos.x(), root->lineTop())); 6788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 6798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 6808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Could not find a next line. This means we must already be on the last line. 6818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // Move to the end of the content in this block, which effectively moves us 6828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // to the end of the line we're on. 6832bde8e466a4451c7319e3a072d118917957d6554Steve Block Element* rootElement = node->rendererIsEditable() ? node->rootEditableElement() : node->document()->documentElement(); 6842bde8e466a4451c7319e3a072d118917957d6554Steve Block if (!rootElement) 6852bde8e466a4451c7319e3a072d118917957d6554Steve Block return VisiblePosition(); 68681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return VisiblePosition(lastPositionInNode(rootElement), DOWNSTREAM); 6878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 6888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 6898e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// --------- 6908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 6915f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned startSentenceBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&) 6928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 6938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project TextBreakIterator* iterator = sentenceBreakIterator(characters, length); 6948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // FIXME: The following function can return -1; we don't handle that. 6958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return textBreakPreceding(iterator, length); 6968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 6978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 6988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition startOfSentence(const VisiblePosition &c) 6998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 7008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return previousBoundary(c, startSentenceBoundary); 7018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 7028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 7035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned endSentenceBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&) 7048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 7058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project TextBreakIterator* iterator = sentenceBreakIterator(characters, length); 7068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return textBreakNext(iterator); 7078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 7088e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 7098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// FIXME: This includes the space after the punctuation that marks the end of the sentence. 7108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition endOfSentence(const VisiblePosition &c) 7118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 7128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return nextBoundary(c, endSentenceBoundary); 7138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 7148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 7155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned previousSentencePositionBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&) 7168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 7178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // FIXME: This is identical to startSentenceBoundary. I'm pretty sure that's not right. 7188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project TextBreakIterator* iterator = sentenceBreakIterator(characters, length); 7198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // FIXME: The following function can return -1; we don't handle that. 7208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return textBreakPreceding(iterator, length); 7218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 7228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 7238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition previousSentencePosition(const VisiblePosition &c) 7248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 7258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project VisiblePosition prev = previousBoundary(c, previousSentencePositionBoundary); 7262fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return c.honorEditableBoundaryAtOrBefore(prev); 7278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 7288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 7295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic unsigned nextSentencePositionBoundary(const UChar* characters, unsigned length, unsigned, BoundarySearchContextAvailability, bool&) 7308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 7318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // FIXME: This is identical to endSentenceBoundary. This isn't right, it needs to 7328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // move to the equivlant position in the following sentence. 7338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project TextBreakIterator* iterator = sentenceBreakIterator(characters, length); 7348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return textBreakFollowing(iterator, 0); 7358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 7368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 7378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition nextSentencePosition(const VisiblePosition &c) 7388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 7398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project VisiblePosition next = nextBoundary(c, nextSentencePositionBoundary); 7402fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return c.honorEditableBoundaryAtOrAfter(next); 7418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 7428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 7434576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) WangVisiblePosition startOfParagraph(const VisiblePosition& c, EditingBoundaryCrossingRule boundaryCrossingRule) 7448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 7458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position p = c.deepEquivalent(); 74681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch Node* startNode = p.deprecatedNode(); 7478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 7488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!startNode) 7498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 7508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 751643ca7872b450ea4efacab6188849e5aac2ba161Steve Block if (isRenderedAsNonInlineTableImageOrHR(startNode)) 7522bde8e466a4451c7319e3a072d118917957d6554Steve Block return positionBeforeNode(startNode); 7538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 7548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Node* startBlock = enclosingBlock(startNode); 7558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 7562bde8e466a4451c7319e3a072d118917957d6554Steve Block Node* node = startNode; 7572bde8e466a4451c7319e3a072d118917957d6554Steve Block Node* highestRoot = highestEditableRoot(p); 7585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int offset = p.deprecatedEditingOffset(); 75981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch Position::AnchorType type = p.anchorType(); 7608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 7612bde8e466a4451c7319e3a072d118917957d6554Steve Block Node* n = startNode; 7628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project while (n) { 7632bde8e466a4451c7319e3a072d118917957d6554Steve Block if (boundaryCrossingRule == CannotCrossEditingBoundary && n->rendererIsEditable() != startNode->rendererIsEditable()) 7648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project break; 7652bde8e466a4451c7319e3a072d118917957d6554Steve Block if (boundaryCrossingRule == CanSkipOverEditingBoundary) { 7662bde8e466a4451c7319e3a072d118917957d6554Steve Block while (n && n->rendererIsEditable() != startNode->rendererIsEditable()) 7672bde8e466a4451c7319e3a072d118917957d6554Steve Block n = n->traversePreviousNodePostOrder(startBlock); 7682bde8e466a4451c7319e3a072d118917957d6554Steve Block if (!n || !n->isDescendantOf(highestRoot)) 7692bde8e466a4451c7319e3a072d118917957d6554Steve Block break; 7702bde8e466a4451c7319e3a072d118917957d6554Steve Block } 7718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RenderObject *r = n->renderer(); 7728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!r) { 7738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = n->traversePreviousNodePostOrder(startBlock); 7748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project continue; 7758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 7768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RenderStyle *style = r->style(); 7778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (style->visibility() != VISIBLE) { 7788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = n->traversePreviousNodePostOrder(startBlock); 7798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project continue; 7808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 7818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 7828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (r->isBR() || isBlock(n)) 7838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project break; 784e14391e94c850b8bd03680c23b38978db68687a8John Reck 785e14391e94c850b8bd03680c23b38978db68687a8John Reck if (r->isText() && r->caretMaxRenderedOffset() > 0) { 78681bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch type = Position::PositionIsOffsetInAnchor; 7878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (style->preserveNewline()) { 788635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const UChar* chars = toRenderText(r)->characters(); 789635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int i = toRenderText(r)->textLength(); 7908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project int o = offset; 7918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (n == startNode && o < i) 7928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project i = max(0, o); 7938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project while (--i >= 0) 7948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (chars[i] == '\n') 79581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return VisiblePosition(Position(n, i + 1, Position::PositionIsOffsetInAnchor), DOWNSTREAM); 7968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 7978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project node = n; 7988e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project offset = 0; 7998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = n->traversePreviousNodePostOrder(startBlock); 8008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } else if (editingIgnoresContent(n) || isTableElement(n)) { 8018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project node = n; 80281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch type = Position::PositionIsBeforeAnchor; 8038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = n->previousSibling() ? n->previousSibling() : n->traversePreviousNodePostOrder(startBlock); 8048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } else 8058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = n->traversePreviousNodePostOrder(startBlock); 8068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 8078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 80881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (type == Position::PositionIsOffsetInAnchor) 80981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return VisiblePosition(Position(node, offset, type), DOWNSTREAM); 81081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch 81181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return VisiblePosition(Position(node, type), DOWNSTREAM); 8128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 8138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 8144576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) WangVisiblePosition endOfParagraph(const VisiblePosition &c, EditingBoundaryCrossingRule boundaryCrossingRule) 8158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 8168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (c.isNull()) 8178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 8188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 8198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position p = c.deepEquivalent(); 82081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch Node* startNode = p.deprecatedNode(); 8218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 822643ca7872b450ea4efacab6188849e5aac2ba161Steve Block if (isRenderedAsNonInlineTableImageOrHR(startNode)) 8232bde8e466a4451c7319e3a072d118917957d6554Steve Block return positionAfterNode(startNode); 8248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 8258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Node* startBlock = enclosingBlock(startNode); 8262bde8e466a4451c7319e3a072d118917957d6554Steve Block Node* stayInsideBlock = startBlock; 8278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 8282bde8e466a4451c7319e3a072d118917957d6554Steve Block Node* node = startNode; 8292bde8e466a4451c7319e3a072d118917957d6554Steve Block Node* highestRoot = highestEditableRoot(p); 8305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian int offset = p.deprecatedEditingOffset(); 83181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch Position::AnchorType type = p.anchorType(); 8328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 8332bde8e466a4451c7319e3a072d118917957d6554Steve Block Node* n = startNode; 8348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project while (n) { 8352bde8e466a4451c7319e3a072d118917957d6554Steve Block if (boundaryCrossingRule == CannotCrossEditingBoundary && n->rendererIsEditable() != startNode->rendererIsEditable()) 8368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project break; 8372bde8e466a4451c7319e3a072d118917957d6554Steve Block if (boundaryCrossingRule == CanSkipOverEditingBoundary) { 8382bde8e466a4451c7319e3a072d118917957d6554Steve Block while (n && n->rendererIsEditable() != startNode->rendererIsEditable()) 8392bde8e466a4451c7319e3a072d118917957d6554Steve Block n = n->traverseNextNode(stayInsideBlock); 8402bde8e466a4451c7319e3a072d118917957d6554Steve Block if (!n || !n->isDescendantOf(highestRoot)) 8412bde8e466a4451c7319e3a072d118917957d6554Steve Block break; 8422bde8e466a4451c7319e3a072d118917957d6554Steve Block } 8432bde8e466a4451c7319e3a072d118917957d6554Steve Block 8448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RenderObject *r = n->renderer(); 8458e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!r) { 8468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = n->traverseNextNode(stayInsideBlock); 8478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project continue; 8488e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 8498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project RenderStyle *style = r->style(); 8508e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (style->visibility() != VISIBLE) { 8518e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = n->traverseNextNode(stayInsideBlock); 8528e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project continue; 8538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 8548e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 8558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (r->isBR() || isBlock(n)) 8568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project break; 857e14391e94c850b8bd03680c23b38978db68687a8John Reck 8588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // FIXME: We avoid returning a position where the renderer can't accept the caret. 8598e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (r->isText() && r->caretMaxRenderedOffset() > 0) { 860635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project int length = toRenderText(r)->textLength(); 86181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch type = Position::PositionIsOffsetInAnchor; 8628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (style->preserveNewline()) { 863635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project const UChar* chars = toRenderText(r)->characters(); 8648e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project int o = n == startNode ? offset : 0; 8658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project for (int i = o; i < length; ++i) 8668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (chars[i] == '\n') 86781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return VisiblePosition(Position(n, i, Position::PositionIsOffsetInAnchor), DOWNSTREAM); 8688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 8698e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project node = n; 8708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project offset = r->caretMaxOffset(); 8718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = n->traverseNextNode(stayInsideBlock); 8728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } else if (editingIgnoresContent(n) || isTableElement(n)) { 8738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project node = n; 87481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch type = Position::PositionIsAfterAnchor; 8758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = n->traverseNextSibling(stayInsideBlock); 8768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } else 8778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project n = n->traverseNextNode(stayInsideBlock); 8788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } 8798e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 88081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (type == Position::PositionIsOffsetInAnchor) 88181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return VisiblePosition(Position(node, offset, type), DOWNSTREAM); 88281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch 88381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return VisiblePosition(Position(node, type), DOWNSTREAM); 8848e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 8858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 8862bde8e466a4451c7319e3a072d118917957d6554Steve Block// FIXME: isStartOfParagraph(startOfNextParagraph(pos)) is not always true 8878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition startOfNextParagraph(const VisiblePosition& visiblePosition) 8888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 8892bde8e466a4451c7319e3a072d118917957d6554Steve Block VisiblePosition paragraphEnd(endOfParagraph(visiblePosition, CanSkipOverEditingBoundary)); 8902bde8e466a4451c7319e3a072d118917957d6554Steve Block VisiblePosition afterParagraphEnd(paragraphEnd.next(CannotCrossEditingBoundary)); 8918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // The position after the last position in the last cell of a table 8928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project // is not the start of the next paragraph. 8938e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (isFirstPositionAfterTable(afterParagraphEnd)) 8942bde8e466a4451c7319e3a072d118917957d6554Steve Block return afterParagraphEnd.next(CannotCrossEditingBoundary); 8958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return afterParagraphEnd; 8968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 8978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 8982bde8e466a4451c7319e3a072d118917957d6554Steve Blockbool inSameParagraph(const VisiblePosition &a, const VisiblePosition &b, EditingBoundaryCrossingRule boundaryCrossingRule) 8998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 9002bde8e466a4451c7319e3a072d118917957d6554Steve Block return a.isNotNull() && startOfParagraph(a, boundaryCrossingRule) == startOfParagraph(b, boundaryCrossingRule); 9018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 9028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9034576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangbool isStartOfParagraph(const VisiblePosition &pos, EditingBoundaryCrossingRule boundaryCrossingRule) 9048e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 905e14391e94c850b8bd03680c23b38978db68687a8John Reck return pos.isNotNull() && pos == startOfParagraph(pos, boundaryCrossingRule); 9068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 9078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9084576aa36e9a9671459299c7963ac95aa94beaea9Shimeng (Simon) Wangbool isEndOfParagraph(const VisiblePosition &pos, EditingBoundaryCrossingRule boundaryCrossingRule) 9098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 910e14391e94c850b8bd03680c23b38978db68687a8John Reck return pos.isNotNull() && pos == endOfParagraph(pos, boundaryCrossingRule); 9118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 9128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9138f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng QianVisiblePosition previousParagraphPosition(const VisiblePosition& p, int x) 9148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 9158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project VisiblePosition pos = p; 9168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project do { 9178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project VisiblePosition n = previousLinePosition(pos, x); 9188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (n.isNull() || n == pos) 9198f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian break; 9208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project pos = n; 9218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } while (inSameParagraph(p, pos)); 9228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return pos; 9238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 9248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9258f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng QianVisiblePosition nextParagraphPosition(const VisiblePosition& p, int x) 9268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 9278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project VisiblePosition pos = p; 9288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project do { 9298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project VisiblePosition n = nextLinePosition(pos, x); 9308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (n.isNull() || n == pos) 9318f72e70a9fd78eec56623b3a62e68f16b7b27e28Feng Qian break; 9328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project pos = n; 9338e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project } while (inSameParagraph(p, pos)); 9348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return pos; 9358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 9368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// --------- 9388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9392bde8e466a4451c7319e3a072d118917957d6554Steve BlockVisiblePosition startOfBlock(const VisiblePosition& visiblePosition, EditingBoundaryCrossingRule rule) 9408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 9412bde8e466a4451c7319e3a072d118917957d6554Steve Block Position position = visiblePosition.deepEquivalent(); 9422bde8e466a4451c7319e3a072d118917957d6554Steve Block Node* startBlock; 9432bde8e466a4451c7319e3a072d118917957d6554Steve Block if (!position.containerNode() || !(startBlock = enclosingBlock(position.containerNode(), rule))) 9448e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 9452bde8e466a4451c7319e3a072d118917957d6554Steve Block return firstPositionInNode(startBlock); 9468e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 9478e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9482bde8e466a4451c7319e3a072d118917957d6554Steve BlockVisiblePosition endOfBlock(const VisiblePosition& visiblePosition, EditingBoundaryCrossingRule rule) 9498e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 9502bde8e466a4451c7319e3a072d118917957d6554Steve Block Position position = visiblePosition.deepEquivalent(); 9512bde8e466a4451c7319e3a072d118917957d6554Steve Block Node* endBlock; 9522bde8e466a4451c7319e3a072d118917957d6554Steve Block if (!position.containerNode() || !(endBlock = enclosingBlock(position.containerNode(), rule))) 9538e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 9542bde8e466a4451c7319e3a072d118917957d6554Steve Block return lastPositionInNode(endBlock); 9558e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 9568e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9578e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool inSameBlock(const VisiblePosition &a, const VisiblePosition &b) 9588e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 9592bde8e466a4451c7319e3a072d118917957d6554Steve Block return !a.isNull() && enclosingBlock(a.deepEquivalent().containerNode()) == enclosingBlock(b.deepEquivalent().containerNode()); 9608e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 9618e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9628e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool isStartOfBlock(const VisiblePosition &pos) 9638e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 9642bde8e466a4451c7319e3a072d118917957d6554Steve Block return pos.isNotNull() && pos == startOfBlock(pos, CanCrossEditingBoundary); 9658e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 9668e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9678e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool isEndOfBlock(const VisiblePosition &pos) 9688e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 9692bde8e466a4451c7319e3a072d118917957d6554Steve Block return pos.isNotNull() && pos == endOfBlock(pos, CanCrossEditingBoundary); 9708e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 9718e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9728e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// --------- 9738e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9748e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition startOfDocument(const Node* node) 9758e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 9768e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!node) 9778e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 9788e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 97981bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return VisiblePosition(firstPositionInNode(node->document()->documentElement()), DOWNSTREAM); 9808e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 9818e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9828e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition startOfDocument(const VisiblePosition &c) 9838e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 98481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return startOfDocument(c.deepEquivalent().deprecatedNode()); 9858e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 9868e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9878e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition endOfDocument(const Node* node) 9888e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 989dd8bb3de4f353a81954234999f1fea748aee2ea9Ben Murdoch if (!node || !node->document() || !node->document()->documentElement()) 9908e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 9918e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9928e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Element* doc = node->document()->documentElement(); 99381bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return VisiblePosition(lastPositionInNode(doc), DOWNSTREAM); 9948e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 9958e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 9968e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition endOfDocument(const VisiblePosition &c) 9978e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 99881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return endOfDocument(c.deepEquivalent().deprecatedNode()); 9998e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 10008e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 10018e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool inSameDocument(const VisiblePosition &a, const VisiblePosition &b) 10028e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 10038e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position ap = a.deepEquivalent(); 100481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch Node* an = ap.deprecatedNode(); 10058e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!an) 10068e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return false; 10078e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Position bp = b.deepEquivalent(); 100881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch Node* bn = bp.deprecatedNode(); 10098e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (an == bn) 10108e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return true; 10118e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 10128e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return an->document() == bn->document(); 10138e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 10148e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 10158e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool isStartOfDocument(const VisiblePosition &p) 10168e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 10178e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return p.isNotNull() && p.previous().isNull(); 10188e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 10198e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 10208e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Projectbool isEndOfDocument(const VisiblePosition &p) 10218e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 10228e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return p.isNotNull() && p.next().isNull(); 10238e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 10248e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 10258e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project// --------- 10268e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 10278e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition startOfEditableContent(const VisiblePosition& visiblePosition) 10288e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 10298e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent()); 10308e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!highestRoot) 10318e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 10328e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 10332bde8e466a4451c7319e3a072d118917957d6554Steve Block return firstPositionInNode(highestRoot); 10348e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 10358e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 10368e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source ProjectVisiblePosition endOfEditableContent(const VisiblePosition& visiblePosition) 10378e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project{ 10388e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent()); 10398e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project if (!highestRoot) 10408e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project return VisiblePosition(); 10418e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project 10422bde8e466a4451c7319e3a072d118917957d6554Steve Block return lastPositionInNode(highestRoot); 10435f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 10445f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10455f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic VisiblePosition logicalStartPositionForLine(const VisiblePosition& c) 10465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 10475f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (c.isNull()) 10485f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return VisiblePosition(); 10495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10505f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian RootInlineBox* rootBox = rootBoxForLine(c); 10515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!rootBox) { 10525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // There are VisiblePositions at offset 0 in blocks without 10535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // RootInlineBoxes, like empty editable blocks and bordered blocks. 10545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Position p = c.deepEquivalent(); 105581bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (p.deprecatedNode()->renderer() && p.deprecatedNode()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset()) 10565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return positionAvoidingFirstPositionInTable(c); 10575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return VisiblePosition(); 10595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 10605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian InlineBox* logicalStartBox; 10622bde8e466a4451c7319e3a072d118917957d6554Steve Block Node* logicalStartNode = rootBox->getLogicalStartBoxWithNode(logicalStartBox); 10635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!logicalStartNode) 10655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return VisiblePosition(); 10665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 106781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch VisiblePosition visPos = logicalStartNode->isTextNode() ? VisiblePosition(Position(logicalStartNode, logicalStartBox->caretMinOffset(), Position::PositionIsOffsetInAnchor), DOWNSTREAM) 106881bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch : VisiblePosition(positionBeforeNode(logicalStartNode), DOWNSTREAM); 10695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return positionAvoidingFirstPositionInTable(visPos); 10705f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 10715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10725f1ab04193ad0130ca8204aadaceae083aca9881Feng QianVisiblePosition logicalStartOfLine(const VisiblePosition& c) 10735f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 1074cad810f21b803229eb11403f9209855525a25d57Steve Block // TODO: this is the current behavior that might need to be fixed. 1075cad810f21b803229eb11403f9209855525a25d57Steve Block // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail. 10765f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian VisiblePosition visPos = logicalStartPositionForLine(c); 10775f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10782fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return c.honorEditableBoundaryAtOrBefore(visPos); 10795f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 10805f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10815f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianstatic VisiblePosition logicalEndPositionForLine(const VisiblePosition& c) 10825f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 10835f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (c.isNull()) 10845f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return VisiblePosition(); 10855f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10865f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian RootInlineBox* rootBox = rootBoxForLine(c); 10875f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!rootBox) { 10885f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // There are VisiblePositions at offset 0 in blocks without 10895f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // RootInlineBoxes, like empty editable blocks and bordered blocks. 10905f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian Position p = c.deepEquivalent(); 109181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch if (p.deprecatedNode()->renderer() && p.deprecatedNode()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset()) 10925f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return c; 10935f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return VisiblePosition(); 10945f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian } 10955f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 10965f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian InlineBox* logicalEndBox; 10972bde8e466a4451c7319e3a072d118917957d6554Steve Block Node* logicalEndNode = rootBox->getLogicalEndBoxWithNode(logicalEndBox); 10982bde8e466a4451c7319e3a072d118917957d6554Steve Block 10995f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!logicalEndNode) 11005f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return VisiblePosition(); 11015f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 110281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch Position pos; 11035f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (logicalEndNode->hasTagName(brTag)) 110481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch pos = positionBeforeNode(logicalEndNode); 11055f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian else if (logicalEndBox->isInlineTextBox()) { 11065f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian InlineTextBox* endTextBox = static_cast<InlineTextBox*>(logicalEndBox); 110781bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch int endOffset = endTextBox->start(); 11085f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!endTextBox->isLineBreak()) 11095f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian endOffset += endTextBox->len(); 111081bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch pos = Position(logicalEndNode, endOffset, Position::PositionIsOffsetInAnchor); 111181bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch } else 111281bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch pos = positionAfterNode(logicalEndNode); 11135f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 111481bc750723a18f21cd17d1b173cd2a4dda9cea6eBen Murdoch return VisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE); 11155f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 11165f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 11175f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianbool inSameLogicalLine(const VisiblePosition& a, const VisiblePosition& b) 11185f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 11195f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian return a.isNotNull() && logicalStartOfLine(a) == logicalStartOfLine(b); 11205f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 11215f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 11225f1ab04193ad0130ca8204aadaceae083aca9881Feng QianVisiblePosition logicalEndOfLine(const VisiblePosition& c) 11235f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{ 1124cad810f21b803229eb11403f9209855525a25d57Steve Block // TODO: this is the current behavior that might need to be fixed. 1125cad810f21b803229eb11403f9209855525a25d57Steve Block // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail. 1126cad810f21b803229eb11403f9209855525a25d57Steve Block 11275f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian VisiblePosition visPos = logicalEndPositionForLine(c); 11285f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 11295f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // Make sure the end of line is at the same line as the given input position. For a wrapping line, the logical end 11305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // position for the not-last-2-lines might incorrectly hand back the logical beginning of the next line. 11315f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // For example, <div contenteditable dir="rtl" style="line-break:before-white-space">abcdefg abcdefg abcdefg 11325f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // a abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg </div> 11335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian // In this case, use the previous position of the computed logical end position. 11345f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian if (!inSameLogicalLine(c, visPos)) 11355f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian visPos = visPos.previous(); 11365f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 11372fc2651226baac27029e38c9d6ef883fa32084dbSteve Block return c.honorEditableBoundaryAtOrAfter(visPos); 11385f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian} 11395f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian 1140cad810f21b803229eb11403f9209855525a25d57Steve BlockVisiblePosition leftBoundaryOfLine(const VisiblePosition& c, TextDirection direction) 1141cad810f21b803229eb11403f9209855525a25d57Steve Block{ 1142cad810f21b803229eb11403f9209855525a25d57Steve Block return direction == LTR ? logicalStartOfLine(c) : logicalEndOfLine(c); 1143cad810f21b803229eb11403f9209855525a25d57Steve Block} 1144cad810f21b803229eb11403f9209855525a25d57Steve Block 1145cad810f21b803229eb11403f9209855525a25d57Steve BlockVisiblePosition rightBoundaryOfLine(const VisiblePosition& c, TextDirection direction) 1146cad810f21b803229eb11403f9209855525a25d57Steve Block{ 1147cad810f21b803229eb11403f9209855525a25d57Steve Block return direction == LTR ? logicalEndOfLine(c) : logicalStartOfLine(c); 1148cad810f21b803229eb11403f9209855525a25d57Steve Block} 1149cad810f21b803229eb11403f9209855525a25d57Steve Block 11502daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic const int invalidOffset = -1; 11512daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 11522daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic VisiblePosition previousWordBreakInBoxInsideBlockWithSameDirectionality(const InlineBox* box, const VisiblePosition& previousWordBreak, int& offsetOfWordBreak) 11532daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 11542daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch bool hasSeenWordBreakInThisBox = previousWordBreak.isNotNull(); 11552daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // In a LTR block, the word break should be on the left boundary of a word. 11562daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // In a RTL block, the word break should be on the right boundary of a word. 11572daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // Because nextWordPosition() returns the word break on the right boundary of the word for LTR text, 11582daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // we need to use previousWordPosition() to traverse words within the inline boxes from right to left 11592daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // to find the previous word break (i.e. the first word break on the left). The same applies to RTL text. 11602daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 11612daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition wordBreak = hasSeenWordBreakInThisBox ? previousWordBreak : Position(box->renderer()->node(), box->caretMaxOffset(), Position::PositionIsOffsetInAnchor); 11622daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 11632daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // FIXME: handle multi-spaces (http://webkit.org/b/57543). 11642daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 11652daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = previousWordPosition(wordBreak); 11662daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (previousWordBreak == wordBreak) 11672daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return VisiblePosition(); 11682daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 11692daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch InlineBox* boxContainingPreviousWordBreak; 11702daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak.getInlineBoxAndOffset(boxContainingPreviousWordBreak, offsetOfWordBreak); 11712daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (boxContainingPreviousWordBreak != box) 11722daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return VisiblePosition(); 11732daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return wordBreak; 11742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 11752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 11762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic VisiblePosition leftmostPositionInRTLBoxInLTRBlock(const InlineBox* box) 11772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 11782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // FIXME: Probably need to take care of bidi level too. 11792daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch Node* node = box->renderer()->node(); 11802daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch InlineBox* previousLeaf = box->prevLeafChild(); 11812daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch InlineBox* nextLeaf = box->nextLeafChild(); 11822daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 11832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (previousLeaf && !previousLeaf->isLeftToRightDirection()) 11842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return Position(node, box->caretMaxOffset(), Position::PositionIsOffsetInAnchor); 11852daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 11862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (nextLeaf && !nextLeaf->isLeftToRightDirection()) { 11872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (previousLeaf) 11882daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return Position(previousLeaf->renderer()->node(), previousLeaf->caretMaxOffset(), Position::PositionIsOffsetInAnchor); 11892daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 11902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch InlineBox* lastRTLLeaf; 11912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch do { 11922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch lastRTLLeaf = nextLeaf; 11932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch nextLeaf = nextLeaf->nextLeafChild(); 11942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } while (nextLeaf && !nextLeaf->isLeftToRightDirection()); 11952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return Position(lastRTLLeaf->renderer()->node(), lastRTLLeaf->caretMinOffset(), Position::PositionIsOffsetInAnchor); 11962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 11972daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 11982daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return Position(node, box->caretMinOffset(), Position::PositionIsOffsetInAnchor); 11992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 12002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic VisiblePosition rightmostPositionInLTRBoxInRTLBlock(const InlineBox* box) 12022daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 12032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // FIXME: Probably need to take care of bidi level too. 12042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch Node* node = box->renderer()->node(); 12052daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch InlineBox* previousLeaf = box->prevLeafChild(); 12062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch InlineBox* nextLeaf = box->nextLeafChild(); 12072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12082daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (nextLeaf && nextLeaf->isLeftToRightDirection()) 12092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return Position(node, box->caretMaxOffset(), Position::PositionIsOffsetInAnchor); 12102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (previousLeaf && previousLeaf->isLeftToRightDirection()) { 12122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (nextLeaf) 12132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return Position(nextLeaf->renderer()->node(), nextLeaf->caretMaxOffset(), Position::PositionIsOffsetInAnchor); 12142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch InlineBox* firstLTRLeaf; 12162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch do { 12172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch firstLTRLeaf = previousLeaf; 12182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch previousLeaf = previousLeaf->prevLeafChild(); 12192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } while (previousLeaf && previousLeaf->isLeftToRightDirection()); 12202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return Position(firstLTRLeaf->renderer()->node(), firstLTRLeaf->caretMinOffset(), Position::PositionIsOffsetInAnchor); 12212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 12222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return Position(node, box->caretMinOffset(), Position::PositionIsOffsetInAnchor); 12242daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 12252daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12262daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic VisiblePosition lastWordBreakInBox(const InlineBox* box, int& offsetOfWordBreak) 12272daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 12282daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // Add the leftmost word break for RTL box or rightmost word break for LTR box. 12292daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch InlineBox* previousLeaf = box->prevLeafChild(); 12302daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch InlineBox* nextLeaf = box->nextLeafChild(); 12312daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition boundaryPosition; 12322daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (box->direction() == RTL && (!previousLeaf || previousLeaf->isLeftToRightDirection())) 12332daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch boundaryPosition = leftmostPositionInRTLBoxInLTRBlock(box); 12342daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch else if (box->direction() == LTR && (!nextLeaf || !nextLeaf->isLeftToRightDirection())) 12352daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch boundaryPosition = rightmostPositionInLTRBoxInRTLBlock(box); 12362daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12372daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (boundaryPosition.isNull()) 12382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return VisiblePosition(); 12392daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition wordBreak = nextWordPosition(boundaryPosition); 12412daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (wordBreak != boundaryPosition) 12422daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = previousWordPosition(wordBreak); 12432daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12442daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch InlineBox* boxOfWordBreak; 12452daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak.getInlineBoxAndOffset(boxOfWordBreak, offsetOfWordBreak); 12462daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (boxOfWordBreak == box) 12472daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return wordBreak; 12482daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return VisiblePosition(); 12492daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 12502daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12512daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic bool positionIsVisuallyOrderedInBoxInBlockWithDifferentDirectionality(const VisiblePosition& wordBreak, const InlineBox* box, int& offsetOfWordBreak) 12522daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 12532daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int previousOffset = offsetOfWordBreak; 12542daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch InlineBox* boxOfWordBreak; 12552daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak.getInlineBoxAndOffset(boxOfWordBreak, offsetOfWordBreak); 12562daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (boxOfWordBreak == box && (previousOffset == invalidOffset || previousOffset < offsetOfWordBreak)) 12572daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return true; 12582daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return false; 12592daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 12602daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12612daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic VisiblePosition nextWordBreakInBoxInsideBlockWithDifferentDirectionality( 12622daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch const InlineBox* box, const VisiblePosition& previousWordBreak, int& offsetOfWordBreak, bool& isLastWordBreakInBox) 12632daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 12642daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // FIXME: Probably need to take care of bidi level too. 12652daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12662daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // In a LTR block, the word break should be on the left boundary of a word. 12672daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // In a RTL block, the word break should be on the right boundary of a word. 12682daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // Because previousWordPosition() returns the word break on the right boundary of the word for RTL text, 12692daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // we need to use nextWordPosition() to traverse words within the inline boxes from right to left to find the next word break. 12702daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // The same applies to LTR text, in which words are traversed within the inline boxes from left to right. 12712daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12722daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // FIXME: handle multi-spaces (http://webkit.org/b/57543). 12732daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch bool hasSeenWordBreakInThisBox = previousWordBreak.isNotNull(); 12752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition wordBreak = hasSeenWordBreakInThisBox ? previousWordBreak : Position(box->renderer()->node(), box->caretMinOffset(), Position::PositionIsOffsetInAnchor); 12762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = nextWordPosition(wordBreak); 12772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (wordBreak == previousWordBreak) { 12792daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch isLastWordBreakInBox = true; 12802daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return VisiblePosition(); 12812daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 12822daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // Given RTL box "ABC DEF" either follows a LTR box or is the first visual box in an LTR block as an example, 12852daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // the visual display of the RTL box is: "(0)J(10)I(9)H(8) (7)F(6)E(5)D(4) (3)C(2)B(1)A(11)", 12862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // where the number in parenthesis represents offset in visiblePosition. 12872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // Start at offset 0, the first word break is at offset 3, the 2nd word break is at offset 7, and the 3rd word break should be at offset 0. 12882daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // But nextWordPosition() of offset 7 is offset 11, which should be ignored, 12892daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // and the position at offset 0 should be manually added as the last word break within the box. 12902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (positionIsVisuallyOrderedInBoxInBlockWithDifferentDirectionality(wordBreak, box, offsetOfWordBreak)) { 12912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch isLastWordBreakInBox = false; 12922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return wordBreak; 12932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 12942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch isLastWordBreakInBox = true; 12962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return lastWordBreakInBox(box, offsetOfWordBreak); 12972daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 12982daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 12992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstruct WordBoundaryEntry { 13002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch WordBoundaryEntry() 13012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch : offsetInInlineBox(invalidOffset) 13022daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch { 13032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 13042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 13052daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch WordBoundaryEntry(const VisiblePosition& position, int offset) 13062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch : visiblePosition(position) 13072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch , offsetInInlineBox(offset) 13082daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch { 13092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 13102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 13112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition visiblePosition; 13122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int offsetInInlineBox; 13132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch}; 13142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 13152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochtypedef Vector<WordBoundaryEntry, 50> WordBoundaryVector; 13162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 13172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic void collectWordBreaksInBoxInsideBlockWithSameDirectionality(const InlineBox* box, WordBoundaryVector& orderedWordBoundaries) 13182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 13192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch orderedWordBoundaries.clear(); 13202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 13212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition wordBreak; 13222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int offsetOfWordBreak = invalidOffset; 13232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch while (1) { 13242daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = previousWordBreakInBoxInsideBlockWithSameDirectionality(box, wordBreak, offsetOfWordBreak); 13252daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (wordBreak.isNull()) 13262daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch break; 13272daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch WordBoundaryEntry wordBoundaryEntry(wordBreak, offsetOfWordBreak); 13282daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch orderedWordBoundaries.append(wordBoundaryEntry); 13292daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 13302daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 13312daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 13322daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic void collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(const InlineBox* box, WordBoundaryVector& orderedWordBoundaries) 13332daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 13342daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch orderedWordBoundaries.clear(); 13352daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 13362daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition wordBreak; 13372daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int offsetOfWordBreak = invalidOffset; 13382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch while (1) { 13392daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch bool isLastWordBreakInBox = false; 13402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = nextWordBreakInBoxInsideBlockWithDifferentDirectionality(box, wordBreak, offsetOfWordBreak, isLastWordBreakInBox); 13412daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (wordBreak.isNotNull()) { 13422daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch WordBoundaryEntry wordBoundaryEntry(wordBreak, offsetOfWordBreak); 13432daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch orderedWordBoundaries.append(wordBoundaryEntry); 13442daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 13452daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (isLastWordBreakInBox) 13462daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch break; 13472daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 13482daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 13492daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 13502daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic VisiblePosition previousWordBreakInBox(const InlineBox* box, int offset, TextDirection blockDirection) 13512daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 13522daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int offsetOfWordBreak = 0; 13532daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition wordBreak; 13542daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch while (true) { 13552daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (box->direction() == blockDirection) 13562daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = previousWordBreakInBoxInsideBlockWithSameDirectionality(box, wordBreak, offsetOfWordBreak); 13572daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // FIXME: Implement the 'else' case when the box direction is not equal to the block direction. 13582daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (wordBreak.isNull()) 13592daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch break; 13602daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (offset == invalidOffset || offsetOfWordBreak != offset) 13612daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return wordBreak; 13622daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 13632daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return VisiblePosition(); 13642daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 13652daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 13662daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic int greatestValueUnder(int offset, bool boxAndBlockAreInSameDirection, const WordBoundaryVector& orderedWordBoundaries) 13672daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 13682daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (!orderedWordBoundaries.size()) 13692daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return invalidOffset; 13702daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // FIXME: binary search. 13712daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (boxAndBlockAreInSameDirection) { 13722daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch for (unsigned i = 0; i < orderedWordBoundaries.size(); ++i) { 13732daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (orderedWordBoundaries[i].offsetInInlineBox < offset) 13742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return i; 13752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 13762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return invalidOffset; 13772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 13782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch for (int i = orderedWordBoundaries.size() - 1; i >= 0; --i) { 13792daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (orderedWordBoundaries[i].offsetInInlineBox < offset) 13802daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return i; 13812daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 13822daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return invalidOffset; 13832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 13842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 13852daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic int smallestOffsetAbove(int offset, bool boxAndBlockAreInSameDirection, const WordBoundaryVector& orderedWordBoundaries) 13862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 13872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (!orderedWordBoundaries.size()) 13882daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return invalidOffset; 13892daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // FIXME: binary search. 13902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (boxAndBlockAreInSameDirection) { 13912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch for (int i = orderedWordBoundaries.size() - 1; i >= 0; --i) { 13922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (orderedWordBoundaries[i].offsetInInlineBox > offset) 13932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return i; 13942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 13952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return invalidOffset; 13962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 13972daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch for (unsigned i = 0; i < orderedWordBoundaries.size(); ++i) { 13982daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (orderedWordBoundaries[i].offsetInInlineBox > offset) 13992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return i; 14002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 14012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return invalidOffset; 14022daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 14032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 14042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic VisiblePosition leftWordBoundary(const InlineBox* box, int offset, TextDirection blockDirection) 14052daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 14062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition wordBreak; 14072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch for (const InlineBox* adjacentBox = box; adjacentBox; adjacentBox = adjacentBox->prevLeafChild()) { 14082daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (blockDirection == LTR) 14092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = previousWordBreakInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset, blockDirection); 14102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // FIXME: Implement the "else" case. 14112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (wordBreak.isNotNull()) 14122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return wordBreak; 14132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 14142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return VisiblePosition(); 14152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 14162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 14172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic VisiblePosition rightWordBoundary(const InlineBox* box, int offset, TextDirection blockDirection) 14182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 14192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 14202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition wordBreak; 14212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch for (const InlineBox* adjacentBox = box; adjacentBox; adjacentBox = adjacentBox->nextLeafChild()) { 14222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (blockDirection == RTL) 14232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = previousWordBreakInBox(adjacentBox, adjacentBox == box ? offset : invalidOffset, blockDirection); 14242daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // FIXME: Implement the "else" case. 14252daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (!wordBreak.isNull()) 14262daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return wordBreak; 14272daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 14282daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return VisiblePosition(); 14292daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 14302daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 14312daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic bool positionIsInsideBox(const VisiblePosition& wordBreak, const InlineBox* box) 14322daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 14332daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch InlineBox* boxOfWordBreak; 14342daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int offsetOfWordBreak; 14352daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak.getInlineBoxAndOffset(boxOfWordBreak, offsetOfWordBreak); 14362daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return box == boxOfWordBreak && offsetOfWordBreak != box->caretMaxOffset() && offsetOfWordBreak != box->caretMinOffset(); 14372daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 14382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 14392daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic VisiblePosition positionBeforeNextWord(const VisiblePosition& position) 14402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 14412daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition positionAfterCurrentWord = nextWordPosition(position); 14422daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition positionAfterNextWord = nextWordPosition(positionAfterCurrentWord); 14432daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (positionAfterCurrentWord == positionAfterNextWord) 14442daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return positionAfterCurrentWord; 14452daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return previousWordPosition(positionAfterNextWord); 14462daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 14472daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 14482daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdochstatic VisiblePosition positionAfterPreviousWord(const VisiblePosition& position) 14492daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 14502daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition positionBeforeCurrentWord = previousWordPosition(position); 14512daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition positionBeforePreviousWord = previousWordPosition(positionBeforeCurrentWord); 14522daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (positionBeforeCurrentWord == positionBeforePreviousWord) 14532daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return positionBeforeCurrentWord; 14542daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return nextWordPosition(positionBeforePreviousWord); 14552daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 14562daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 14572daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben MurdochVisiblePosition leftWordPosition(const VisiblePosition& visiblePosition) 14582daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 14592daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch InlineBox* box; 14602daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int offset; 14612daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch visiblePosition.getInlineBoxAndOffset(box, offset); 14622daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch TextDirection blockDirection = directionOfEnclosingBlock(visiblePosition.deepEquivalent()); 14632daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 14642daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // FIXME: If the box's directionality is the same as that of the enclosing block, when the offset is at the box boundary 14652daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // and the direction is towards inside the box, do I still need to make it a special case? For example, a LTR box inside a LTR block, 14662daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch // when offset is at box's caretMinOffset and the direction is DirectionRight, should it be taken care as a general case? 14672daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (offset == box->caretLeftmostOffset()) 14682daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return leftWordBoundary(box->prevLeafChild(), invalidOffset, blockDirection); 14692daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (offset == box->caretRightmostOffset()) 14702daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return leftWordBoundary(box, offset, blockDirection); 14712daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 14722daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 14732daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition wordBreak; 14742daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (box->direction() == blockDirection) { 14752daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (blockDirection == RTL) 14762daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = positionBeforeNextWord(visiblePosition); 14772daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch else 14782daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = previousWordPosition(visiblePosition); 14792daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } else { 14802daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (blockDirection == RTL) 14812daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = positionAfterPreviousWord(visiblePosition); 14822daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch else 14832daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = nextWordPosition(visiblePosition); 14842daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 14852daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (positionIsInsideBox(wordBreak, box)) 14862daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return wordBreak; 14872daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 14882daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch WordBoundaryVector orderedWordBoundaries; 14892daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (box->direction() == blockDirection) 14902daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch collectWordBreaksInBoxInsideBlockWithSameDirectionality(box, orderedWordBoundaries); 14912daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch else 14922daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(box, orderedWordBoundaries); 14932daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 14942daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int index = box->isLeftToRightDirection() ? greatestValueUnder(offset, blockDirection == LTR, orderedWordBoundaries) : 14952daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch smallestOffsetAbove(offset, blockDirection == RTL, orderedWordBoundaries); 14962daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (index != invalidOffset) 14972daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return orderedWordBoundaries[index].visiblePosition; 14982daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 14992daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return leftWordBoundary(box->prevLeafChild(), invalidOffset, blockDirection); 15002daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 15012daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 15022daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben MurdochVisiblePosition rightWordPosition(const VisiblePosition& visiblePosition) 15032daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch{ 15042daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch InlineBox* box; 15052daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int offset; 15062daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch visiblePosition.getInlineBoxAndOffset(box, offset); 15072daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch TextDirection blockDirection = directionOfEnclosingBlock(visiblePosition.deepEquivalent()); 15082daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 15092daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (offset == box->caretLeftmostOffset()) 15102daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return rightWordBoundary(box, offset, blockDirection); 15112daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (offset == box->caretRightmostOffset()) 15122daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return rightWordBoundary(box->nextLeafChild(), invalidOffset, blockDirection); 15132daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 15142daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch VisiblePosition wordBreak; 15152daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (box->direction() == blockDirection) { 15162daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (blockDirection == LTR) 15172daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = positionBeforeNextWord(visiblePosition); 15182daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch else 15192daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = previousWordPosition(visiblePosition); 15202daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } else { 15212daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (blockDirection == LTR) 15222daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = positionAfterPreviousWord(visiblePosition); 15232daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch else 15242daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch wordBreak = nextWordPosition(visiblePosition); 15252daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch } 15262daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (positionIsInsideBox(wordBreak, box)) 15272daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return wordBreak; 15282daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 15292daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch WordBoundaryVector orderedWordBoundaries; 15302daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (box->direction() == blockDirection) 15312daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch collectWordBreaksInBoxInsideBlockWithSameDirectionality(box, orderedWordBoundaries); 15322daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch else 15332daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch collectWordBreaksInBoxInsideBlockWithDifferntDirectionality(box, orderedWordBoundaries); 15342daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch int index = box->isLeftToRightDirection() ? smallestOffsetAbove(offset, blockDirection == LTR, orderedWordBoundaries) : 15352daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch greatestValueUnder(offset, blockDirection == RTL, orderedWordBoundaries); 15362daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch if (index != invalidOffset) 15372daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return orderedWordBoundaries[index].visiblePosition; 15382daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 15392daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch return rightWordBoundary(box->nextLeafChild(), invalidOffset, blockDirection); 15402daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch} 15412daae5fd11344eaa88a0d92b0f6d65f8d2255c00Ben Murdoch 15428e35f3cfc7fba1d1c829dc557ebad6409cbe16a2The Android Open Source Project} 1543