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