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