2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "VisiblePosition.h"
30 #include "FloatQuad.h"
31 #include "HTMLElement.h"
32 #include "HTMLNames.h"
33 #include "InlineTextBox.h"
36 #include "RenderBlock.h"
37 #include "RootInlineBox.h"
39 #include "htmlediting.h"
40 #include "visible_units.h"
42 #include <wtf/text/CString.h>
46 using namespace HTMLNames;
48 VisiblePosition::VisiblePosition(const Position &pos, EAffinity affinity)
53 void VisiblePosition::init(const Position& position, EAffinity affinity)
55 m_affinity = affinity;
57 m_deepPosition = canonicalPosition(position);
59 // When not at a line wrap, make sure to end up with DOWNSTREAM affinity.
60 if (m_affinity == UPSTREAM && (isNull() || inSameLine(VisiblePosition(position, DOWNSTREAM), *this)))
61 m_affinity = DOWNSTREAM;
64 VisiblePosition VisiblePosition::next(EditingBoundaryCrossingRule rule) const
66 // FIXME: Support CanSkipEditingBoundary
67 ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
68 VisiblePosition next(nextVisuallyDistinctCandidate(m_deepPosition), m_affinity);
70 if (rule == CanCrossEditingBoundary)
73 return honorEditingBoundaryAtOrAfter(next);
76 VisiblePosition VisiblePosition::previous(EditingBoundaryCrossingRule rule) const
78 // FIXME: Support CanSkipEditingBoundary
79 ASSERT(rule == CanCrossEditingBoundary || rule == CannotCrossEditingBoundary);
80 // find first previous DOM position that is visible
81 Position pos = previousVisuallyDistinctCandidate(m_deepPosition);
83 // return null visible position if there is no previous visible position
84 if (pos.atStartOfTree())
85 return VisiblePosition();
87 VisiblePosition prev = VisiblePosition(pos, DOWNSTREAM);
88 ASSERT(prev != *this);
91 // we should always be able to make the affinity DOWNSTREAM, because going previous from an
92 // UPSTREAM position can never yield another UPSTREAM position (unless line wrap length is 0!).
93 if (prev.isNotNull() && m_affinity == UPSTREAM) {
94 VisiblePosition temp = prev;
95 temp.setAffinity(UPSTREAM);
96 ASSERT(inSameLine(temp, prev));
100 if (rule == CanCrossEditingBoundary)
103 return honorEditingBoundaryAtOrBefore(prev);
106 Position VisiblePosition::leftVisuallyDistinctCandidate() const
108 Position p = m_deepPosition;
112 Position downstreamStart = p.downstream();
113 TextDirection primaryDirection = p.primaryDirection();
118 p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
120 return primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
122 RenderObject* renderer = box->renderer();
125 if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretRightmostOffset())
126 return box->isLeftToRightDirection() ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
128 offset = box->isLeftToRightDirection() ? renderer->previousOffset(offset) : renderer->nextOffset(offset);
130 int caretMinOffset = box->caretMinOffset();
131 int caretMaxOffset = box->caretMaxOffset();
133 if (offset > caretMinOffset && offset < caretMaxOffset)
136 if (box->isLeftToRightDirection() ? offset < caretMinOffset : offset > caretMaxOffset) {
137 // Overshot to the left.
138 InlineBox* prevBox = box->prevLeafChild();
140 Position positionOnLeft = primaryDirection == LTR ? previousVisuallyDistinctCandidate(m_deepPosition) : nextVisuallyDistinctCandidate(m_deepPosition);
141 if (positionOnLeft.isNull())
144 InlineBox* boxOnLeft;
146 positionOnLeft.getInlineBoxAndOffset(m_affinity, primaryDirection, boxOnLeft, offsetOnLeft);
147 if (boxOnLeft && boxOnLeft->root() == box->root())
149 return positionOnLeft;
152 // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
154 renderer = box->renderer();
155 offset = prevBox->caretRightmostOffset();
159 ASSERT(offset == box->caretLeftmostOffset());
161 unsigned char level = box->bidiLevel();
162 InlineBox* prevBox = box->prevLeafChild();
164 if (box->direction() == primaryDirection) {
166 InlineBox* logicalStart = 0;
167 if (primaryDirection == LTR ? box->root()->getLogicalStartBoxWithNode(logicalStart) : box->root()->getLogicalEndBoxWithNode(logicalStart)) {
169 renderer = box->renderer();
170 offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset();
174 if (prevBox->bidiLevel() >= level)
177 level = prevBox->bidiLevel();
179 InlineBox* nextBox = box;
181 nextBox = nextBox->nextLeafChild();
182 } while (nextBox && nextBox->bidiLevel() > level);
184 if (nextBox && nextBox->bidiLevel() == level)
188 renderer = box->renderer();
189 offset = box->caretRightmostOffset();
190 if (box->direction() == primaryDirection)
197 renderer = box->renderer();
198 offset = box->caretRightmostOffset();
199 if (box->bidiLevel() > level) {
201 prevBox = prevBox->prevLeafChild();
202 } while (prevBox && prevBox->bidiLevel() > level);
204 if (!prevBox || prevBox->bidiLevel() < level)
208 // Trailing edge of a secondary run. Set to the leading edge of the entire run.
210 while (InlineBox* nextBox = box->nextLeafChild()) {
211 if (nextBox->bidiLevel() < level)
215 if (box->bidiLevel() == level)
217 level = box->bidiLevel();
218 while (InlineBox* prevBox = box->prevLeafChild()) {
219 if (prevBox->bidiLevel() < level)
223 if (box->bidiLevel() == level)
225 level = box->bidiLevel();
227 renderer = box->renderer();
228 offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset();
233 p = createLegacyEditingPosition(renderer->node(), offset);
235 if ((p.isCandidate() && p.downstream() != downstreamStart) || p.atStartOfTree() || p.atEndOfTree())
240 VisiblePosition VisiblePosition::left(bool stayInEditableContent) const
242 Position pos = leftVisuallyDistinctCandidate();
243 // FIXME: Why can't we move left from the last position in a tree?
244 if (pos.atStartOfTree() || pos.atEndOfTree())
245 return VisiblePosition();
247 VisiblePosition left = VisiblePosition(pos, DOWNSTREAM);
248 ASSERT(left != *this);
250 if (!stayInEditableContent)
253 // FIXME: This may need to do something different from "before".
254 return honorEditingBoundaryAtOrBefore(left);
257 Position VisiblePosition::rightVisuallyDistinctCandidate() const
259 Position p = m_deepPosition;
263 Position downstreamStart = p.downstream();
264 TextDirection primaryDirection = p.primaryDirection();
269 p.getInlineBoxAndOffset(m_affinity, primaryDirection, box, offset);
271 return primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
273 RenderObject* renderer = box->renderer();
276 if ((renderer->isReplaced() || renderer->isBR()) && offset == box->caretLeftmostOffset())
277 return box->isLeftToRightDirection() ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
279 offset = box->isLeftToRightDirection() ? renderer->nextOffset(offset) : renderer->previousOffset(offset);
281 int caretMinOffset = box->caretMinOffset();
282 int caretMaxOffset = box->caretMaxOffset();
284 if (offset > caretMinOffset && offset < caretMaxOffset)
287 if (box->isLeftToRightDirection() ? offset > caretMaxOffset : offset < caretMinOffset) {
288 // Overshot to the right.
289 InlineBox* nextBox = box->nextLeafChild();
291 Position positionOnRight = primaryDirection == LTR ? nextVisuallyDistinctCandidate(m_deepPosition) : previousVisuallyDistinctCandidate(m_deepPosition);
292 if (positionOnRight.isNull())
295 InlineBox* boxOnRight;
297 positionOnRight.getInlineBoxAndOffset(m_affinity, primaryDirection, boxOnRight, offsetOnRight);
298 if (boxOnRight && boxOnRight->root() == box->root())
300 return positionOnRight;
303 // Reposition at the other logical position corresponding to our edge's visual position and go for another round.
305 renderer = box->renderer();
306 offset = nextBox->caretLeftmostOffset();
310 ASSERT(offset == box->caretRightmostOffset());
312 unsigned char level = box->bidiLevel();
313 InlineBox* nextBox = box->nextLeafChild();
315 if (box->direction() == primaryDirection) {
317 InlineBox* logicalEnd = 0;
318 if (primaryDirection == LTR ? box->root()->getLogicalEndBoxWithNode(logicalEnd) : box->root()->getLogicalStartBoxWithNode(logicalEnd)) {
320 renderer = box->renderer();
321 offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset();
325 if (nextBox->bidiLevel() >= level)
328 level = nextBox->bidiLevel();
330 InlineBox* prevBox = box;
332 prevBox = prevBox->prevLeafChild();
333 } while (prevBox && prevBox->bidiLevel() > level);
335 if (prevBox && prevBox->bidiLevel() == level) // For example, abc FED 123 ^ CBA
338 // For example, abc 123 ^ CBA or 123 ^ CBA abc
340 renderer = box->renderer();
341 offset = box->caretLeftmostOffset();
342 if (box->direction() == primaryDirection)
349 renderer = box->renderer();
350 offset = box->caretLeftmostOffset();
351 if (box->bidiLevel() > level) {
353 nextBox = nextBox->nextLeafChild();
354 } while (nextBox && nextBox->bidiLevel() > level);
356 if (!nextBox || nextBox->bidiLevel() < level)
360 // Trailing edge of a secondary run. Set to the leading edge of the entire run.
362 while (InlineBox* prevBox = box->prevLeafChild()) {
363 if (prevBox->bidiLevel() < level)
367 if (box->bidiLevel() == level)
369 level = box->bidiLevel();
370 while (InlineBox* nextBox = box->nextLeafChild()) {
371 if (nextBox->bidiLevel() < level)
375 if (box->bidiLevel() == level)
377 level = box->bidiLevel();
379 renderer = box->renderer();
380 offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset();
385 p = createLegacyEditingPosition(renderer->node(), offset);
387 if ((p.isCandidate() && p.downstream() != downstreamStart) || p.atStartOfTree() || p.atEndOfTree())
392 VisiblePosition VisiblePosition::right(bool stayInEditableContent) const
394 Position pos = rightVisuallyDistinctCandidate();
395 // FIXME: Why can't we move left from the last position in a tree?
396 if (pos.atStartOfTree() || pos.atEndOfTree())
397 return VisiblePosition();
399 VisiblePosition right = VisiblePosition(pos, DOWNSTREAM);
400 ASSERT(right != *this);
402 if (!stayInEditableContent)
405 // FIXME: This may need to do something different from "after".
406 return honorEditingBoundaryAtOrAfter(right);
409 VisiblePosition VisiblePosition::honorEditingBoundaryAtOrBefore(const VisiblePosition &pos) const
414 Node* highestRoot = highestEditableRoot(deepEquivalent());
416 // Return empty position if pos is not somewhere inside the editable region containing this position
417 if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot))
418 return VisiblePosition();
420 // Return pos itself if the two are from the very same editable region, or both are non-editable
421 // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
422 // to it is allowed. VisibleSelection::adjustForEditableContent has this problem too.
423 if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
426 // Return empty position if this position is non-editable, but pos is editable
427 // FIXME: Move to the previous non-editable region.
429 return VisiblePosition();
431 // Return the last position before pos that is in the same editable region as this position
432 return lastEditablePositionBeforePositionInRoot(pos.deepEquivalent(), highestRoot);
435 VisiblePosition VisiblePosition::honorEditingBoundaryAtOrAfter(const VisiblePosition &pos) const
440 Node* highestRoot = highestEditableRoot(deepEquivalent());
442 // Return empty position if pos is not somewhere inside the editable region containing this position
443 if (highestRoot && !pos.deepEquivalent().deprecatedNode()->isDescendantOf(highestRoot))
444 return VisiblePosition();
446 // Return pos itself if the two are from the very same editable region, or both are non-editable
447 // FIXME: In the non-editable case, just because the new position is non-editable doesn't mean movement
448 // to it is allowed. VisibleSelection::adjustForEditableContent has this problem too.
449 if (highestEditableRoot(pos.deepEquivalent()) == highestRoot)
452 // Return empty position if this position is non-editable, but pos is editable
453 // FIXME: Move to the next non-editable region.
455 return VisiblePosition();
457 // Return the next position after pos that is in the same editable region as this position
458 return firstEditablePositionAfterPositionInRoot(pos.deepEquivalent(), highestRoot);
461 static Position canonicalizeCandidate(const Position& candidate)
463 if (candidate.isNull())
465 ASSERT(candidate.isCandidate());
466 Position upstream = candidate.upstream();
467 if (upstream.isCandidate())
472 Position VisiblePosition::canonicalPosition(const Position& passedPosition)
474 // The updateLayout call below can do so much that even the position passed
475 // in to us might get changed as a side effect. Specifically, there are code
476 // paths that pass selection endpoints, and updateLayout can change the selection.
477 Position position = passedPosition;
479 // FIXME (9535): Canonicalizing to the leftmost candidate means that if we're at a line wrap, we will
480 // ask renderers to paint downstream carets for other renderers.
481 // To fix this, we need to either a) add code to all paintCarets to pass the responsibility off to
482 // the appropriate renderer for VisiblePosition's like these, or b) canonicalize to the rightmost candidate
483 // unless the affinity is upstream.
484 if (position.isNull())
487 Node* node = position.containerNode();
489 ASSERT(position.document());
490 position.document()->updateLayoutIgnorePendingStylesheets();
492 Position candidate = position.upstream();
493 if (candidate.isCandidate())
495 candidate = position.downstream();
496 if (candidate.isCandidate())
499 // When neither upstream or downstream gets us to a candidate (upstream/downstream won't leave
500 // blocks or enter new ones), we search forward and backward until we find one.
501 Position next = canonicalizeCandidate(nextCandidate(position));
502 Position prev = canonicalizeCandidate(previousCandidate(position));
503 Node* nextNode = next.deprecatedNode();
504 Node* prevNode = prev.deprecatedNode();
506 // The new position must be in the same editable element. Enforce that first.
507 // Unless the descent is from a non-editable html element to an editable body.
508 if (node && node->hasTagName(htmlTag) && !node->rendererIsEditable() && node->document()->body() && node->document()->body()->rendererIsEditable())
509 return next.isNotNull() ? next : prev;
511 Node* editingRoot = editableRootForPosition(position);
513 // If the html element is editable, descending into its body will look like a descent
514 // from non-editable to editable content since rootEditableElement() always stops at the body.
515 if ((editingRoot && editingRoot->hasTagName(htmlTag)) || position.deprecatedNode()->isDocumentNode())
516 return next.isNotNull() ? next : prev;
518 bool prevIsInSameEditableElement = prevNode && editableRootForPosition(prev) == editingRoot;
519 bool nextIsInSameEditableElement = nextNode && editableRootForPosition(next) == editingRoot;
520 if (prevIsInSameEditableElement && !nextIsInSameEditableElement)
523 if (nextIsInSameEditableElement && !prevIsInSameEditableElement)
526 if (!nextIsInSameEditableElement && !prevIsInSameEditableElement)
529 // The new position should be in the same block flow element. Favor that.
530 Node* originalBlock = node ? node->enclosingBlockFlowElement() : 0;
531 bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) && nextNode != originalBlock;
532 bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) && prevNode != originalBlock;
533 if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock)
539 UChar32 VisiblePosition::characterAfter() const
541 // We canonicalize to the first of two equivalent candidates, but the second of the two candidates
542 // is the one that will be inside the text node containing the character after this visible position.
543 Position pos = m_deepPosition.downstream();
544 if (!pos.containerNode() || !pos.containerNode()->isTextNode())
546 switch (pos.anchorType()) {
547 case Position::PositionIsAfterChildren:
548 case Position::PositionIsAfterAnchor:
549 case Position::PositionIsBeforeAnchor:
550 case Position::PositionIsBeforeChildren:
552 case Position::PositionIsOffsetInAnchor:
555 unsigned offset = static_cast<unsigned>(pos.offsetInContainerNode());
556 Text* textNode = pos.containerText();
557 unsigned length = textNode->length();
558 if (offset >= length)
562 const UChar* characters = textNode->data().characters();
563 U16_NEXT(characters, offset, length, ch);
567 IntRect VisiblePosition::localCaretRect(RenderObject*& renderer) const
569 if (m_deepPosition.isNull()) {
573 Node* node = m_deepPosition.anchorNode();
575 renderer = node->renderer();
579 InlineBox* inlineBox;
581 getInlineBoxAndOffset(inlineBox, caretOffset);
584 renderer = inlineBox->renderer();
586 return renderer->localCaretRect(inlineBox, caretOffset);
589 IntRect VisiblePosition::absoluteCaretBounds() const
591 RenderObject* renderer;
592 IntRect localRect = localCaretRect(renderer);
593 if (localRect.isEmpty() || !renderer)
596 return renderer->localToAbsoluteQuad(FloatRect(localRect)).enclosingBoundingBox();
599 int VisiblePosition::lineDirectionPointForBlockDirectionNavigation() const
601 RenderObject* renderer;
602 IntRect localRect = localCaretRect(renderer);
603 if (localRect.isEmpty() || !renderer)
606 // This ignores transforms on purpose, for now. Vertical navigation is done
607 // without consulting transforms, so that 'up' in transformed text is 'up'
608 // relative to the text, not absolute 'up'.
609 FloatPoint caretPoint = renderer->localToAbsolute(localRect.location());
610 return renderer->containingBlock()->isHorizontalWritingMode() ? caretPoint.x() : caretPoint.y();
615 void VisiblePosition::debugPosition(const char* msg) const
618 fprintf(stderr, "Position [%s]: null\n", msg);
620 fprintf(stderr, "Position [%s]: %s, ", msg, m_deepPosition.deprecatedNode()->nodeName().utf8().data());
621 m_deepPosition.showAnchorTypeAndOffset();
625 void VisiblePosition::formatForDebugger(char* buffer, unsigned length) const
627 m_deepPosition.formatForDebugger(buffer, length);
630 void VisiblePosition::showTreeForThis() const
632 m_deepPosition.showTreeForThis();
637 PassRefPtr<Range> makeRange(const VisiblePosition &start, const VisiblePosition &end)
639 if (start.isNull() || end.isNull())
642 Position s = start.deepEquivalent().parentAnchoredEquivalent();
643 Position e = end.deepEquivalent().parentAnchoredEquivalent();
644 if (s.isNull() || e.isNull())
647 return Range::create(s.containerNode()->document(), s.containerNode(), s.offsetInContainerNode(), e.containerNode(), e.offsetInContainerNode());
650 VisiblePosition startVisiblePosition(const Range *r, EAffinity affinity)
652 return VisiblePosition(r->startPosition(), affinity);
655 VisiblePosition endVisiblePosition(const Range *r, EAffinity affinity)
657 return VisiblePosition(r->endPosition(), affinity);
660 bool setStart(Range *r, const VisiblePosition &visiblePosition)
664 Position p = visiblePosition.deepEquivalent().parentAnchoredEquivalent();
666 r->setStart(p.containerNode(), p.offsetInContainerNode(), code);
670 bool setEnd(Range *r, const VisiblePosition &visiblePosition)
674 Position p = visiblePosition.deepEquivalent().parentAnchoredEquivalent();
676 r->setEnd(p.containerNode(), p.offsetInContainerNode(), code);
680 Element* enclosingBlockFlowElement(const VisiblePosition &visiblePosition)
682 if (visiblePosition.isNull())
685 return visiblePosition.deepEquivalent().deprecatedNode()->enclosingBlockFlowElement();
688 bool isFirstVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node)
690 if (visiblePosition.isNull())
693 if (!visiblePosition.deepEquivalent().containerNode()->isDescendantOf(node))
696 VisiblePosition previous = visiblePosition.previous();
697 return previous.isNull() || !previous.deepEquivalent().deprecatedNode()->isDescendantOf(node);
700 bool isLastVisiblePositionInNode(const VisiblePosition &visiblePosition, const Node *node)
702 if (visiblePosition.isNull())
705 if (!visiblePosition.deepEquivalent().containerNode()->isDescendantOf(node))
708 VisiblePosition next = visiblePosition.next();
709 return next.isNull() || !next.deepEquivalent().deprecatedNode()->isDescendantOf(node);
712 } // namespace WebCore
716 void showTree(const WebCore::VisiblePosition* vpos)
719 vpos->showTreeForThis();
722 void showTree(const WebCore::VisiblePosition& vpos)
724 vpos.showTreeForThis();