Index: Source/core/editing/VisibleUnits.cpp |
diff --git a/Source/core/editing/VisibleUnits.cpp b/Source/core/editing/VisibleUnits.cpp |
index 97bb5e9ccdee5cb70cbc8a9cb41c4bf623bd3daa..b69f0bf5ca55a840e0f0e1147544868e26261adb 100644 |
--- a/Source/core/editing/VisibleUnits.cpp |
+++ b/Source/core/editing/VisibleUnits.cpp |
@@ -2494,6 +2494,335 @@ UChar32 characterBefore(const VisiblePosition& visiblePosition) |
return characterAfter(previousPositionOf(visiblePosition)); |
} |
+static Position leftVisuallyDistinctCandidate(const VisiblePosition& visiblePosition) |
+{ |
+ const Position deepPosition = visiblePosition.deepEquivalent(); |
+ Position p = deepPosition; |
+ if (p.isNull()) |
+ return Position(); |
+ |
+ Position downstreamStart = mostForwardCaretPosition(p); |
+ TextDirection primaryDirection = primaryDirectionOf(*p.anchorNode()); |
+ const TextAffinity affinity = visiblePosition.affinity(); |
+ |
+ while (true) { |
+ InlineBoxPosition boxPosition = computeInlineBoxPosition(p, affinity, primaryDirection); |
+ InlineBox* box = boxPosition.inlineBox; |
+ int offset = boxPosition.offsetInBox; |
+ if (!box) |
+ return primaryDirection == LTR ? previousVisuallyDistinctCandidate(deepPosition) : nextVisuallyDistinctCandidate(deepPosition); |
+ |
+ LayoutObject* layoutObject = &box->layoutObject(); |
+ |
+ while (true) { |
+ if ((layoutObject->isReplaced() || layoutObject->isBR()) && offset == box->caretRightmostOffset()) |
+ return box->isLeftToRightDirection() ? previousVisuallyDistinctCandidate(deepPosition) : nextVisuallyDistinctCandidate(deepPosition); |
+ |
+ if (!layoutObject->node()) { |
+ box = box->prevLeafChild(); |
+ if (!box) |
+ return primaryDirection == LTR ? previousVisuallyDistinctCandidate(deepPosition) : nextVisuallyDistinctCandidate(deepPosition); |
+ layoutObject = &box->layoutObject(); |
+ offset = box->caretRightmostOffset(); |
+ continue; |
+ } |
+ |
+ offset = box->isLeftToRightDirection() ? layoutObject->previousOffset(offset) : layoutObject->nextOffset(offset); |
+ |
+ int caretMinOffset = box->caretMinOffset(); |
+ int caretMaxOffset = box->caretMaxOffset(); |
+ |
+ if (offset > caretMinOffset && offset < caretMaxOffset) |
+ break; |
+ |
+ if (box->isLeftToRightDirection() ? offset < caretMinOffset : offset > caretMaxOffset) { |
+ // Overshot to the left. |
+ InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak(); |
+ if (!prevBox) { |
+ Position positionOnLeft = primaryDirection == LTR ? previousVisuallyDistinctCandidate(deepPosition) : nextVisuallyDistinctCandidate(deepPosition); |
+ if (positionOnLeft.isNull()) |
+ return Position(); |
+ |
+ InlineBox* boxOnLeft = computeInlineBoxPosition(positionOnLeft, affinity, primaryDirection).inlineBox; |
+ if (boxOnLeft && boxOnLeft->root() == box->root()) |
+ return Position(); |
+ return positionOnLeft; |
+ } |
+ |
+ // Reposition at the other logical position corresponding to our |
+ // edge's visual position and go for another round. |
+ box = prevBox; |
+ layoutObject = &box->layoutObject(); |
+ offset = prevBox->caretRightmostOffset(); |
+ continue; |
+ } |
+ |
+ ASSERT(offset == box->caretLeftmostOffset()); |
+ |
+ unsigned char level = box->bidiLevel(); |
+ InlineBox* prevBox = box->prevLeafChild(); |
+ |
+ if (box->direction() == primaryDirection) { |
+ if (!prevBox) { |
+ InlineBox* logicalStart = 0; |
+ if (primaryDirection == LTR ? box->root().getLogicalStartBoxWithNode(logicalStart) : box->root().getLogicalEndBoxWithNode(logicalStart)) { |
+ box = logicalStart; |
+ layoutObject = &box->layoutObject(); |
+ offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset(); |
+ } |
+ break; |
+ } |
+ if (prevBox->bidiLevel() >= level) |
+ break; |
+ |
+ level = prevBox->bidiLevel(); |
+ |
+ InlineBox* nextBox = box; |
+ do { |
+ nextBox = nextBox->nextLeafChild(); |
+ } while (nextBox && nextBox->bidiLevel() > level); |
+ |
+ if (nextBox && nextBox->bidiLevel() == level) |
+ break; |
+ |
+ box = prevBox; |
+ layoutObject = &box->layoutObject(); |
+ offset = box->caretRightmostOffset(); |
+ if (box->direction() == primaryDirection) |
+ break; |
+ continue; |
+ } |
+ |
+ while (prevBox && !prevBox->layoutObject().node()) |
+ prevBox = prevBox->prevLeafChild(); |
+ |
+ if (prevBox) { |
+ box = prevBox; |
+ layoutObject = &box->layoutObject(); |
+ offset = box->caretRightmostOffset(); |
+ if (box->bidiLevel() > level) { |
+ do { |
+ prevBox = prevBox->prevLeafChild(); |
+ } while (prevBox && prevBox->bidiLevel() > level); |
+ |
+ if (!prevBox || prevBox->bidiLevel() < level) |
+ continue; |
+ } |
+ } else { |
+ // Trailing edge of a secondary run. Set to the leading edge of the entire run. |
+ while (true) { |
+ while (InlineBox* nextBox = box->nextLeafChild()) { |
+ if (nextBox->bidiLevel() < level) |
+ break; |
+ box = nextBox; |
+ } |
+ if (box->bidiLevel() == level) |
+ break; |
+ level = box->bidiLevel(); |
+ while (InlineBox* prevBox = box->prevLeafChild()) { |
+ if (prevBox->bidiLevel() < level) |
+ break; |
+ box = prevBox; |
+ } |
+ if (box->bidiLevel() == level) |
+ break; |
+ level = box->bidiLevel(); |
+ } |
+ layoutObject = &box->layoutObject(); |
+ offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset(); |
+ } |
+ break; |
+ } |
+ |
+ p = Position::editingPositionOf(layoutObject->node(), offset); |
+ |
+ if ((isVisuallyEquivalentCandidate(p) && mostForwardCaretPosition(p) != downstreamStart) || p.atStartOfTree() || p.atEndOfTree()) |
+ return p; |
+ |
+ ASSERT(p != deepPosition); |
+ } |
+} |
+ |
+VisiblePosition leftPositionOf(const VisiblePosition& visiblePosition) |
+{ |
+ const Position pos = leftVisuallyDistinctCandidate(visiblePosition); |
+ // TODO(yosin) Why can't we move left from the last position in a tree? |
+ if (pos.atStartOfTree() || pos.atEndOfTree()) |
+ return VisiblePosition(); |
+ |
+ VisiblePosition left = createVisiblePosition(pos); |
+ ASSERT(left.deepEquivalent() != visiblePosition.deepEquivalent()); |
+ |
+ return directionOfEnclosingBlock(left.deepEquivalent()) == LTR ? honorEditingBoundaryAtOrBefore(left, visiblePosition.deepEquivalent()) : honorEditingBoundaryAtOrAfter(left, visiblePosition.deepEquivalent()); |
+} |
+ |
+static Position rightVisuallyDistinctCandidate(const VisiblePosition& visiblePosition) |
+{ |
+ const Position deepPosition = visiblePosition.deepEquivalent(); |
+ Position p = deepPosition; |
+ if (p.isNull()) |
+ return Position(); |
+ |
+ Position downstreamStart = mostForwardCaretPosition(p); |
+ TextDirection primaryDirection = primaryDirectionOf(*p.anchorNode()); |
+ const TextAffinity affinity = visiblePosition.affinity(); |
+ |
+ while (true) { |
+ InlineBoxPosition boxPosition = computeInlineBoxPosition(p, affinity, primaryDirection); |
+ InlineBox* box = boxPosition.inlineBox; |
+ int offset = boxPosition.offsetInBox; |
+ if (!box) |
+ return primaryDirection == LTR ? nextVisuallyDistinctCandidate(deepPosition) : previousVisuallyDistinctCandidate(deepPosition); |
+ |
+ LayoutObject* layoutObject = &box->layoutObject(); |
+ |
+ while (true) { |
+ if ((layoutObject->isReplaced() || layoutObject->isBR()) && offset == box->caretLeftmostOffset()) |
+ return box->isLeftToRightDirection() ? nextVisuallyDistinctCandidate(deepPosition) : previousVisuallyDistinctCandidate(deepPosition); |
+ |
+ if (!layoutObject->node()) { |
+ box = box->nextLeafChild(); |
+ if (!box) |
+ return primaryDirection == LTR ? nextVisuallyDistinctCandidate(deepPosition) : previousVisuallyDistinctCandidate(deepPosition); |
+ layoutObject = &box->layoutObject(); |
+ offset = box->caretLeftmostOffset(); |
+ continue; |
+ } |
+ |
+ offset = box->isLeftToRightDirection() ? layoutObject->nextOffset(offset) : layoutObject->previousOffset(offset); |
+ |
+ int caretMinOffset = box->caretMinOffset(); |
+ int caretMaxOffset = box->caretMaxOffset(); |
+ |
+ if (offset > caretMinOffset && offset < caretMaxOffset) |
+ break; |
+ |
+ if (box->isLeftToRightDirection() ? offset > caretMaxOffset : offset < caretMinOffset) { |
+ // Overshot to the right. |
+ InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak(); |
+ if (!nextBox) { |
+ Position positionOnRight = primaryDirection == LTR ? nextVisuallyDistinctCandidate(deepPosition) : previousVisuallyDistinctCandidate(deepPosition); |
+ if (positionOnRight.isNull()) |
+ return Position(); |
+ |
+ InlineBox* boxOnRight = computeInlineBoxPosition(positionOnRight, affinity, primaryDirection).inlineBox; |
+ if (boxOnRight && boxOnRight->root() == box->root()) |
+ return Position(); |
+ return positionOnRight; |
+ } |
+ |
+ // Reposition at the other logical position corresponding to our |
+ // edge's visual position and go for another round. |
+ box = nextBox; |
+ layoutObject = &box->layoutObject(); |
+ offset = nextBox->caretLeftmostOffset(); |
+ continue; |
+ } |
+ |
+ ASSERT(offset == box->caretRightmostOffset()); |
+ |
+ unsigned char level = box->bidiLevel(); |
+ InlineBox* nextBox = box->nextLeafChild(); |
+ |
+ if (box->direction() == primaryDirection) { |
+ if (!nextBox) { |
+ InlineBox* logicalEnd = 0; |
+ if (primaryDirection == LTR ? box->root().getLogicalEndBoxWithNode(logicalEnd) : box->root().getLogicalStartBoxWithNode(logicalEnd)) { |
+ box = logicalEnd; |
+ layoutObject = &box->layoutObject(); |
+ offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset(); |
+ } |
+ break; |
+ } |
+ |
+ if (nextBox->bidiLevel() >= level) |
+ break; |
+ |
+ level = nextBox->bidiLevel(); |
+ |
+ InlineBox* prevBox = box; |
+ do { |
+ prevBox = prevBox->prevLeafChild(); |
+ } while (prevBox && prevBox->bidiLevel() > level); |
+ |
+ // For example, abc FED 123 ^ CBA |
+ if (prevBox && prevBox->bidiLevel() == level) |
+ break; |
+ |
+ // For example, abc 123 ^ CBA or 123 ^ CBA abc |
+ box = nextBox; |
+ layoutObject = &box->layoutObject(); |
+ offset = box->caretLeftmostOffset(); |
+ if (box->direction() == primaryDirection) |
+ break; |
+ continue; |
+ } |
+ |
+ while (nextBox && !nextBox->layoutObject().node()) |
+ nextBox = nextBox->nextLeafChild(); |
+ |
+ if (nextBox) { |
+ box = nextBox; |
+ layoutObject = &box->layoutObject(); |
+ offset = box->caretLeftmostOffset(); |
+ |
+ if (box->bidiLevel() > level) { |
+ do { |
+ nextBox = nextBox->nextLeafChild(); |
+ } while (nextBox && nextBox->bidiLevel() > level); |
+ |
+ if (!nextBox || nextBox->bidiLevel() < level) |
+ continue; |
+ } |
+ } else { |
+ // Trailing edge of a secondary run. Set to the leading edge of |
+ // the entire run. |
+ while (true) { |
+ while (InlineBox* prevBox = box->prevLeafChild()) { |
+ if (prevBox->bidiLevel() < level) |
+ break; |
+ box = prevBox; |
+ } |
+ if (box->bidiLevel() == level) |
+ break; |
+ level = box->bidiLevel(); |
+ while (InlineBox* nextBox = box->nextLeafChild()) { |
+ if (nextBox->bidiLevel() < level) |
+ break; |
+ box = nextBox; |
+ } |
+ if (box->bidiLevel() == level) |
+ break; |
+ level = box->bidiLevel(); |
+ } |
+ layoutObject = &box->layoutObject(); |
+ offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset(); |
+ } |
+ break; |
+ } |
+ |
+ p = Position::editingPositionOf(layoutObject->node(), offset); |
+ |
+ if ((isVisuallyEquivalentCandidate(p) && mostForwardCaretPosition(p) != downstreamStart) || p.atStartOfTree() || p.atEndOfTree()) |
+ return p; |
+ |
+ ASSERT(p != deepPosition); |
+ } |
+} |
+ |
+VisiblePosition rightPositionOf(const VisiblePosition& visiblePosition) |
+{ |
+ const Position pos = rightVisuallyDistinctCandidate(visiblePosition); |
+ // TODO(yosin) Why can't we move left from the last position in a tree? |
+ if (pos.atStartOfTree() || pos.atEndOfTree()) |
+ return VisiblePosition(); |
+ |
+ VisiblePosition right = createVisiblePosition(pos); |
+ ASSERT(right.deepEquivalent() != visiblePosition.deepEquivalent()); |
+ |
+ return directionOfEnclosingBlock(right.deepEquivalent()) == LTR ? honorEditingBoundaryAtOrAfter(right, visiblePosition.deepEquivalent()) : honorEditingBoundaryAtOrBefore(right, visiblePosition.deepEquivalent()); |
+} |
+ |
VisiblePosition nextPositionOf(const VisiblePosition& visiblePosition, EditingBoundaryCrossingRule rule) |
{ |
VisiblePosition next(nextVisuallyDistinctCandidate(visiblePosition.deepEquivalent()), visiblePosition.affinity()); |