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 "core/editing/VisiblePosition.h"
30 #include "bindings/core/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"
49 using namespace HTMLNames;
51 VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity)
56 VisiblePosition::VisiblePosition(const PositionWithAffinity& positionWithAffinity)
58 init(positionWithAffinity.position(), positionWithAffinity.affinity());
61 void VisiblePosition::init(const Position& position, EAffinity affinity)
63 m_affinity = affinity;
65 m_deepPosition = canonicalPosition(position);
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;
72 VisiblePosition VisiblePosition::next(EditingBoundaryCrossingRule rule) const
74 VisiblePosition next(nextVisuallyDistinctCandidate(m_deepPosition), m_affinity);
77 case CanCrossEditingBoundary:
79 case CannotCrossEditingBoundary:
80 return honorEditingBoundaryAtOrAfter(next);
81 case CanSkipOverEditingBoundary:
82 return skipToEndOfEditingBoundary(next);
85 return honorEditingBoundaryAtOrAfter(next);
88 VisiblePosition VisiblePosition::previous(EditingBoundaryCrossingRule rule) const
90 Position pos = previousVisuallyDistinctCandidate(m_deepPosition);
92 // return null visible position if there is no previous visible position
93 if (pos.atStartOfTree())
94 return VisiblePosition();
96 VisiblePosition prev = VisiblePosition(pos, DOWNSTREAM);
97 ASSERT(prev != *this);
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));
110 case CanCrossEditingBoundary:
112 case CannotCrossEditingBoundary:
113 return honorEditingBoundaryAtOrBefore(prev);
114 case CanSkipOverEditingBoundary:
115 return skipToStartOfEditingBoundary(prev);
118 ASSERT_NOT_REACHED();
119 return honorEditingBoundaryAtOrBefore(prev);
122 Position VisiblePosition::leftVisuallyDistinctCandidate() const
124 Position p = m_deepPosition;
128 Position downstreamStart = p.downstream();
129 TextDirection primaryDirection = p.primaryDirection();
134 p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
136 return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
138 RenderObject* renderer = &box->renderer();
141 if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretRightmostOffset())
142 return box->isLeftToRightDirection() ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
144 if (!renderer->node()) {
145 box = box->prevLeafChild();
147 return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
148 renderer = &box->renderer();
149 offset = box->caretRightmostOffset();
153 offset = box->isLeftToRightDirection() ? renderer->previousOffset(offset) : renderer->nextOffset(offset);
155 int caretMinOffset = box->caretMinOffset();
156 int caretMaxOffset = box->caretMaxOffset();
158 if (offset > caretMinOffset && offset < caretMaxOffset)
161 if (box->isLeftToRightDirection() ? offset < caretMinOffset : offset > caretMaxOffset) {
162 // Overshot to the left.
163 InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak();
165 Position positionOnLeft = primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
166 if (positionOnLeft.isNull())
169 InlineBox* boxOnLeft;
171 positionOnLeft.getInlineBoxAndOffset(m_affinity, primaryDirection, boxOnLeft, offsetOnLeft);
172 if (boxOnLeft && boxOnLeft->root() == box->root())
174 return positionOnLeft;
177 // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
179 renderer = &box->renderer();
180 offset = prevBox->caretRightmostOffset();
184 ASSERT(offset == box->caretLeftmostOffset());
186 unsigned char level = box->bidiLevel();
187 InlineBox* prevBox = box->prevLeafChild();
189 if (box->direction() == primaryDirection) {
191 InlineBox* logicalStart = 0;
192 if (primaryDirection == LTR ? box->root().getLogicalStartBoxWithNode(logicalStart) : box->root().getLogicalEndBoxWithNode(logicalStart)) {
194 renderer = &box->renderer();
195 offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset();
199 if (prevBox->bidiLevel() >= level)
202 level = prevBox->bidiLevel();
204 InlineBox* nextBox = box;
206 nextBox = nextBox->nextLeafChild();
207 } while (nextBox && nextBox->bidiLevel() > level);
209 if (nextBox && nextBox->bidiLevel() == level)
213 renderer = &box->renderer();
214 offset = box->caretRightmostOffset();
215 if (box->direction() == primaryDirection)
220 while (prevBox && !prevBox->renderer().node())
221 prevBox = prevBox->prevLeafChild();
225 renderer = &box->renderer();
226 offset = box->caretRightmostOffset();
227 if (box->bidiLevel() > level) {
229 prevBox = prevBox->prevLeafChild();
230 } while (prevBox && prevBox->bidiLevel() > level);
232 if (!prevBox || prevBox->bidiLevel() < level)
236 // Trailing edge of a secondary run. Set to the leading edge of the entire run.
238 while (InlineBox* nextBox = box->nextLeafChild()) {
239 if (nextBox->bidiLevel() < level)
243 if (box->bidiLevel() == level)
245 level = box->bidiLevel();
246 while (InlineBox* prevBox = box->prevLeafChild()) {
247 if (prevBox->bidiLevel() < level)
251 if (box->bidiLevel() == level)
253 level = box->bidiLevel();
255 renderer = &box->renderer();
256 offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset();
261 p = createLegacyEditingPosition(renderer->node(), offset);
263 if ((p.isCandidate() && p.downstream() != downstreamStart) || p.atStartOfTree() || p.atEndOfTree())
266 ASSERT(p != m_deepPosition);
270 VisiblePosition VisiblePosition::left(bool stayInEditableContent) const
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();
277 VisiblePosition left = VisiblePosition(pos, DOWNSTREAM);
278 ASSERT(left != *this);
280 if (!stayInEditableContent)
283 // FIXME: This may need to do something different from "before".
284 return honorEditingBoundaryAtOrBefore(left);
287 Position VisiblePosition::rightVisuallyDistinctCandidate() const
289 Position p = m_deepPosition;
293 Position downstreamStart = p.downstream();
294 TextDirection primaryDirection = p.primaryDirection();
299 p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
301 return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
303 RenderObject* renderer = &box->renderer();
306 if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretLeftmostOffset())
307 return box->isLeftToRightDirection() ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
309 if (!renderer->node()) {
310 box = box->nextLeafChild();
312 return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
313 renderer = &box->renderer();
314 offset = box->caretLeftmostOffset();
318 offset = box->isLeftToRightDirection() ? renderer->nextOffset(offset) : renderer->previousOffset(offset);
320 int caretMinOffset = box->caretMinOffset();
321 int caretMaxOffset = box->caretMaxOffset();
323 if (offset > caretMinOffset && offset < caretMaxOffset)
326 if (box->isLeftToRightDirection() ? offset > caretMaxOffset : offset < caretMinOffset) {
327 // Overshot to the right.
328 InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak();
330 Position positionOnRight = primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
331 if (positionOnRight.isNull())
334 InlineBox* boxOnRight;
336 positionOnRight.getInlineBoxAndOffset(m_affinity, primaryDirection, boxOnRight, offsetOnRight);
337 if (boxOnRight && boxOnRight->root() == box->root())
339 return positionOnRight;
342 // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
344 renderer = &box->renderer();
345 offset = nextBox->caretLeftmostOffset();
349 ASSERT(offset == box->caretRightmostOffset());
351 unsigned char level = box->bidiLevel();
352 InlineBox* nextBox = box->nextLeafChild();
354 if (box->direction() == primaryDirection) {
356 InlineBox* logicalEnd = 0;
357 if (primaryDirection == LTR ? box->root().getLogicalEndBoxWithNode(logicalEnd) : box->root().getLogicalStartBoxWithNode(logicalEnd)) {
359 renderer = &box->renderer();
360 offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset();
365 if (nextBox->bidiLevel() >= level)
368 level = nextBox->bidiLevel();
370 InlineBox* prevBox = box;
372 prevBox = prevBox->prevLeafChild();
373 } while (prevBox && prevBox->bidiLevel() > level);
375 if (prevBox && prevBox->bidiLevel() == level) // For example, abc FED 123 ^ CBA
378 // For example, abc 123 ^ CBA or 123 ^ CBA abc
380 renderer = &box->renderer();
381 offset = box->caretLeftmostOffset();
382 if (box->direction() == primaryDirection)
387 while (nextBox && !nextBox->renderer().node())
388 nextBox = nextBox->nextLeafChild();
392 renderer = &box->renderer();
393 offset = box->caretLeftmostOffset();
395 if (box->bidiLevel() > level) {
397 nextBox = nextBox->nextLeafChild();
398 } while (nextBox && nextBox->bidiLevel() > level);
400 if (!nextBox || nextBox->bidiLevel() < level)
404 // Trailing edge of a secondary run. Set to the leading edge of the entire run.
406 while (InlineBox* prevBox = box->prevLeafChild()) {
407 if (prevBox->bidiLevel() < level)
411 if (box->bidiLevel() == level)
413 level = box->bidiLevel();
414 while (InlineBox* nextBox = box->nextLeafChild()) {
415 if (nextBox->bidiLevel() < level)
419 if (box->bidiLevel() == level)
421 level = box->bidiLevel();
423 renderer = &box->renderer();
424 offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset();
429 p = createLegacyEditingPosition(renderer->node(), offset);
431 if ((p.isCandidate() && p.downstream() != downstreamStart) || p.atStartOfTree() || p.atEndOfTree())
434 ASSERT(p != m_deepPosition);
438 VisiblePosition VisiblePosition::right(bool stayInEditableContent) const
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();
445 VisiblePosition right = VisiblePosition(pos, DOWNSTREAM);
446 ASSERT(right != *this);
448 if (!stayInEditableContent)
451 // FIXME: This may need to do something different from "after".
452 return honorEditingBoundaryAtOrAfter(right);
455 VisiblePosition VisiblePosition::honorEditingBoundaryAtOrBefore(const VisiblePosition &pos) const
460 ContainerNode* highestRoot = highestEditableRoot(deepEquivalent());
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();
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)
472 // Return empty position if this position is non-editable, but pos is editable
473 // FIXME: Move to the previous non-editable region.
475 return VisiblePosition();
477 // Return the last position before pos that is in the same editable region as this position
478 return lastEditableVisiblePositionBeforePositionInRoot(pos.deepEquivalent(), highestRoot);
481 VisiblePosition VisiblePosition::honorEditingBoundaryAtOrAfter(const VisiblePosition &pos) const
486 ContainerNode* highestRoot = highestEditableRoot(deepEquivalent());
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();
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)
498 // Return empty position if this position is non-editable, but pos is editable
499 // FIXME: Move to the next non-editable region.
501 return VisiblePosition();
503 // Return the next position after pos that is in the same editable region as this position
504 return firstEditableVisiblePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot);
507 VisiblePosition VisiblePosition::skipToStartOfEditingBoundary(const VisiblePosition &pos) const
512 ContainerNode* highestRoot = highestEditableRoot(deepEquivalent());
513 ContainerNode* highestRootOfPos = highestEditableRoot(pos.deepEquivalent());
515 // Return pos itself if the two are from the very same editable region, or both are non-editable.
516 if (highestRootOfPos == highestRoot)
519 // If |pos| has an editable root, skip to the start
520 if (highestRootOfPos)
521 return VisiblePosition(previousVisuallyDistinctCandidate(Position(highestRootOfPos, Position::PositionIsBeforeAnchor).parentAnchoredEquivalent()));
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);
527 VisiblePosition VisiblePosition::skipToEndOfEditingBoundary(const VisiblePosition &pos) const
532 ContainerNode* highestRoot = highestEditableRoot(deepEquivalent());
533 ContainerNode* highestRootOfPos = highestEditableRoot(pos.deepEquivalent());
535 // Return pos itself if the two are from the very same editable region, or both are non-editable.
536 if (highestRootOfPos == highestRoot)
539 // If |pos| has an editable root, skip to the end
540 if (highestRootOfPos)
541 return VisiblePosition(Position(highestRootOfPos, Position::PositionIsAfterAnchor).parentAnchoredEquivalent());
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);
547 static Position canonicalizeCandidate(const Position& candidate)
549 if (candidate.isNull())
551 ASSERT(candidate.isCandidate());
552 Position upstream = candidate.upstream();
553 if (upstream.isCandidate())
558 Position VisiblePosition::canonicalPosition(const Position& passedPosition)
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;
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())
573 ASSERT(position.document());
574 position.document()->updateLayoutIgnorePendingStylesheets();
576 Node* node = position.containerNode();
578 Position candidate = position.upstream();
579 if (candidate.isCandidate())
581 candidate = position.downstream();
582 if (candidate.isCandidate())
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();
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->hasEditableStyle() && node->document().body() && node->document().body()->hasEditableStyle())
595 return next.isNotNull() ? next : prev;
597 Element* editingRoot = editableRootForPosition(position);
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;
604 bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev) == editingRoot;
605 bool nextIsInSameEditableElement = nextNode && editableRootForPosition(next) == editingRoot;
606 if (prevIsInSameEditableElement && !nextIsInSameEditableElement)
609 if (nextIsInSameEditableElement && !prevIsInSameEditableElement)
612 if (!nextIsInSameEditableElement && !prevIsInSameEditableElement)
615 // The new position should be in the same block flow element. Favor that.
616 Element* originalBlock = node ? enclosingBlockFlowElement(*node) : 0;
617 bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) && nextNode != originalBlock;
618 bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) && prevNode != originalBlock;
619 if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock)
625 UChar32 VisiblePosition::characterAfter() const
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())
632 switch (pos.anchorType()) {
633 case Position::PositionIsAfterChildren:
634 case Position::PositionIsAfterAnchor:
635 case Position::PositionIsBeforeAnchor:
636 case Position::PositionIsBeforeChildren:
638 case Position::PositionIsOffsetInAnchor:
641 unsigned offset = static_cast<unsigned>(pos.offsetInContainerNode());
642 Text* textNode = pos.containerText();
643 unsigned length = textNode->length();
644 if (offset >= length)
647 return textNode->data().characterStartingAt(offset);
650 LayoutRect VisiblePosition::localCaretRect(RenderObject*& renderer) const
652 PositionWithAffinity positionWithAffinity(m_deepPosition, m_affinity);
653 return localCaretRectOfPosition(positionWithAffinity, renderer);
656 IntRect VisiblePosition::absoluteCaretBounds() const
658 RenderObject* renderer;
659 LayoutRect localRect = localCaretRect(renderer);
660 if (localRect.isEmpty() || !renderer)
663 return renderer->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
666 int VisiblePosition::lineDirectionPointForBlockDirectionNavigation() const
668 RenderObject* renderer;
669 LayoutRect localRect = localCaretRect(renderer);
670 if (localRect.isEmpty() || !renderer)
673 // This ignores transforms on purpose, for now. Vertical navigation is done
674 // without consulting transforms, so that 'up' in transformed text is 'up'
675 // relative to the text, not absolute 'up'.
676 FloatPoint caretPoint = renderer->localToAbsolute(localRect.location());
677 RenderObject* containingBlock = renderer->containingBlock();
678 if (!containingBlock)
679 containingBlock = renderer; // Just use ourselves to determine the writing mode if we have no containing block.
680 return containingBlock->isHorizontalWritingMode() ? caretPoint.x() : caretPoint.y();
685 void VisiblePosition::debugPosition(const char* msg) const
688 fprintf(stderr, "Position [%s]: null\n", msg);
690 fprintf(stderr, "Position [%s]: %s, ", msg, m_deepPosition.deprecatedNode()->nodeName().utf8().data());
691 m_deepPosition.showAnchorTypeAndOffset();
695 void VisiblePosition::formatForDebugger(char* buffer, unsigned length) const
697 m_deepPosition.formatForDebugger(buffer, length);
700 void VisiblePosition::showTreeForThis() const
702 m_deepPosition.showTreeForThis();
707 PassRefPtrWillBeRawPtr<Range> makeRange(const VisiblePosition &start, const VisiblePosition &end)
709 if (start.isNull() || end.isNull())
712 Position s = start.deepEquivalent().parentAnchoredEquivalent();
713 Position e = end.deepEquivalent().parentAnchoredEquivalent();
714 if (s.isNull() || e.isNull())
717 return Range::create(s.containerNode()->document(), s.containerNode(), s.offsetInContainerNode(), e.containerNode(), e.offsetInContainerNode());
720 VisiblePosition startVisiblePosition(const Range *r, EAffinity affinity)
722 return VisiblePosition(r->startPosition(), affinity);
725 bool setStart(Range *r, const VisiblePosition &visiblePosition)
729 Position p = visiblePosition.deepEquivalent().parentAnchoredEquivalent();
730 TrackExceptionState exceptionState;
731 r->setStart(p.containerNode(), p.offsetInContainerNode(), exceptionState);
732 return !exceptionState.hadException();
735 bool setEnd(Range *r, const VisiblePosition &visiblePosition)
739 Position p = visiblePosition.deepEquivalent().parentAnchoredEquivalent();
740 TrackExceptionState exceptionState;
741 r->setEnd(p.containerNode(), p.offsetInContainerNode(), exceptionState);
742 return !exceptionState.hadException();
745 Element* enclosingBlockFlowElement(const VisiblePosition& visiblePosition)
747 if (visiblePosition.isNull())
750 return enclosingBlockFlowElement(*visiblePosition.deepEquivalent().deprecatedNode());
753 bool isFirstVisiblePositionInNode(const VisiblePosition& visiblePosition, const ContainerNode* node)
755 if (visiblePosition.isNull())
758 if (!visiblePosition.deepEquivalent().containerNode()->isDescendantOf(node))
761 VisiblePosition previous = visiblePosition.previous();
762 return previous.isNull() || !previous.deepEquivalent().deprecatedNode()->isDescendantOf(node);
765 bool isLastVisiblePositionInNode(const VisiblePosition& visiblePosition, const ContainerNode* node)
767 if (visiblePosition.isNull())
770 if (!visiblePosition.deepEquivalent().containerNode()->isDescendantOf(node))
773 VisiblePosition next = visiblePosition.next();
774 return next.isNull() || !next.deepEquivalent().deprecatedNode()->isDescendantOf(node);
777 void VisiblePosition::trace(Visitor* visitor)
779 visitor->trace(m_deepPosition);
786 void showTree(const blink::VisiblePosition* vpos)
789 vpos->showTreeForThis();
792 void showTree(const blink::VisiblePosition& vpos)
794 vpos.showTreeForThis();