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