| 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());
|
|
|