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->topOverflow()));
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->topOverflow()));
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
renderedAsNonInlineTableOrHR(RenderObject * renderer)779 static bool renderedAsNonInlineTableOrHR(RenderObject* renderer)
780 {
781 return renderer && ((renderer->isTable() && !renderer->isInline()) || renderer->isHR());
782 }
783
784 // FIXME: Broken for positions before/after images that aren't inline (5027702)
startOfParagraph(const VisiblePosition & c)785 VisiblePosition startOfParagraph(const VisiblePosition& c)
786 {
787 Position p = c.deepEquivalent();
788 Node *startNode = p.node();
789
790 if (!startNode)
791 return VisiblePosition();
792
793 if (renderedAsNonInlineTableOrHR(startNode->renderer()) && p.atLastEditingPositionForNode())
794 return firstDeepEditingPositionForNode(startNode);
795
796 Node* startBlock = enclosingBlock(startNode);
797
798 Node *node = startNode;
799 int offset = p.deprecatedEditingOffset();
800
801 Node *n = startNode;
802 while (n) {
803 if (n->isContentEditable() != startNode->isContentEditable())
804 break;
805 RenderObject *r = n->renderer();
806 if (!r) {
807 n = n->traversePreviousNodePostOrder(startBlock);
808 continue;
809 }
810 RenderStyle *style = r->style();
811 if (style->visibility() != VISIBLE) {
812 n = n->traversePreviousNodePostOrder(startBlock);
813 continue;
814 }
815
816 if (r->isBR() || isBlock(n))
817 break;
818
819 if (r->isText()) {
820 if (style->preserveNewline()) {
821 const UChar* chars = toRenderText(r)->characters();
822 int i = toRenderText(r)->textLength();
823 int o = offset;
824 if (n == startNode && o < i)
825 i = max(0, o);
826 while (--i >= 0)
827 if (chars[i] == '\n')
828 return VisiblePosition(n, i + 1, DOWNSTREAM);
829 }
830 node = n;
831 offset = 0;
832 n = n->traversePreviousNodePostOrder(startBlock);
833 } else if (editingIgnoresContent(n) || isTableElement(n)) {
834 node = n;
835 offset = 0;
836 n = n->previousSibling() ? n->previousSibling() : n->traversePreviousNodePostOrder(startBlock);
837 } else
838 n = n->traversePreviousNodePostOrder(startBlock);
839 }
840
841 return VisiblePosition(node, offset, DOWNSTREAM);
842 }
843
844 // FIXME: Broken for positions before/after images that aren't inline (5027702)
endOfParagraph(const VisiblePosition & c)845 VisiblePosition endOfParagraph(const VisiblePosition &c)
846 {
847 if (c.isNull())
848 return VisiblePosition();
849
850 Position p = c.deepEquivalent();
851 Node* startNode = p.node();
852
853 if (renderedAsNonInlineTableOrHR(startNode->renderer()) && p.atFirstEditingPositionForNode())
854 return lastDeepEditingPositionForNode(startNode);
855
856 Node* startBlock = enclosingBlock(startNode);
857 Node *stayInsideBlock = startBlock;
858
859 Node *node = startNode;
860 int offset = p.deprecatedEditingOffset();
861
862 Node *n = startNode;
863 while (n) {
864 if (n->isContentEditable() != startNode->isContentEditable())
865 break;
866 RenderObject *r = n->renderer();
867 if (!r) {
868 n = n->traverseNextNode(stayInsideBlock);
869 continue;
870 }
871 RenderStyle *style = r->style();
872 if (style->visibility() != VISIBLE) {
873 n = n->traverseNextNode(stayInsideBlock);
874 continue;
875 }
876
877 if (r->isBR() || isBlock(n))
878 break;
879
880 // FIXME: We avoid returning a position where the renderer can't accept the caret.
881 // We should probably do this in other cases such as startOfParagraph.
882 if (r->isText() && r->caretMaxRenderedOffset() > 0) {
883 int length = toRenderText(r)->textLength();
884 if (style->preserveNewline()) {
885 const UChar* chars = toRenderText(r)->characters();
886 int o = n == startNode ? offset : 0;
887 for (int i = o; i < length; ++i)
888 if (chars[i] == '\n')
889 return VisiblePosition(n, i, DOWNSTREAM);
890 }
891 node = n;
892 offset = r->caretMaxOffset();
893 n = n->traverseNextNode(stayInsideBlock);
894 } else if (editingIgnoresContent(n) || isTableElement(n)) {
895 node = n;
896 offset = lastOffsetForEditing(n);
897 n = n->traverseNextSibling(stayInsideBlock);
898 } else
899 n = n->traverseNextNode(stayInsideBlock);
900 }
901
902 return VisiblePosition(node, offset, DOWNSTREAM);
903 }
904
startOfNextParagraph(const VisiblePosition & visiblePosition)905 VisiblePosition startOfNextParagraph(const VisiblePosition& visiblePosition)
906 {
907 VisiblePosition paragraphEnd(endOfParagraph(visiblePosition));
908 VisiblePosition afterParagraphEnd(paragraphEnd.next(true));
909 // The position after the last position in the last cell of a table
910 // is not the start of the next paragraph.
911 if (isFirstPositionAfterTable(afterParagraphEnd))
912 return afterParagraphEnd.next(true);
913 return afterParagraphEnd;
914 }
915
inSameParagraph(const VisiblePosition & a,const VisiblePosition & b)916 bool inSameParagraph(const VisiblePosition &a, const VisiblePosition &b)
917 {
918 return a.isNotNull() && startOfParagraph(a) == startOfParagraph(b);
919 }
920
isStartOfParagraph(const VisiblePosition & pos)921 bool isStartOfParagraph(const VisiblePosition &pos)
922 {
923 return pos.isNotNull() && pos == startOfParagraph(pos);
924 }
925
isEndOfParagraph(const VisiblePosition & pos)926 bool isEndOfParagraph(const VisiblePosition &pos)
927 {
928 return pos.isNotNull() && pos == endOfParagraph(pos);
929 }
930
previousParagraphPosition(const VisiblePosition & p,int x)931 VisiblePosition previousParagraphPosition(const VisiblePosition& p, int x)
932 {
933 VisiblePosition pos = p;
934 do {
935 VisiblePosition n = previousLinePosition(pos, x);
936 if (n.isNull() || n == pos)
937 break;
938 pos = n;
939 } while (inSameParagraph(p, pos));
940 return pos;
941 }
942
nextParagraphPosition(const VisiblePosition & p,int x)943 VisiblePosition nextParagraphPosition(const VisiblePosition& p, int x)
944 {
945 VisiblePosition pos = p;
946 do {
947 VisiblePosition n = nextLinePosition(pos, x);
948 if (n.isNull() || n == pos)
949 break;
950 pos = n;
951 } while (inSameParagraph(p, pos));
952 return pos;
953 }
954
955 // ---------
956
startOfBlock(const VisiblePosition & c)957 VisiblePosition startOfBlock(const VisiblePosition &c)
958 {
959 Position p = c.deepEquivalent();
960 Node *startNode = p.node();
961 if (!startNode)
962 return VisiblePosition();
963 return VisiblePosition(Position(startNode->enclosingBlockFlowElement(), 0), DOWNSTREAM);
964 }
965
endOfBlock(const VisiblePosition & c)966 VisiblePosition endOfBlock(const VisiblePosition &c)
967 {
968 Position p = c.deepEquivalent();
969
970 Node *startNode = p.node();
971 if (!startNode)
972 return VisiblePosition();
973
974 Node *startBlock = startNode->enclosingBlockFlowElement();
975
976 return VisiblePosition(startBlock, startBlock->childNodeCount(), VP_DEFAULT_AFFINITY);
977 }
978
inSameBlock(const VisiblePosition & a,const VisiblePosition & b)979 bool inSameBlock(const VisiblePosition &a, const VisiblePosition &b)
980 {
981 return !a.isNull() && enclosingBlockFlowElement(a) == enclosingBlockFlowElement(b);
982 }
983
isStartOfBlock(const VisiblePosition & pos)984 bool isStartOfBlock(const VisiblePosition &pos)
985 {
986 return pos.isNotNull() && pos == startOfBlock(pos);
987 }
988
isEndOfBlock(const VisiblePosition & pos)989 bool isEndOfBlock(const VisiblePosition &pos)
990 {
991 return pos.isNotNull() && pos == endOfBlock(pos);
992 }
993
994 // ---------
995
startOfDocument(const Node * node)996 VisiblePosition startOfDocument(const Node* node)
997 {
998 if (!node)
999 return VisiblePosition();
1000
1001 return VisiblePosition(node->document()->documentElement(), 0, DOWNSTREAM);
1002 }
1003
startOfDocument(const VisiblePosition & c)1004 VisiblePosition startOfDocument(const VisiblePosition &c)
1005 {
1006 return startOfDocument(c.deepEquivalent().node());
1007 }
1008
endOfDocument(const Node * node)1009 VisiblePosition endOfDocument(const Node* node)
1010 {
1011 if (!node || !node->document())
1012 return VisiblePosition();
1013
1014 Element* doc = node->document()->documentElement();
1015 return VisiblePosition(doc, doc->childNodeCount(), DOWNSTREAM);
1016 }
1017
endOfDocument(const VisiblePosition & c)1018 VisiblePosition endOfDocument(const VisiblePosition &c)
1019 {
1020 return endOfDocument(c.deepEquivalent().node());
1021 }
1022
inSameDocument(const VisiblePosition & a,const VisiblePosition & b)1023 bool inSameDocument(const VisiblePosition &a, const VisiblePosition &b)
1024 {
1025 Position ap = a.deepEquivalent();
1026 Node *an = ap.node();
1027 if (!an)
1028 return false;
1029 Position bp = b.deepEquivalent();
1030 Node *bn = bp.node();
1031 if (an == bn)
1032 return true;
1033
1034 return an->document() == bn->document();
1035 }
1036
isStartOfDocument(const VisiblePosition & p)1037 bool isStartOfDocument(const VisiblePosition &p)
1038 {
1039 return p.isNotNull() && p.previous().isNull();
1040 }
1041
isEndOfDocument(const VisiblePosition & p)1042 bool isEndOfDocument(const VisiblePosition &p)
1043 {
1044 return p.isNotNull() && p.next().isNull();
1045 }
1046
1047 // ---------
1048
startOfEditableContent(const VisiblePosition & visiblePosition)1049 VisiblePosition startOfEditableContent(const VisiblePosition& visiblePosition)
1050 {
1051 Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
1052 if (!highestRoot)
1053 return VisiblePosition();
1054
1055 return firstDeepEditingPositionForNode(highestRoot);
1056 }
1057
endOfEditableContent(const VisiblePosition & visiblePosition)1058 VisiblePosition endOfEditableContent(const VisiblePosition& visiblePosition)
1059 {
1060 Node* highestRoot = highestEditableRoot(visiblePosition.deepEquivalent());
1061 if (!highestRoot)
1062 return VisiblePosition();
1063
1064 return lastDeepEditingPositionForNode(highestRoot);
1065 }
1066
getLeafBoxesInLogicalOrder(RootInlineBox * rootBox,Vector<InlineBox * > & leafBoxesInLogicalOrder)1067 static void getLeafBoxesInLogicalOrder(RootInlineBox* rootBox, Vector<InlineBox*>& leafBoxesInLogicalOrder)
1068 {
1069 unsigned char minLevel = 128;
1070 unsigned char maxLevel = 0;
1071 unsigned count = 0;
1072 InlineBox* r = rootBox->firstLeafChild();
1073 // First find highest and lowest levels,
1074 // and initialize leafBoxesInLogicalOrder with the leaf boxes in visual order.
1075 while (r) {
1076 if (r->bidiLevel() > maxLevel)
1077 maxLevel = r->bidiLevel();
1078 if (r->bidiLevel() < minLevel)
1079 minLevel = r->bidiLevel();
1080 leafBoxesInLogicalOrder.append(r);
1081 r = r->nextLeafChild();
1082 ++count;
1083 }
1084
1085 if (rootBox->renderer()->style()->visuallyOrdered())
1086 return;
1087 // Reverse of reordering of the line (L2 according to Bidi spec):
1088 // L2. From the highest level found in the text to the lowest odd level on each line,
1089 // reverse any contiguous sequence of characters that are at that level or higher.
1090
1091 // Reversing the reordering of the line is only done up to the lowest odd level.
1092 if (!(minLevel % 2))
1093 minLevel++;
1094
1095 InlineBox** end = leafBoxesInLogicalOrder.end();
1096 while (minLevel <= maxLevel) {
1097 InlineBox** iter = leafBoxesInLogicalOrder.begin();
1098 while (iter != end) {
1099 while (iter != end) {
1100 if ((*iter)->bidiLevel() >= minLevel)
1101 break;
1102 ++iter;
1103 }
1104 InlineBox** first = iter;
1105 while (iter != end) {
1106 if ((*iter)->bidiLevel() < minLevel)
1107 break;
1108 ++iter;
1109 }
1110 InlineBox** last = iter;
1111 std::reverse(first, last);
1112 }
1113 ++minLevel;
1114 }
1115 }
1116
getLogicalStartBoxAndNode(RootInlineBox * rootBox,InlineBox * & startBox,Node * & startNode)1117 static void getLogicalStartBoxAndNode(RootInlineBox* rootBox, InlineBox*& startBox, Node*& startNode)
1118 {
1119 Vector<InlineBox*> leafBoxesInLogicalOrder;
1120 getLeafBoxesInLogicalOrder(rootBox, leafBoxesInLogicalOrder);
1121 startBox = 0;
1122 startNode = 0;
1123 for (size_t i = 0; i < leafBoxesInLogicalOrder.size(); ++i) {
1124 startBox = leafBoxesInLogicalOrder[i];
1125 startNode = startBox->renderer()->node();
1126 if (startNode)
1127 return;
1128 }
1129 }
1130
getLogicalEndBoxAndNode(RootInlineBox * rootBox,InlineBox * & endBox,Node * & endNode)1131 static void getLogicalEndBoxAndNode(RootInlineBox* rootBox, InlineBox*& endBox, Node*& endNode)
1132 {
1133 Vector<InlineBox*> leafBoxesInLogicalOrder;
1134 getLeafBoxesInLogicalOrder(rootBox, leafBoxesInLogicalOrder);
1135 endBox = 0;
1136 endNode = 0;
1137 // Generated content (e.g. list markers and CSS :before and :after
1138 // pseudoelements) have no corresponding DOM element, and so cannot be
1139 // represented by a VisiblePosition. Use whatever precedes instead.
1140 for (size_t i = leafBoxesInLogicalOrder.size(); i > 0; --i) {
1141 endBox = leafBoxesInLogicalOrder[i - 1];
1142 endNode = endBox->renderer()->node();
1143 if (endNode)
1144 return;
1145 }
1146 }
1147
logicalStartPositionForLine(const VisiblePosition & c)1148 static VisiblePosition logicalStartPositionForLine(const VisiblePosition& c)
1149 {
1150 if (c.isNull())
1151 return VisiblePosition();
1152
1153 RootInlineBox* rootBox = rootBoxForLine(c);
1154 if (!rootBox) {
1155 // There are VisiblePositions at offset 0 in blocks without
1156 // RootInlineBoxes, like empty editable blocks and bordered blocks.
1157 Position p = c.deepEquivalent();
1158 if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset())
1159 return positionAvoidingFirstPositionInTable(c);
1160
1161 return VisiblePosition();
1162 }
1163
1164 InlineBox* logicalStartBox;
1165 Node* logicalStartNode;
1166 getLogicalStartBoxAndNode(rootBox, logicalStartBox, logicalStartNode);
1167
1168 if (!logicalStartNode)
1169 return VisiblePosition();
1170
1171 int startOffset = logicalStartBox->caretMinOffset();
1172
1173 VisiblePosition visPos = VisiblePosition(logicalStartNode, startOffset, DOWNSTREAM);
1174 return positionAvoidingFirstPositionInTable(visPos);
1175 }
1176
logicalStartOfLine(const VisiblePosition & c)1177 VisiblePosition logicalStartOfLine(const VisiblePosition& c)
1178 {
1179 VisiblePosition visPos = logicalStartPositionForLine(c);
1180
1181 return c.honorEditableBoundaryAtOrAfter(visPos);
1182 }
1183
logicalEndPositionForLine(const VisiblePosition & c)1184 static VisiblePosition logicalEndPositionForLine(const VisiblePosition& c)
1185 {
1186 if (c.isNull())
1187 return VisiblePosition();
1188
1189 RootInlineBox* rootBox = rootBoxForLine(c);
1190 if (!rootBox) {
1191 // There are VisiblePositions at offset 0 in blocks without
1192 // RootInlineBoxes, like empty editable blocks and bordered blocks.
1193 Position p = c.deepEquivalent();
1194 if (p.node()->renderer() && p.node()->renderer()->isRenderBlock() && !p.deprecatedEditingOffset())
1195 return c;
1196 return VisiblePosition();
1197 }
1198
1199 InlineBox* logicalEndBox;
1200 Node* logicalEndNode;
1201 getLogicalEndBoxAndNode(rootBox, logicalEndBox, logicalEndNode);
1202 if (!logicalEndNode)
1203 return VisiblePosition();
1204
1205 int endOffset = 1;
1206 if (logicalEndNode->hasTagName(brTag))
1207 endOffset = 0;
1208 else if (logicalEndBox->isInlineTextBox()) {
1209 InlineTextBox* endTextBox = static_cast<InlineTextBox*>(logicalEndBox);
1210 endOffset = endTextBox->start();
1211 if (!endTextBox->isLineBreak())
1212 endOffset += endTextBox->len();
1213 }
1214
1215 return VisiblePosition(logicalEndNode, endOffset, VP_UPSTREAM_IF_POSSIBLE);
1216 }
1217
inSameLogicalLine(const VisiblePosition & a,const VisiblePosition & b)1218 bool inSameLogicalLine(const VisiblePosition& a, const VisiblePosition& b)
1219 {
1220 return a.isNotNull() && logicalStartOfLine(a) == logicalStartOfLine(b);
1221 }
1222
logicalEndOfLine(const VisiblePosition & c)1223 VisiblePosition logicalEndOfLine(const VisiblePosition& c)
1224 {
1225 VisiblePosition visPos = logicalEndPositionForLine(c);
1226
1227 // Make sure the end of line is at the same line as the given input position. For a wrapping line, the logical end
1228 // position for the not-last-2-lines might incorrectly hand back the logical beginning of the next line.
1229 // For example, <div contenteditable dir="rtl" style="line-break:before-white-space">abcdefg abcdefg abcdefg
1230 // a abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg abcdefg </div>
1231 // In this case, use the previous position of the computed logical end position.
1232 if (!inSameLogicalLine(c, visPos))
1233 visPos = visPos.previous();
1234
1235 return c.honorEditableBoundaryAtOrBefore(visPos);
1236 }
1237
1238 }
1239