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.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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.
28 #include "VisiblePosition.h"
31 #include "FloatQuad.h"
32 #include "HTMLElement.h"
33 #include "HTMLNames.h"
34 #include "InlineTextBox.h"
37 #include "RenderBlock.h"
38 #include "RootInlineBox.h"
40 #include "htmlediting.h"
41 #include "visible_units.h"
43 #include <wtf/text/CString.h>
47 using namespace HTMLNames;
49 VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity)
54 void VisiblePosition::init(const Position& position, EAffinity affinity)
56 m_affinity = affinity;
58 m_deepPosition = canonicalPosition(position);
60 // When not at a line wrap, make sure to end up with DOWNSTREAM affinity.
61 if (m_affinity == UPSTREAM && (isNull() || inSameLine(VisiblePosition(position, DOWNSTREAM), *this)))
62 m_affinity = DOWNSTREAM;
65 VisiblePosition VisiblePosition::next(EditingBoundaryCrossingRule rule) const
67 // FIXME: Support CanSkipEditingBoundary
68 ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
69 VisiblePosition next(nextVisuallyDistinctCandidate(m_deepPosition), m_affinity);
71 if (rule == CanCrossEditingBoundary)
74 return honorEditingBoundaryAtOrAfter(next);
77 VisiblePosition VisiblePosition::previous(EditingBoundaryCrossingRule rule) const
79 // FIXME: Support CanSkipEditingBoundary
80 ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
81 // find first previous DOM position that is visible
82 Position pos = previousVisuallyDistinctCandidate(m_deepPosition);
84 // return null visible position if there is no previous visible position
85 if (pos.atStartOfTree())
86 return VisiblePosition();
88 VisiblePosition prev = VisiblePosition(pos, DOWNSTREAM);
89 ASSERT(prev != *this);
92 // we should always be able to make the affinity DOWNSTREAM, because going previous from an
93 // UPSTREAM position can never yield another UPSTREAM position (unless line wrap length is 0!).
94 if (prev.isNotNull() && m_affinity == UPSTREAM) {
95 VisiblePosition temp = prev;
96 temp.setAffinity(UPSTREAM);
97 ASSERT(inSameLine(temp, prev));
101 if (rule == CanCrossEditingBoundary)
104 return honorEditingBoundaryAtOrBefore(prev);
107 Position VisiblePosition::leftVisuallyDistinctCandidate() const
109 Position p = m_deepPosition;
113 Position downstreamStart = p.downstream();
114 TextDirection primaryDirection = p.primaryDirection();
119 p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
121 return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
123 RenderObject* renderer = box->renderer();
126 if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretRightmostOffset())
127 return box->isLeftToRightDirection() ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
129 if (!renderer->node()) {
130 box = box->prevLeafChild();
132 return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
133 renderer = box->renderer();
134 offset = box->caretRightmostOffset();
138 offset = box->isLeftToRightDirection() ? renderer->previousOffset(offset) : renderer->nextOffset(offset);
140 int caretMinOffset = box->caretMinOffset();
141 int caretMaxOffset = box->caretMaxOffset();
143 if (offset > caretMinOffset && offset < caretMaxOffset)
146 if (box->isLeftToRightDirection() ? offset < caretMinOffset : offset > caretMaxOffset) {
147 // Overshot to the left.
148 InlineBox* prevBox = box->prevLeafChild();
150 Position positionOnLeft = primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
151 if (positionOnLeft.isNull())
154 InlineBox* boxOnLeft;
156 positionOnLeft.getInlineBoxAndOffset(m_affinity, primaryDirection, boxOnLeft, offsetOnLeft);
157 if (boxOnLeft && boxOnLeft->root() == box->root())
159 return positionOnLeft;
162 // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
164 renderer = box->renderer();
165 offset = prevBox->caretRightmostOffset();
169 ASSERT(offset == box->caretLeftmostOffset());
171 unsigned char level = box->bidiLevel();
172 InlineBox* prevBox = box->prevLeafChild();
174 if (box->direction() == primaryDirection) {
176 InlineBox* logicalStart = 0;
177 if (primaryDirection == LTR ? box->root()->getLogicalStartBoxWithNode(logicalStart) : box->root()->getLogicalEndBoxWithNode(logicalStart)) {
179 renderer = box->renderer();
180 offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset();
184 if (prevBox->bidiLevel() >= level)
187 level = prevBox->bidiLevel();
189 InlineBox* nextBox = box;
191 nextBox = nextBox->nextLeafChild();
192 } while (nextBox && nextBox->bidiLevel() > level);
194 if (nextBox && nextBox->bidiLevel() == level)
198 renderer = box->renderer();
199 offset = box->caretRightmostOffset();
200 if (box->direction() == primaryDirection)
205 while (prevBox && !prevBox->renderer()->node())
206 prevBox = prevBox->prevLeafChild();
210 renderer = box->renderer();
211 offset = box->caretRightmostOffset();
212 if (box->bidiLevel() > level) {
214 prevBox = prevBox->prevLeafChild();
215 } while (prevBox && prevBox->bidiLevel() > level);
217 if (!prevBox || prevBox->bidiLevel() < level)
221 // Trailing edge of a secondary run. Set to the leading edge of the entire run.
223 while (InlineBox* nextBox = box->nextLeafChild()) {
224 if (nextBox->bidiLevel() < level)
228 if (box->bidiLevel() == level)
230 level = box->bidiLevel();
231 while (InlineBox* prevBox = box->prevLeafChild()) {
232 if (prevBox->bidiLevel() < level)
236 if (box->bidiLevel() == level)
238 level = box->bidiLevel();
240 renderer = box->renderer();
241 offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset();
246 p = createLegacyEditingPosition(renderer->node(), offset);
248 if ((p.isCandidate() && p.downstream() != downstreamStart) || p.atStartOfTree() || p.atEndOfTree())
251 ASSERT(p != m_deepPosition);
255 VisiblePosition VisiblePosition::left(bool stayInEditableContent) const
257 Position pos = leftVisuallyDistinctCandidate();
258 // FIXME: Why can't we move left from the last position in a tree?
259 if (pos.atStartOfTree() || pos.atEndOfTree())
260 return VisiblePosition();
262 VisiblePosition left = VisiblePosition(pos, DOWNSTREAM);
263 ASSERT(left != *this);
265 if (!stayInEditableContent)
268 // FIXME: This may need to do something different from "before".
269 return honorEditingBoundaryAtOrBefore(left);
272 Position VisiblePosition::rightVisuallyDistinctCandidate() const
274 Position p = m_deepPosition;
278 Position downstreamStart = p.downstream();
279 TextDirection primaryDirection = p.primaryDirection();
284 p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
286 return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
288 RenderObject* renderer = box->renderer();
291 if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretLeftmostOffset())
292 return box->isLeftToRightDirection() ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
294 if (!renderer->node()) {
295 box = box->nextLeafChild();
297 return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
298 renderer = box->renderer();
299 offset = box->caretLeftmostOffset();
303 offset = box->isLeftToRightDirection() ? renderer->nextOffset(offset) : renderer->previousOffset(offset);
305 int caretMinOffset = box->caretMinOffset();
306 int caretMaxOffset = box->caretMaxOffset();
308 if (offset > caretMinOffset && offset < caretMaxOffset)
311 if (box->isLeftToRightDirection() ? offset > caretMaxOffset : offset < caretMinOffset) {
312 // Overshot to the right.
313 InlineBox* nextBox = box->nextLeafChild();
315 Position positionOnRight = primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
316 if (positionOnRight.isNull())
319 InlineBox* boxOnRight;
321 positionOnRight.getInlineBoxAndOffset(m_affinity, primaryDirection, boxOnRight, offsetOnRight);
322 if (boxOnRight && boxOnRight->root() == box->root())
324 return positionOnRight;
327 // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
329 renderer = box->renderer();
330 offset = nextBox->caretLeftmostOffset();
334 ASSERT(offset == box->caretRightmostOffset());
336 unsigned char level = box->bidiLevel();
337 InlineBox* nextBox = box->nextLeafChild();
339 if (box->direction() == primaryDirection) {
341 InlineBox* logicalEnd = 0;
342 if (primaryDirection == LTR ? box->root()->getLogicalEndBoxWithNode(logicalEnd) : box->root()->getLogicalStartBoxWithNode(logicalEnd)) {
344 renderer = box->renderer();
345 offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset();
350 if (nextBox->bidiLevel() >= level)
353 level = nextBox->bidiLevel();
355 InlineBox* prevBox = box;
357 prevBox = prevBox->prevLeafChild();
358 } while (prevBox && prevBox->bidiLevel() > level);
360 if (prevBox && prevBox->bidiLevel() == level) // For example, abc FED 123 ^ CBA
363 // For example, abc 123 ^ CBA or 123 ^ CBA abc
365 renderer = box->renderer();
366 offset = box->caretLeftmostOffset();
367 if (box->direction() == primaryDirection)
372 while (nextBox && !nextBox->renderer()->node())
373 nextBox = nextBox->nextLeafChild();
377 renderer = box->renderer();
378 offset = box->caretLeftmostOffset();
380 if (box->bidiLevel() > level) {
382 nextBox = nextBox->nextLeafChild();
383 } while (nextBox && nextBox->bidiLevel() > level);
385 if (!nextBox || nextBox->bidiLevel() < level)
389 // Trailing edge of a secondary run. Set to the leading edge of the entire run.
391 while (InlineBox* prevBox = box->prevLeafChild()) {
392 if (prevBox->bidiLevel() < level)
396 if (box->bidiLevel() == level)
398 level = box->bidiLevel();
399 while (InlineBox* nextBox = box->nextLeafChild()) {
400 if (nextBox->bidiLevel() < level)
404 if (box->bidiLevel() == level)
406 level = box->bidiLevel();
408 renderer = box->renderer();
409 offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset();
414 p = createLegacyEditingPosition(renderer->node(), offset);
416 if ((p.isCandidate() && p.downstream() != downstreamStart) || p.atStartOfTree() || p.atEndOfTree())
419 ASSERT(p != m_deepPosition);
423 VisiblePosition VisiblePosition::right(bool stayInEditableContent) const
425 Position pos = rightVisuallyDistinctCandidate();
426 // FIXME: Why can't we move left from the last position in a tree?
427 if (pos.atStartOfTree() || pos.atEndOfTree())
428 return VisiblePosition();
430 VisiblePosition right = VisiblePosition(pos, DOWNSTREAM);
431 ASSERT(right != *this);
433 if (!stayInEditableContent)
436 // FIXME: This may need to do something different from "after".
437 return honorEditingBoundaryAtOrAfter(right);
440 VisiblePosition VisiblePosition::honorEditingBoundaryAtOrBefore(const VisiblePosition &pos) const
445 Node* highestRoot = highestEditableRoot(deepEquivalent());
447 // Return empty position if pos is not somewhere inside the editable region containing this position
448 if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot))
449 return VisiblePosition();
451 // Return pos itself if the two are from the very same editable region, or both are non-editable
452 // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
453 // to it is allowed. VisibleSelection::adjustForEditableContent has this problem too.
454 if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
457 // Return empty position if this position is non-editable, but pos is editable
458 // FIXME: Move to the previous non-editable region.
460 return VisiblePosition();
462 // Return the last position before pos that is in the same editable region as this position
463 return lastEditablePositionBeforePositionInRoot(pos.deepEquivalent(), highestRoot);
466 VisiblePosition VisiblePosition::honorEditingBoundaryAtOrAfter(const VisiblePosition &pos) const
471 Node* highestRoot = highestEditableRoot(deepEquivalent());
473 // Return empty position if pos is not somewhere inside the editable region containing this position
474 if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot))
475 return VisiblePosition();
477 // Return pos itself if the two are from the very same editable region, or both are non-editable
478 // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
479 // to it is allowed. VisibleSelection::adjustForEditableContent has this problem too.
480 if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
483 // Return empty position if this position is non-editable, but pos is editable
484 // FIXME: Move to the next non-editable region.
486 return VisiblePosition();
488 // Return the next position after pos that is in the same editable region as this position
489 return firstEditablePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot);
492 static Position canonicalizeCandidate(const Position& candidate)
494 if (candidate.isNull())
496 ASSERT(candidate.isCandidate());
497 Position upstream = candidate.upstream();
498 if (upstream.isCandidate())
503 Position VisiblePosition::canonicalPosition(const Position& passedPosition)
505 // The updateLayout call below can do so much that even the position passed
506 // in to us might get changed as a side effect. Specifically, there are code
507 // paths that pass selection endpoints, and updateLayout can change the selection.
508 Position position = passedPosition;
510 // FIXME (9535): Canonicalizing to the leftmost candidate means that if we're at a line wrap, we will
511 // ask renderers to paint downstream carets for other renderers.
512 // To fix this, we need to either a) add code to all paintCarets to pass the responsibility off to
513 // the appropriate renderer for VisiblePosition's like these, or b) canonicalize to the rightmost candidate
514 // unless the affinity is upstream.
515 if (position.isNull())
518 ASSERT(position.document());
519 position.document()->updateLayoutIgnorePendingStylesheets();
521 Node* node = position.containerNode();
523 Position candidate = position.upstream();
524 if (candidate.isCandidate())
526 candidate = position.downstream();
527 if (candidate.isCandidate())
530 // When neither upstream or downstream gets us to a candidate (upstream/downstream won't leave
531 // blocks or enter new ones), we search forward and backward until we find one.
532 Position next = canonicalizeCandidate(nextCandidate(position));
533 Position prev = canonicalizeCandidate(previousCandidate(position));
534 Node* nextNode = next.deprecatedNode();
535 Node* prevNode = prev.deprecatedNode();
537 // The new position must be in the same editable element. Enforce that first.
538 // Unless the descent is from a non-editable html element to an editable body.
539 if (node && node->hasTagName(htmlTag) && !node->rendererIsEditable() && node->document()->body() && node->document()->body()->rendererIsEditable())
540 return next.isNotNull() ? next : prev;
542 Node* editingRoot = editableRootForPosition(position);
544 // If the html element is editable, descending into its body will look like a descent
545 // from non-editable to editable content since rootEditableElement() always stops at the body.
546 if ((editingRoot && editingRoot->hasTagName(htmlTag)) || position.deprecatedNode()->isDocumentNode())
547 return next.isNotNull() ? next : prev;
549 bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev) == editingRoot;
550 bool nextIsInSameEditableElement = nextNode && editableRootForPosition(next) == editingRoot;
551 if (prevIsInSameEditableElement && !nextIsInSameEditableElement)
554 if (nextIsInSameEditableElement && !prevIsInSameEditableElement)
557 if (!nextIsInSameEditableElement && !prevIsInSameEditableElement)
560 // The new position should be in the same block flow element. Favor that.
561 Node* originalBlock = node ? node->enclosingBlockFlowElement() : 0;
562 bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) && nextNode != originalBlock;
563 bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) && prevNode != originalBlock;
564 if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock)
570 UChar32 VisiblePosition::characterAfter() const
572 // We canonicalize to the first of two equivalent candidates, but the second of the two candidates
573 // is the one that will be inside the text node containing the character after this visible position.
574 Position pos = m_deepPosition.downstream();
575 if (!pos.containerNode() || !pos.containerNode()->isTextNode())
577 switch (pos.anchorType()) {
578 case Position::PositionIsAfterChildren:
579 case Position::PositionIsAfterAnchor:
580 case Position::PositionIsBeforeAnchor:
581 case Position::PositionIsBeforeChildren:
583 case Position::PositionIsOffsetInAnchor:
586 unsigned offset = static_cast<unsigned>(pos.offsetInContainerNode());
587 Text* textNode = pos.containerText();
588 unsigned length = textNode->length();
589 if (offset >= length)
593 const UChar* characters = textNode->data().characters();
594 U16_NEXT(characters, offset, length, ch);
598 IntRect VisiblePosition::localCaretRect(RenderObject*& renderer) const
600 if (m_deepPosition.isNull()) {
604 Node* node = m_deepPosition.anchorNode();
606 renderer = node->renderer();
610 InlineBox* inlineBox;
612 getInlineBoxAndOffset(inlineBox, caretOffset);
615 renderer = inlineBox->renderer();
617 return renderer->localCaretRect(inlineBox, caretOffset);
620 IntRect VisiblePosition::absoluteCaretBounds() const
622 RenderObject* renderer;
623 IntRect localRect = localCaretRect(renderer);
624 if (localRect.isEmpty() || !renderer)
627 return renderer->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
630 int VisiblePosition::lineDirectionPointForBlockDirectionNavigation() const
632 RenderObject* renderer;
633 IntRect localRect = localCaretRect(renderer);
634 if (localRect.isEmpty() || !renderer)
637 // This ignores transforms on purpose, for now. Vertical navigation is done
638 // without consulting transforms, so that 'up' in transformed text is 'up'
639 // relative to the text, not absolute 'up'.
640 FloatPoint caretPoint = renderer->localToAbsolute(localRect.location());
641 RenderObject* containingBlock = renderer->containingBlock();
642 if (!containingBlock)
643 containingBlock = renderer; // Just use ourselves to determine the writing mode if we have no containing block.
644 return containingBlock->isHorizontalWritingMode() ? caretPoint.x() : caretPoint.y();
649 void VisiblePosition::debugPosition(const char* msg) const
652 fprintf(stderr, "Position [%s]: null\n", msg);
654 fprintf(stderr, "Position [%s]: %s, ", msg, m_deepPosition.deprecatedNode()->nodeName().utf8().data());
655 m_deepPosition.showAnchorTypeAndOffset();
659 void VisiblePosition::formatForDebugger(char* buffer, unsigned length) const
661 m_deepPosition.formatForDebugger(buffer, length);
664 void VisiblePosition::showTreeForThis() const
666 m_deepPosition.showTreeForThis();
671 PassRefPtr<Range> makeRange(const VisiblePosition &start, const VisiblePosition &end)
673 if (start.isNull() || end.isNull())
676 Position s = start.deepEquivalent().parentAnchoredEquivalent();
677 Position e = end.deepEquivalent().parentAnchoredEquivalent();
678 if (s.isNull() || e.isNull())
681 return Range::create(s.containerNode()->document(), s.containerNode(), s.offsetInContainerNode(), e.containerNode(), e.offsetInContainerNode());
684 VisiblePosition startVisiblePosition(const Range *r, EAffinity affinity)
686 return VisiblePosition(r->startPosition(), affinity);
689 VisiblePosition endVisiblePosition(const Range *r, EAffinity affinity)
691 return VisiblePosition(r->endPosition(), affinity);
694 bool setStart(Range *r, const VisiblePosition &visiblePosition)
698 Position p = visiblePosition.deepEquivalent().parentAnchoredEquivalent();
700 r->setStart(p.containerNode(), p.offsetInContainerNode(), code);
704 bool setEnd(Range *r, const VisiblePosition &visiblePosition)
708 Position p = visiblePosition.deepEquivalent().parentAnchoredEquivalent();
710 r->setEnd(p.containerNode(), p.offsetInContainerNode(), code);
714 Element* enclosingBlockFlowElement(const VisiblePosition &visiblePosition)
716 if (visiblePosition.isNull())
719 return visiblePosition.deepEquivalent().deprecatedNode()->enclosingBlockFlowElement();
722 bool isFirstVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node)
724 if (visiblePosition.isNull())
727 if (!visiblePosition.deepEquivalent().containerNode()->isDescendantOf(node))
730 VisiblePosition previous = visiblePosition.previous();
731 return previous.isNull() || !previous.deepEquivalent().deprecatedNode()->isDescendantOf(node);
734 bool isLastVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node)
736 if (visiblePosition.isNull())
739 if (!visiblePosition.deepEquivalent().containerNode()->isDescendantOf(node))
742 VisiblePosition next = visiblePosition.next();
743 return next.isNull() || !next.deepEquivalent().deprecatedNode()->isDescendantOf(node);
746 } // namespace WebCore
750 void showTree(const WebCore::VisiblePosition* vpos)
753 vpos->showTreeForThis();
756 void showTree(const WebCore::VisiblePosition& vpos)
758 vpos.showTreeForThis();