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