1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
3 * Portions Copyright (c) 2011 Motorola Mobility, Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 #include "config.h"
28 #include "core/editing/VisiblePosition.h"
29
30 #include "HTMLNames.h"
31 #include "bindings/v8/ExceptionState.h"
32 #include "core/dom/Document.h"
33 #include "core/dom/Range.h"
34 #include "core/dom/Text.h"
35 #include "core/editing/VisibleUnits.h"
36 #include "core/editing/htmlediting.h"
37 #include "core/html/HTMLElement.h"
38 #include "core/html/HTMLHtmlElement.h"
39 #include "core/rendering/RenderBlock.h"
40 #include "core/rendering/RootInlineBox.h"
41 #include "platform/geometry/FloatQuad.h"
42 #include "wtf/text/CString.h"
43
44 #ifndef NDEBUG
45 #include <stdio.h>
46 #endif
47
48 namespace WebCore {
49
50 using namespace HTMLNames;
51
VisiblePosition(const Position & pos,EAffinity affinity)52 VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity)
53 {
54 init(pos, affinity);
55 }
56
VisiblePosition(const PositionWithAffinity & positionWithAffinity)57 VisiblePosition::VisiblePosition(const PositionWithAffinity& positionWithAffinity)
58 {
59 init(positionWithAffinity.position(), positionWithAffinity.affinity());
60 }
61
init(const Position & position,EAffinity affinity)62 void VisiblePosition::init(const Position& position, EAffinity affinity)
63 {
64 m_affinity = affinity;
65
66 m_deepPosition = canonicalPosition(position);
67
68 // When not at a line wrap, make sure to end up with DOWNSTREAM affinity.
69 if (m_affinity == UPSTREAM && (isNull() || inSameLine(VisiblePosition(position, DOWNSTREAM), *this)))
70 m_affinity = DOWNSTREAM;
71 }
72
next(EditingBoundaryCrossingRule rule) const73 VisiblePosition VisiblePosition::next(EditingBoundaryCrossingRule rule) const
74 {
75 VisiblePosition next(nextVisuallyDistinctCandidate(m_deepPosition), m_affinity);
76
77 switch (rule) {
78 case CanCrossEditingBoundary:
79 return next;
80 case CannotCrossEditingBoundary:
81 return honorEditingBoundaryAtOrAfter(next);
82 case CanSkipOverEditingBoundary:
83 return skipToEndOfEditingBoundary(next);
84 }
85 ASSERT_NOT_REACHED();
86 return honorEditingBoundaryAtOrAfter(next);
87 }
88
previous(EditingBoundaryCrossingRule rule) const89 VisiblePosition VisiblePosition::previous(EditingBoundaryCrossingRule rule) const
90 {
91 Position pos = previousVisuallyDistinctCandidate(m_deepPosition);
92
93 // return null visible position if there is no previous visible position
94 if (pos.atStartOfTree())
95 return VisiblePosition();
96
97 VisiblePosition prev = VisiblePosition(pos, DOWNSTREAM);
98 ASSERT(prev != *this);
99
100 #ifndef NDEBUG
101 // we should always be able to make the affinity DOWNSTREAM, because going previous from an
102 // UPSTREAM position can never yield another UPSTREAM position (unless line wrap length is 0!).
103 if (prev.isNotNull() && m_affinity == UPSTREAM) {
104 VisiblePosition temp = prev;
105 temp.setAffinity(UPSTREAM);
106 ASSERT(inSameLine(temp, prev));
107 }
108 #endif
109
110 switch (rule) {
111 case CanCrossEditingBoundary:
112 return prev;
113 case CannotCrossEditingBoundary:
114 return honorEditingBoundaryAtOrBefore(prev);
115 case CanSkipOverEditingBoundary:
116 return skipToStartOfEditingBoundary(prev);
117 }
118
119 ASSERT_NOT_REACHED();
120 return honorEditingBoundaryAtOrBefore(prev);
121 }
122
leftVisuallyDistinctCandidate() const123 Position VisiblePosition::leftVisuallyDistinctCandidate() const
124 {
125 Position p = m_deepPosition;
126 if (p.isNull())
127 return Position();
128
129 Position downstreamStart = p.downstream();
130 TextDirection primaryDirection = p.primaryDirection();
131
132 while (true) {
133 InlineBox* box;
134 int offset;
135 p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
136 if (!box)
137 return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
138
139 RenderObject* renderer = box->renderer();
140
141 while (true) {
142 if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretRightmostOffset())
143 return box->isLeftToRightDirection() ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
144
145 if (!renderer->node()) {
146 box = box->prevLeafChild();
147 if (!box)
148 return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
149 renderer = box->renderer();
150 offset = box->caretRightmostOffset();
151 continue;
152 }
153
154 offset = box->isLeftToRightDirection() ? renderer->previousOffset(offset) : renderer->nextOffset(offset);
155
156 int caretMinOffset = box->caretMinOffset();
157 int caretMaxOffset = box->caretMaxOffset();
158
159 if (offset > caretMinOffset && offset < caretMaxOffset)
160 break;
161
162 if (box->isLeftToRightDirection() ? offset < caretMinOffset : offset > caretMaxOffset) {
163 // Overshot to the left.
164 InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak();
165 if (!prevBox) {
166 Position positionOnLeft = primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
167 if (positionOnLeft.isNull())
168 return Position();
169
170 InlineBox* boxOnLeft;
171 int offsetOnLeft;
172 positionOnLeft.getInlineBoxAndOffset(m_affinity, primaryDirection, boxOnLeft, offsetOnLeft);
173 if (boxOnLeft && boxOnLeft->root() == box->root())
174 return Position();
175 return positionOnLeft;
176 }
177
178 // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
179 box = prevBox;
180 renderer = box->renderer();
181 offset = prevBox->caretRightmostOffset();
182 continue;
183 }
184
185 ASSERT(offset == box->caretLeftmostOffset());
186
187 unsigned char level = box->bidiLevel();
188 InlineBox* prevBox = box->prevLeafChild();
189
190 if (box->direction() == primaryDirection) {
191 if (!prevBox) {
192 InlineBox* logicalStart = 0;
193 if (primaryDirection == LTR ? box->root()->getLogicalStartBoxWithNode(logicalStart) : box->root()->getLogicalEndBoxWithNode(logicalStart)) {
194 box = logicalStart;
195 renderer = box->renderer();
196 offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset();
197 }
198 break;
199 }
200 if (prevBox->bidiLevel() >= level)
201 break;
202
203 level = prevBox->bidiLevel();
204
205 InlineBox* nextBox = box;
206 do {
207 nextBox = nextBox->nextLeafChild();
208 } while (nextBox && nextBox->bidiLevel() > level);
209
210 if (nextBox && nextBox->bidiLevel() == level)
211 break;
212
213 box = prevBox;
214 renderer = box->renderer();
215 offset = box->caretRightmostOffset();
216 if (box->direction() == primaryDirection)
217 break;
218 continue;
219 }
220
221 while (prevBox && !prevBox->renderer()->node())
222 prevBox = prevBox->prevLeafChild();
223
224 if (prevBox) {
225 box = prevBox;
226 renderer = box->renderer();
227 offset = box->caretRightmostOffset();
228 if (box->bidiLevel() > level) {
229 do {
230 prevBox = prevBox->prevLeafChild();
231 } while (prevBox && prevBox->bidiLevel() > level);
232
233 if (!prevBox || prevBox->bidiLevel() < level)
234 continue;
235 }
236 } else {
237 // Trailing edge of a secondary run. Set to the leading edge of the entire run.
238 while (true) {
239 while (InlineBox* nextBox = box->nextLeafChild()) {
240 if (nextBox->bidiLevel() < level)
241 break;
242 box = nextBox;
243 }
244 if (box->bidiLevel() == level)
245 break;
246 level = box->bidiLevel();
247 while (InlineBox* prevBox = box->prevLeafChild()) {
248 if (prevBox->bidiLevel() < level)
249 break;
250 box = prevBox;
251 }
252 if (box->bidiLevel() == level)
253 break;
254 level = box->bidiLevel();
255 }
256 renderer = box->renderer();
257 offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset();
258 }
259 break;
260 }
261
262 p = createLegacyEditingPosition(renderer->node(), offset);
263
264 if ((p.isCandidate() && p.downstream() != downstreamStart) || p.atStartOfTree() || p.atEndOfTree())
265 return p;
266
267 ASSERT(p != m_deepPosition);
268 }
269 }
270
left(bool stayInEditableContent) const271 VisiblePosition VisiblePosition::left(bool stayInEditableContent) const
272 {
273 Position pos = leftVisuallyDistinctCandidate();
274 // FIXME: Why can't we move left from the last position in a tree?
275 if (pos.atStartOfTree() || pos.atEndOfTree())
276 return VisiblePosition();
277
278 VisiblePosition left = VisiblePosition(pos, DOWNSTREAM);
279 ASSERT(left != *this);
280
281 if (!stayInEditableContent)
282 return left;
283
284 // FIXME: This may need to do something different from "before".
285 return honorEditingBoundaryAtOrBefore(left);
286 }
287
rightVisuallyDistinctCandidate() const288 Position VisiblePosition::rightVisuallyDistinctCandidate() const
289 {
290 Position p = m_deepPosition;
291 if (p.isNull())
292 return Position();
293
294 Position downstreamStart = p.downstream();
295 TextDirection primaryDirection = p.primaryDirection();
296
297 while (true) {
298 InlineBox* box;
299 int offset;
300 p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
301 if (!box)
302 return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
303
304 RenderObject* renderer = box->renderer();
305
306 while (true) {
307 if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretLeftmostOffset())
308 return box->isLeftToRightDirection() ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
309
310 if (!renderer->node()) {
311 box = box->nextLeafChild();
312 if (!box)
313 return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
314 renderer = box->renderer();
315 offset = box->caretLeftmostOffset();
316 continue;
317 }
318
319 offset = box->isLeftToRightDirection() ? renderer->nextOffset(offset) : renderer->previousOffset(offset);
320
321 int caretMinOffset = box->caretMinOffset();
322 int caretMaxOffset = box->caretMaxOffset();
323
324 if (offset > caretMinOffset && offset < caretMaxOffset)
325 break;
326
327 if (box->isLeftToRightDirection() ? offset > caretMaxOffset : offset < caretMinOffset) {
328 // Overshot to the right.
329 InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak();
330 if (!nextBox) {
331 Position positionOnRight = primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
332 if (positionOnRight.isNull())
333 return Position();
334
335 InlineBox* boxOnRight;
336 int offsetOnRight;
337 positionOnRight.getInlineBoxAndOffset(m_affinity, primaryDirection, boxOnRight, offsetOnRight);
338 if (boxOnRight && boxOnRight->root() == box->root())
339 return Position();
340 return positionOnRight;
341 }
342
343 // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
344 box = nextBox;
345 renderer = box->renderer();
346 offset = nextBox->caretLeftmostOffset();
347 continue;
348 }
349
350 ASSERT(offset == box->caretRightmostOffset());
351
352 unsigned char level = box->bidiLevel();
353 InlineBox* nextBox = box->nextLeafChild();
354
355 if (box->direction() == primaryDirection) {
356 if (!nextBox) {
357 InlineBox* logicalEnd = 0;
358 if (primaryDirection == LTR ? box->root()->getLogicalEndBoxWithNode(logicalEnd) : box->root()->getLogicalStartBoxWithNode(logicalEnd)) {
359 box = logicalEnd;
360 renderer = box->renderer();
361 offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset();
362 }
363 break;
364 }
365
366 if (nextBox->bidiLevel() >= level)
367 break;
368
369 level = nextBox->bidiLevel();
370
371 InlineBox* prevBox = box;
372 do {
373 prevBox = prevBox->prevLeafChild();
374 } while (prevBox && prevBox->bidiLevel() > level);
375
376 if (prevBox && prevBox->bidiLevel() == level) // For example, abc FED 123 ^ CBA
377 break;
378
379 // For example, abc 123 ^ CBA or 123 ^ CBA abc
380 box = nextBox;
381 renderer = box->renderer();
382 offset = box->caretLeftmostOffset();
383 if (box->direction() == primaryDirection)
384 break;
385 continue;
386 }
387
388 while (nextBox && !nextBox->renderer()->node())
389 nextBox = nextBox->nextLeafChild();
390
391 if (nextBox) {
392 box = nextBox;
393 renderer = box->renderer();
394 offset = box->caretLeftmostOffset();
395
396 if (box->bidiLevel() > level) {
397 do {
398 nextBox = nextBox->nextLeafChild();
399 } while (nextBox && nextBox->bidiLevel() > level);
400
401 if (!nextBox || nextBox->bidiLevel() < level)
402 continue;
403 }
404 } else {
405 // Trailing edge of a secondary run. Set to the leading edge of the entire run.
406 while (true) {
407 while (InlineBox* prevBox = box->prevLeafChild()) {
408 if (prevBox->bidiLevel() < level)
409 break;
410 box = prevBox;
411 }
412 if (box->bidiLevel() == level)
413 break;
414 level = box->bidiLevel();
415 while (InlineBox* nextBox = box->nextLeafChild()) {
416 if (nextBox->bidiLevel() < level)
417 break;
418 box = nextBox;
419 }
420 if (box->bidiLevel() == level)
421 break;
422 level = box->bidiLevel();
423 }
424 renderer = box->renderer();
425 offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset();
426 }
427 break;
428 }
429
430 p = createLegacyEditingPosition(renderer->node(), offset);
431
432 if ((p.isCandidate() && p.downstream() != downstreamStart) || p.atStartOfTree() || p.atEndOfTree())
433 return p;
434
435 ASSERT(p != m_deepPosition);
436 }
437 }
438
right(bool stayInEditableContent) const439 VisiblePosition VisiblePosition::right(bool stayInEditableContent) const
440 {
441 Position pos = rightVisuallyDistinctCandidate();
442 // FIXME: Why can't we move left from the last position in a tree?
443 if (pos.atStartOfTree() || pos.atEndOfTree())
444 return VisiblePosition();
445
446 VisiblePosition right = VisiblePosition(pos, DOWNSTREAM);
447 ASSERT(right != *this);
448
449 if (!stayInEditableContent)
450 return right;
451
452 // FIXME: This may need to do something different from "after".
453 return honorEditingBoundaryAtOrAfter(right);
454 }
455
honorEditingBoundaryAtOrBefore(const VisiblePosition & pos) const456 VisiblePosition VisiblePosition::honorEditingBoundaryAtOrBefore(const VisiblePosition &pos) const
457 {
458 if (pos.isNull())
459 return pos;
460
461 Node* highestRoot = highestEditableRoot(deepEquivalent());
462
463 // Return empty position if pos is not somewhere inside the editable region containing this position
464 if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot))
465 return VisiblePosition();
466
467 // Return pos itself if the two are from the very same editable region, or both are non-editable
468 // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
469 // to it is allowed. VisibleSelection::adjustForEditableContent has this problem too.
470 if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
471 return pos;
472
473 // Return empty position if this position is non-editable, but pos is editable
474 // FIXME: Move to the previous non-editable region.
475 if (!highestRoot)
476 return VisiblePosition();
477
478 // Return the last position before pos that is in the same editable region as this position
479 return lastEditablePositionBeforePositionInRoot(pos.deepEquivalent(), highestRoot);
480 }
481
honorEditingBoundaryAtOrAfter(const VisiblePosition & pos) const482 VisiblePosition VisiblePosition::honorEditingBoundaryAtOrAfter(const VisiblePosition &pos) const
483 {
484 if (pos.isNull())
485 return pos;
486
487 Node* highestRoot = highestEditableRoot(deepEquivalent());
488
489 // Return empty position if pos is not somewhere inside the editable region containing this position
490 if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot))
491 return VisiblePosition();
492
493 // Return pos itself if the two are from the very same editable region, or both are non-editable
494 // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
495 // to it is allowed. VisibleSelection::adjustForEditableContent has this problem too.
496 if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
497 return pos;
498
499 // Return empty position if this position is non-editable, but pos is editable
500 // FIXME: Move to the next non-editable region.
501 if (!highestRoot)
502 return VisiblePosition();
503
504 // Return the next position after pos that is in the same editable region as this position
505 return firstEditablePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot);
506 }
507
skipToStartOfEditingBoundary(const VisiblePosition & pos) const508 VisiblePosition VisiblePosition::skipToStartOfEditingBoundary(const VisiblePosition &pos) const
509 {
510 if (pos.isNull())
511 return pos;
512
513 Node* highestRoot = highestEditableRoot(deepEquivalent());
514 Node* highestRootOfPos = highestEditableRoot(pos.deepEquivalent());
515
516 // Return pos itself if the two are from the very same editable region, or both are non-editable.
517 if (highestRootOfPos == highestRoot)
518 return pos;
519
520 // If |pos| has an editable root, skip to the start
521 if (highestRootOfPos)
522 return previousVisuallyDistinctCandidate(Position(highestRootOfPos, Position::PositionIsBeforeAnchor).parentAnchoredEquivalent());
523
524 // That must mean that |pos| is not editable. Return the last position before pos that is in the same editable region as this position
525 return lastEditablePositionBeforePositionInRoot(pos.deepEquivalent(), highestRoot);
526 }
527
skipToEndOfEditingBoundary(const VisiblePosition & pos) const528 VisiblePosition VisiblePosition::skipToEndOfEditingBoundary(const VisiblePosition &pos) const
529 {
530 if (pos.isNull())
531 return pos;
532
533 Node* highestRoot = highestEditableRoot(deepEquivalent());
534 Node* highestRootOfPos = highestEditableRoot(pos.deepEquivalent());
535
536 // Return pos itself if the two are from the very same editable region, or both are non-editable.
537 if (highestRootOfPos == highestRoot)
538 return pos;
539
540 // If |pos| has an editable root, skip to the end
541 if (highestRootOfPos)
542 return Position(highestRootOfPos, Position::PositionIsAfterAnchor).parentAnchoredEquivalent();
543
544 // That must mean that |pos| is not editable. Return the next position after pos that is in the same editable region as this position
545 return firstEditablePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot);
546 }
547
canonicalizeCandidate(const Position & candidate)548 static Position canonicalizeCandidate(const Position& candidate)
549 {
550 if (candidate.isNull())
551 return Position();
552 ASSERT(candidate.isCandidate());
553 Position upstream = candidate.upstream();
554 if (upstream.isCandidate())
555 return upstream;
556 return candidate;
557 }
558
canonicalPosition(const Position & passedPosition)559 Position VisiblePosition::canonicalPosition(const Position& passedPosition)
560 {
561 // The updateLayout call below can do so much that even the position passed
562 // in to us might get changed as a side effect. Specifically, there are code
563 // paths that pass selection endpoints, and updateLayout can change the selection.
564 Position position = passedPosition;
565
566 // FIXME (9535): Canonicalizing to the leftmost candidate means that if we're at a line wrap, we will
567 // ask renderers to paint downstream carets for other renderers.
568 // To fix this, we need to either a) add code to all paintCarets to pass the responsibility off to
569 // the appropriate renderer for VisiblePosition's like these, or b) canonicalize to the rightmost candidate
570 // unless the affinity is upstream.
571 if (position.isNull())
572 return Position();
573
574 ASSERT(position.document());
575 position.document()->updateLayoutIgnorePendingStylesheets();
576
577 Node* node = position.containerNode();
578
579 Position candidate = position.upstream();
580 if (candidate.isCandidate())
581 return candidate;
582 candidate = position.downstream();
583 if (candidate.isCandidate())
584 return candidate;
585
586 // When neither upstream or downstream gets us to a candidate (upstream/downstream won't leave
587 // blocks or enter new ones), we search forward and backward until we find one.
588 Position next = canonicalizeCandidate(nextCandidate(position));
589 Position prev = canonicalizeCandidate(previousCandidate(position));
590 Node* nextNode = next.deprecatedNode();
591 Node* prevNode = prev.deprecatedNode();
592
593 // The new position must be in the same editable element. Enforce that first.
594 // Unless the descent is from a non-editable html element to an editable body.
595 if (node && isHTMLHtmlElement(node) && !node->rendererIsEditable() && node->document().body() && node->document().body()->rendererIsEditable())
596 return next.isNotNull() ? next : prev;
597
598 Node* editingRoot = editableRootForPosition(position);
599
600 // If the html element is editable, descending into its body will look like a descent
601 // from non-editable to editable content since rootEditableElement() always stops at the body.
602 if ((editingRoot && isHTMLHtmlElement(editingRoot)) || position.deprecatedNode()->isDocumentNode())
603 return next.isNotNull() ? next : prev;
604
605 bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev) == editingRoot;
606 bool nextIsInSameEditableElement = nextNode && editableRootForPosition(next) == editingRoot;
607 if (prevIsInSameEditableElement && !nextIsInSameEditableElement)
608 return prev;
609
610 if (nextIsInSameEditableElement && !prevIsInSameEditableElement)
611 return next;
612
613 if (!nextIsInSameEditableElement && !prevIsInSameEditableElement)
614 return Position();
615
616 // The new position should be in the same block flow element. Favor that.
617 Node* originalBlock = node ? node->enclosingBlockFlowElement() : 0;
618 bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) && nextNode != originalBlock;
619 bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) && prevNode != originalBlock;
620 if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock)
621 return prev;
622
623 return next;
624 }
625
characterAfter() const626 UChar32 VisiblePosition::characterAfter() const
627 {
628 // We canonicalize to the first of two equivalent candidates, but the second of the two candidates
629 // is the one that will be inside the text node containing the character after this visible position.
630 Position pos = m_deepPosition.downstream();
631 if (!pos.containerNode() || !pos.containerNode()->isTextNode())
632 return 0;
633 switch (pos.anchorType()) {
634 case Position::PositionIsAfterChildren:
635 case Position::PositionIsAfterAnchor:
636 case Position::PositionIsBeforeAnchor:
637 case Position::PositionIsBeforeChildren:
638 return 0;
639 case Position::PositionIsOffsetInAnchor:
640 break;
641 }
642 unsigned offset = static_cast<unsigned>(pos.offsetInContainerNode());
643 Text* textNode = pos.containerText();
644 unsigned length = textNode->length();
645 if (offset >= length)
646 return 0;
647
648 return textNode->data().characterStartingAt(offset);
649 }
650
localCaretRect(RenderObject * & renderer) const651 LayoutRect VisiblePosition::localCaretRect(RenderObject*& renderer) const
652 {
653 if (m_deepPosition.isNull()) {
654 renderer = 0;
655 return IntRect();
656 }
657 Node* node = m_deepPosition.anchorNode();
658
659 renderer = node->renderer();
660 if (!renderer)
661 return LayoutRect();
662
663 InlineBox* inlineBox;
664 int caretOffset;
665 getInlineBoxAndOffset(inlineBox, caretOffset);
666
667 if (inlineBox)
668 renderer = inlineBox->renderer();
669
670 return renderer->localCaretRect(inlineBox, caretOffset);
671 }
672
absoluteCaretBounds() const673 IntRect VisiblePosition::absoluteCaretBounds() const
674 {
675 RenderObject* renderer;
676 LayoutRect localRect = localCaretRect(renderer);
677 if (localRect.isEmpty() || !renderer)
678 return IntRect();
679
680 return renderer->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
681 }
682
lineDirectionPointForBlockDirectionNavigation() const683 int VisiblePosition::lineDirectionPointForBlockDirectionNavigation() const
684 {
685 RenderObject* renderer;
686 LayoutRect localRect = localCaretRect(renderer);
687 if (localRect.isEmpty() || !renderer)
688 return 0;
689
690 // This ignores transforms on purpose, for now. Vertical navigation is done
691 // without consulting transforms, so that 'up' in transformed text is 'up'
692 // relative to the text, not absolute 'up'.
693 FloatPoint caretPoint = renderer->localToAbsolute(localRect.location());
694 RenderObject* containingBlock = renderer->containingBlock();
695 if (!containingBlock)
696 containingBlock = renderer; // Just use ourselves to determine the writing mode if we have no containing block.
697 return containingBlock->isHorizontalWritingMode() ? caretPoint.x() : caretPoint.y();
698 }
699
700 #ifndef NDEBUG
701
debugPosition(const char * msg) const702 void VisiblePosition::debugPosition(const char* msg) const
703 {
704 if (isNull())
705 fprintf(stderr, "Position [%s]: null\n", msg);
706 else {
707 fprintf(stderr, "Position [%s]: %s, ", msg, m_deepPosition.deprecatedNode()->nodeName().utf8().data());
708 m_deepPosition.showAnchorTypeAndOffset();
709 }
710 }
711
formatForDebugger(char * buffer,unsigned length) const712 void VisiblePosition::formatForDebugger(char* buffer, unsigned length) const
713 {
714 m_deepPosition.formatForDebugger(buffer, length);
715 }
716
showTreeForThis() const717 void VisiblePosition::showTreeForThis() const
718 {
719 m_deepPosition.showTreeForThis();
720 }
721
722 #endif
723
makeRange(const VisiblePosition & start,const VisiblePosition & end)724 PassRefPtr<Range> makeRange(const VisiblePosition &start, const VisiblePosition &end)
725 {
726 if (start.isNull() || end.isNull())
727 return 0;
728
729 Position s = start.deepEquivalent().parentAnchoredEquivalent();
730 Position e = end.deepEquivalent().parentAnchoredEquivalent();
731 if (s.isNull() || e.isNull())
732 return 0;
733
734 return Range::create(s.containerNode()->document(), s.containerNode(), s.offsetInContainerNode(), e.containerNode(), e.offsetInContainerNode());
735 }
736
startVisiblePosition(const Range * r,EAffinity affinity)737 VisiblePosition startVisiblePosition(const Range *r, EAffinity affinity)
738 {
739 return VisiblePosition(r->startPosition(), affinity);
740 }
741
endVisiblePosition(const Range * r,EAffinity affinity)742 VisiblePosition endVisiblePosition(const Range *r, EAffinity affinity)
743 {
744 return VisiblePosition(r->endPosition(), affinity);
745 }
746
setStart(Range * r,const VisiblePosition & visiblePosition)747 bool setStart(Range *r, const VisiblePosition &visiblePosition)
748 {
749 if (!r)
750 return false;
751 Position p = visiblePosition.deepEquivalent().parentAnchoredEquivalent();
752 TrackExceptionState exceptionState;
753 r->setStart(p.containerNode(), p.offsetInContainerNode(), exceptionState);
754 return !exceptionState.hadException();
755 }
756
setEnd(Range * r,const VisiblePosition & visiblePosition)757 bool setEnd(Range *r, const VisiblePosition &visiblePosition)
758 {
759 if (!r)
760 return false;
761 Position p = visiblePosition.deepEquivalent().parentAnchoredEquivalent();
762 TrackExceptionState exceptionState;
763 r->setEnd(p.containerNode(), p.offsetInContainerNode(), exceptionState);
764 return !exceptionState.hadException();
765 }
766
enclosingBlockFlowElement(const VisiblePosition & visiblePosition)767 Element* enclosingBlockFlowElement(const VisiblePosition &visiblePosition)
768 {
769 if (visiblePosition.isNull())
770 return NULL;
771
772 return visiblePosition.deepEquivalent().deprecatedNode()->enclosingBlockFlowElement();
773 }
774
isFirstVisiblePositionInNode(const VisiblePosition & visiblePosition,const Node * node)775 bool isFirstVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node)
776 {
777 if (visiblePosition.isNull())
778 return false;
779
780 if (!visiblePosition.deepEquivalent().containerNode()->isDescendantOf(node))
781 return false;
782
783 VisiblePosition previous = visiblePosition.previous();
784 return previous.isNull() || !previous.deepEquivalent().deprecatedNode()->isDescendantOf(node);
785 }
786
isLastVisiblePositionInNode(const VisiblePosition & visiblePosition,const Node * node)787 bool isLastVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node)
788 {
789 if (visiblePosition.isNull())
790 return false;
791
792 if (!visiblePosition.deepEquivalent().containerNode()->isDescendantOf(node))
793 return false;
794
795 VisiblePosition next = visiblePosition.next();
796 return next.isNull() || !next.deepEquivalent().deprecatedNode()->isDescendantOf(node);
797 }
798
799 } // namespace WebCore
800
801 #ifndef NDEBUG
802
showTree(const WebCore::VisiblePosition * vpos)803 void showTree(const WebCore::VisiblePosition* vpos)
804 {
805 if (vpos)
806 vpos->showTreeForThis();
807 }
808
showTree(const WebCore::VisiblePosition & vpos)809 void showTree(const WebCore::VisiblePosition& vpos)
810 {
811 vpos.showTreeForThis();
812 }
813
814 #endif
815