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