OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserv
ed. | 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserv
ed. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions | 5 * modification, are permitted provided that the following conditions |
6 * are met: | 6 * are met: |
7 * 1. Redistributions of source code must retain the above copyright | 7 * 1. Redistributions of source code must retain the above copyright |
8 * notice, this list of conditions and the following disclaimer. | 8 * notice, this list of conditions and the following disclaimer. |
9 * 2. Redistributions in binary form must reproduce the above copyright | 9 * 2. Redistributions in binary form must reproduce the above copyright |
10 * notice, this list of conditions and the following disclaimer in the | 10 * notice, this list of conditions and the following disclaimer in the |
(...skipping 144 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
155 { | 155 { |
156 return canonicalPosition(position); | 156 return canonicalPosition(position); |
157 } | 157 } |
158 | 158 |
159 PositionInComposedTree canonicalPositionOf(const PositionInComposedTree& positio
n) | 159 PositionInComposedTree canonicalPositionOf(const PositionInComposedTree& positio
n) |
160 { | 160 { |
161 return canonicalPosition(position); | 161 return canonicalPosition(position); |
162 } | 162 } |
163 | 163 |
164 template <typename Strategy> | 164 template <typename Strategy> |
165 static PositionWithAffinityTemplate<Strategy> honorEditingBoundaryAtOrBeforeAlgo
rithm(const PositionWithAffinityTemplate<Strategy>& pos, const PositionAlgorithm
<Strategy>& anchor) | 165 static PositionWithAffinityTemplate<Strategy> honorEditingBoundaryAtOrBefore(con
st PositionWithAffinityTemplate<Strategy>& pos, const PositionAlgorithm<Strategy
>& anchor) |
166 { | 166 { |
167 if (pos.isNull()) | 167 if (pos.isNull()) |
168 return pos; | 168 return pos; |
169 | 169 |
170 ContainerNode* highestRoot = highestEditableRoot(anchor); | 170 ContainerNode* highestRoot = highestEditableRoot(anchor); |
171 | 171 |
172 // Return empty position if |pos| is not somewhere inside the editable | 172 // Return empty position if |pos| is not somewhere inside the editable |
173 // region containing this position | 173 // region containing this position |
174 if (highestRoot && !pos.position().anchorNode()->isDescendantOf(highestRoot)
) | 174 if (highestRoot && !pos.position().anchorNode()->isDescendantOf(highestRoot)
) |
175 return PositionWithAffinityTemplate<Strategy>(); | 175 return PositionWithAffinityTemplate<Strategy>(); |
(...skipping 10 matching lines...) Expand all Loading... |
186 // editable. | 186 // editable. |
187 // TODO(yosin) Move to the previous non-editable region. | 187 // TODO(yosin) Move to the previous non-editable region. |
188 if (!highestRoot) | 188 if (!highestRoot) |
189 return PositionWithAffinityTemplate<Strategy>(); | 189 return PositionWithAffinityTemplate<Strategy>(); |
190 | 190 |
191 // Return the last position before |pos| that is in the same editable region | 191 // Return the last position before |pos| that is in the same editable region |
192 // as this position | 192 // as this position |
193 return lastEditablePositionBeforePositionInRoot(pos.position(), highestRoot)
; | 193 return lastEditablePositionBeforePositionInRoot(pos.position(), highestRoot)
; |
194 } | 194 } |
195 | 195 |
196 static PositionWithAffinity honorEditingBoundaryAtOrBeforeOf(const PositionWithA
ffinity& pos, const Position& anchor) | 196 template <typename Strategy> |
| 197 static VisiblePositionTemplate<Strategy> honorEditingBoundaryAtOrBefore(const Vi
siblePositionTemplate<Strategy>& pos, const PositionAlgorithm<Strategy>& anchor) |
197 { | 198 { |
198 return honorEditingBoundaryAtOrBeforeAlgorithm(pos, anchor); | 199 return createVisiblePosition(honorEditingBoundaryAtOrBefore(pos.toPositionWi
thAffinity(), anchor)); |
199 } | 200 } |
200 | 201 |
201 static PositionInComposedTreeWithAffinity honorEditingBoundaryAtOrBeforeOf(const
PositionInComposedTreeWithAffinity& pos, const PositionInComposedTree& anchor) | 202 template <typename Strategy> |
202 { | 203 static VisiblePositionTemplate<Strategy> honorEditingBoundaryAtOrAfter(const Vis
iblePositionTemplate<Strategy>& pos, const PositionAlgorithm<Strategy>& anchor) |
203 return honorEditingBoundaryAtOrBeforeAlgorithm(pos, anchor); | |
204 } | |
205 | |
206 static VisiblePosition honorEditingBoundaryAtOrBefore(const VisiblePosition& pos
, const Position& anchor) | |
207 { | |
208 return createVisiblePosition(honorEditingBoundaryAtOrBeforeOf(pos.toPosition
WithAffinity(), anchor)); | |
209 } | |
210 | |
211 static VisiblePosition honorEditingBoundaryAtOrAfter(const VisiblePosition& pos,
const Position& anchor) | |
212 { | 204 { |
213 if (pos.isNull()) | 205 if (pos.isNull()) |
214 return pos; | 206 return pos; |
215 | 207 |
216 ContainerNode* highestRoot = highestEditableRoot(anchor); | 208 ContainerNode* highestRoot = highestEditableRoot(anchor); |
217 | 209 |
218 // Return empty position if |pos| is not somewhere inside the editable | 210 // Return empty position if |pos| is not somewhere inside the editable |
219 // region // containing this position | 211 // region containing this position |
220 if (highestRoot && !pos.deepEquivalent().anchorNode()->isDescendantOf(highes
tRoot)) | 212 if (highestRoot && !pos.deepEquivalent().anchorNode()->isDescendantOf(highes
tRoot)) |
221 return VisiblePosition(); | 213 return VisiblePositionTemplate<Strategy>(); |
222 | 214 |
223 // Return |pos| itself if the two are from the very same editable region, or | 215 // Return |pos| itself if the two are from the very same editable region, or |
224 // both are non-editable | 216 // both are non-editable |
225 // TODO(yosin) In the non-editable case, just because the new position is | 217 // TODO(yosin) In the non-editable case, just because the new position is |
226 // non-editable doesn't mean movement to it is allowed. | 218 // non-editable doesn't mean movement to it is allowed. |
227 // |VisibleSelection::adjustForEditableContent()| has this problem too. | 219 // |VisibleSelection::adjustForEditableContent()| has this problem too. |
228 if (highestEditableRoot(pos.deepEquivalent()) == highestRoot) | 220 if (highestEditableRoot(pos.deepEquivalent()) == highestRoot) |
229 return pos; | 221 return pos; |
230 | 222 |
231 // Return empty position if this position is non-editable, but |pos| is | 223 // Return empty position if this position is non-editable, but |pos| is |
232 // editable | 224 // editable. |
233 // TODO(yosin) Move to the next non-editable region. | 225 // TODO(yosin) Move to the next non-editable region. |
234 if (!highestRoot) | 226 if (!highestRoot) |
235 return VisiblePosition(); | 227 return VisiblePositionTemplate<Strategy>(); |
236 | 228 |
237 // Return the next position after |pos| that is in the same editable region | 229 // Return the next position after |pos| that is in the same editable region |
238 // as this position | 230 // as this position |
239 return firstEditableVisiblePositionAfterPositionInRoot(pos.deepEquivalent(),
highestRoot); | 231 return firstEditableVisiblePositionAfterPositionInRoot(pos.deepEquivalent(),
highestRoot); |
240 } | 232 } |
241 | 233 |
242 static Node* previousLeafWithSameEditability(Node* node, EditableType editableTy
pe) | 234 static Node* previousLeafWithSameEditability(Node* node, EditableType editableTy
pe) |
243 { | 235 { |
244 bool editable = node->hasEditableStyle(editableType); | 236 bool editable = node->hasEditableStyle(editableType); |
245 node = previousAtomicLeafNode(*node); | 237 node = previousAtomicLeafNode(*node); |
(...skipping 707 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
953 // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail. | 945 // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail. |
954 PositionWithAffinityTemplate<Strategy> visPos = startPositionForLine(c, mode
); | 946 PositionWithAffinityTemplate<Strategy> visPos = startPositionForLine(c, mode
); |
955 | 947 |
956 if (mode == UseLogicalOrdering) { | 948 if (mode == UseLogicalOrdering) { |
957 if (ContainerNode* editableRoot = highestEditableRoot(c.position())) { | 949 if (ContainerNode* editableRoot = highestEditableRoot(c.position())) { |
958 if (!editableRoot->contains(visPos.position().computeContainerNode()
)) | 950 if (!editableRoot->contains(visPos.position().computeContainerNode()
)) |
959 return PositionWithAffinityTemplate<Strategy>(PositionAlgorithm<
Strategy>::firstPositionInNode(editableRoot)); | 951 return PositionWithAffinityTemplate<Strategy>(PositionAlgorithm<
Strategy>::firstPositionInNode(editableRoot)); |
960 } | 952 } |
961 } | 953 } |
962 | 954 |
963 return honorEditingBoundaryAtOrBeforeOf(visPos, c.position()); | 955 return honorEditingBoundaryAtOrBefore(visPos, c.position()); |
964 } | 956 } |
965 | 957 |
966 static PositionWithAffinity startOfLine(const PositionWithAffinity& currentPosit
ion) | 958 static PositionWithAffinity startOfLine(const PositionWithAffinity& currentPosit
ion) |
967 { | 959 { |
968 return startOfLine(currentPosition, UseInlineBoxOrdering); | 960 return startOfLine(currentPosition, UseInlineBoxOrdering); |
969 } | 961 } |
970 | 962 |
971 static PositionInComposedTreeWithAffinity startOfLine(const PositionInComposedTr
eeWithAffinity& currentPosition) | 963 static PositionInComposedTreeWithAffinity startOfLine(const PositionInComposedTr
eeWithAffinity& currentPosition) |
972 { | 964 { |
973 return startOfLine(currentPosition, UseInlineBoxOrdering); | 965 return startOfLine(currentPosition, UseInlineBoxOrdering); |
(...skipping 1603 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2577 UChar32 characterAfter(const VisiblePositionInComposedTree& visiblePosition) | 2569 UChar32 characterAfter(const VisiblePositionInComposedTree& visiblePosition) |
2578 { | 2570 { |
2579 return characterAfterAlgorithm<EditingInComposedTreeStrategy>(visiblePositio
n); | 2571 return characterAfterAlgorithm<EditingInComposedTreeStrategy>(visiblePositio
n); |
2580 } | 2572 } |
2581 | 2573 |
2582 UChar32 characterBefore(const VisiblePosition& visiblePosition) | 2574 UChar32 characterBefore(const VisiblePosition& visiblePosition) |
2583 { | 2575 { |
2584 return characterAfter(previousPositionOf(visiblePosition)); | 2576 return characterAfter(previousPositionOf(visiblePosition)); |
2585 } | 2577 } |
2586 | 2578 |
2587 static Position leftVisuallyDistinctCandidate(const VisiblePosition& visiblePosi
tion) | 2579 template <typename Strategy> |
| 2580 static PositionAlgorithm<Strategy> leftVisuallyDistinctCandidate(const VisiblePo
sitionTemplate<Strategy>& visiblePosition) |
2588 { | 2581 { |
2589 const Position deepPosition = visiblePosition.deepEquivalent(); | 2582 const PositionAlgorithm<Strategy> deepPosition = visiblePosition.deepEquival
ent(); |
2590 Position p = deepPosition; | 2583 PositionAlgorithm<Strategy> p = deepPosition; |
| 2584 |
2591 if (p.isNull()) | 2585 if (p.isNull()) |
2592 return Position(); | 2586 return PositionAlgorithm<Strategy>(); |
2593 | 2587 |
2594 Position downstreamStart = mostForwardCaretPosition(p); | 2588 const PositionAlgorithm<Strategy> downstreamStart = mostForwardCaretPosition
(p); |
2595 TextDirection primaryDirection = primaryDirectionOf(*p.anchorNode()); | 2589 TextDirection primaryDirection = primaryDirectionOf(*p.anchorNode()); |
2596 const TextAffinity affinity = visiblePosition.affinity(); | 2590 const TextAffinity affinity = visiblePosition.affinity(); |
2597 | 2591 |
2598 while (true) { | 2592 while (true) { |
2599 InlineBoxPosition boxPosition = computeInlineBoxPosition(p, affinity, pr
imaryDirection); | 2593 InlineBoxPosition boxPosition = computeInlineBoxPosition(p, affinity, pr
imaryDirection); |
2600 InlineBox* box = boxPosition.inlineBox; | 2594 InlineBox* box = boxPosition.inlineBox; |
2601 int offset = boxPosition.offsetInBox; | 2595 int offset = boxPosition.offsetInBox; |
2602 if (!box) | 2596 if (!box) |
2603 return primaryDirection == LTR ? previousVisuallyDistinctCandidate(d
eepPosition) : nextVisuallyDistinctCandidate(deepPosition); | 2597 return primaryDirection == LTR ? previousVisuallyDistinctCandidate(d
eepPosition) : nextVisuallyDistinctCandidate(deepPosition); |
2604 | 2598 |
(...skipping 17 matching lines...) Expand all Loading... |
2622 int caretMinOffset = box->caretMinOffset(); | 2616 int caretMinOffset = box->caretMinOffset(); |
2623 int caretMaxOffset = box->caretMaxOffset(); | 2617 int caretMaxOffset = box->caretMaxOffset(); |
2624 | 2618 |
2625 if (offset > caretMinOffset && offset < caretMaxOffset) | 2619 if (offset > caretMinOffset && offset < caretMaxOffset) |
2626 break; | 2620 break; |
2627 | 2621 |
2628 if (box->isLeftToRightDirection() ? offset < caretMinOffset : offset
> caretMaxOffset) { | 2622 if (box->isLeftToRightDirection() ? offset < caretMinOffset : offset
> caretMaxOffset) { |
2629 // Overshot to the left. | 2623 // Overshot to the left. |
2630 InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak(); | 2624 InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak(); |
2631 if (!prevBox) { | 2625 if (!prevBox) { |
2632 Position positionOnLeft = primaryDirection == LTR ? previous
VisuallyDistinctCandidate(deepPosition) : nextVisuallyDistinctCandidate(deepPosi
tion); | 2626 PositionAlgorithm<Strategy> positionOnLeft = primaryDirectio
n == LTR ? previousVisuallyDistinctCandidate(visiblePosition.deepEquivalent()) :
nextVisuallyDistinctCandidate(visiblePosition.deepEquivalent()); |
2633 if (positionOnLeft.isNull()) | 2627 if (positionOnLeft.isNull()) |
2634 return Position(); | 2628 return PositionAlgorithm<Strategy>(); |
2635 | 2629 |
2636 InlineBox* boxOnLeft = computeInlineBoxPosition(positionOnLe
ft, affinity, primaryDirection).inlineBox; | 2630 InlineBox* boxOnLeft = computeInlineBoxPosition(positionOnLe
ft, affinity, primaryDirection).inlineBox; |
2637 if (boxOnLeft && boxOnLeft->root() == box->root()) | 2631 if (boxOnLeft && boxOnLeft->root() == box->root()) |
2638 return Position(); | 2632 return PositionAlgorithm<Strategy>(); |
2639 return positionOnLeft; | 2633 return positionOnLeft; |
2640 } | 2634 } |
2641 | 2635 |
2642 // Reposition at the other logical position corresponding to our | 2636 // Reposition at the other logical position corresponding to our |
2643 // edge's visual position and go for another round. | 2637 // edge's visual position and go for another round. |
2644 box = prevBox; | 2638 box = prevBox; |
2645 layoutObject = &box->layoutObject(); | 2639 layoutObject = &box->layoutObject(); |
2646 offset = prevBox->caretRightmostOffset(); | 2640 offset = prevBox->caretRightmostOffset(); |
2647 continue; | 2641 continue; |
2648 } | 2642 } |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2692 offset = box->caretRightmostOffset(); | 2686 offset = box->caretRightmostOffset(); |
2693 if (box->bidiLevel() > level) { | 2687 if (box->bidiLevel() > level) { |
2694 do { | 2688 do { |
2695 prevBox = prevBox->prevLeafChild(); | 2689 prevBox = prevBox->prevLeafChild(); |
2696 } while (prevBox && prevBox->bidiLevel() > level); | 2690 } while (prevBox && prevBox->bidiLevel() > level); |
2697 | 2691 |
2698 if (!prevBox || prevBox->bidiLevel() < level) | 2692 if (!prevBox || prevBox->bidiLevel() < level) |
2699 continue; | 2693 continue; |
2700 } | 2694 } |
2701 } else { | 2695 } else { |
2702 // Trailing edge of a secondary run. Set to the leading edge of
the entire run. | 2696 // Trailing edge of a secondary run. Set to the leading edge of |
| 2697 // the entire run. |
2703 while (true) { | 2698 while (true) { |
2704 while (InlineBox* nextBox = box->nextLeafChild()) { | 2699 while (InlineBox* nextBox = box->nextLeafChild()) { |
2705 if (nextBox->bidiLevel() < level) | 2700 if (nextBox->bidiLevel() < level) |
2706 break; | 2701 break; |
2707 box = nextBox; | 2702 box = nextBox; |
2708 } | 2703 } |
2709 if (box->bidiLevel() == level) | 2704 if (box->bidiLevel() == level) |
2710 break; | 2705 break; |
2711 level = box->bidiLevel(); | 2706 level = box->bidiLevel(); |
2712 while (InlineBox* prevBox = box->prevLeafChild()) { | 2707 while (InlineBox* prevBox = box->prevLeafChild()) { |
2713 if (prevBox->bidiLevel() < level) | 2708 if (prevBox->bidiLevel() < level) |
2714 break; | 2709 break; |
2715 box = prevBox; | 2710 box = prevBox; |
2716 } | 2711 } |
2717 if (box->bidiLevel() == level) | 2712 if (box->bidiLevel() == level) |
2718 break; | 2713 break; |
2719 level = box->bidiLevel(); | 2714 level = box->bidiLevel(); |
2720 } | 2715 } |
2721 layoutObject = &box->layoutObject(); | 2716 layoutObject = &box->layoutObject(); |
2722 offset = primaryDirection == LTR ? box->caretMinOffset() : box->
caretMaxOffset(); | 2717 offset = primaryDirection == LTR ? box->caretMinOffset() : box->
caretMaxOffset(); |
2723 } | 2718 } |
2724 break; | 2719 break; |
2725 } | 2720 } |
2726 | 2721 |
2727 p = Position::editingPositionOf(layoutObject->node(), offset); | 2722 p = PositionAlgorithm<Strategy>::editingPositionOf(layoutObject->node(),
offset); |
2728 | 2723 |
2729 if ((isVisuallyEquivalentCandidate(p) && mostForwardCaretPosition(p) !=
downstreamStart) || p.atStartOfTree() || p.atEndOfTree()) | 2724 if ((isVisuallyEquivalentCandidate(p) && mostForwardCaretPosition(p) !=
downstreamStart) || p.atStartOfTree() || p.atEndOfTree()) |
2730 return p; | 2725 return p; |
2731 | 2726 |
2732 ASSERT(p != deepPosition); | 2727 ASSERT(p != deepPosition); |
2733 } | 2728 } |
2734 } | 2729 } |
2735 | 2730 |
2736 VisiblePosition leftPositionOf(const VisiblePosition& visiblePosition) | 2731 template <typename Strategy> |
| 2732 VisiblePositionTemplate<Strategy> leftPositionOfAlgorithm(const VisiblePositionT
emplate<Strategy>& visiblePosition) |
2737 { | 2733 { |
2738 const Position pos = leftVisuallyDistinctCandidate(visiblePosition); | 2734 const PositionAlgorithm<Strategy> pos = leftVisuallyDistinctCandidate(visibl
ePosition); |
2739 // TODO(yosin) Why can't we move left from the last position in a tree? | 2735 // TODO(yosin) Why can't we move left from the last position in a tree? |
2740 if (pos.atStartOfTree() || pos.atEndOfTree()) | 2736 if (pos.atStartOfTree() || pos.atEndOfTree()) |
2741 return VisiblePosition(); | 2737 return VisiblePositionTemplate<Strategy>(); |
2742 | 2738 |
2743 VisiblePosition left = createVisiblePosition(pos); | 2739 const VisiblePositionTemplate<Strategy> left = createVisiblePosition(pos); |
2744 ASSERT(left.deepEquivalent() != visiblePosition.deepEquivalent()); | 2740 ASSERT(left.deepEquivalent() != visiblePosition.deepEquivalent()); |
2745 | 2741 |
2746 return directionOfEnclosingBlock(left.deepEquivalent()) == LTR ? honorEditin
gBoundaryAtOrBefore(left, visiblePosition.deepEquivalent()) : honorEditingBounda
ryAtOrAfter(left, visiblePosition.deepEquivalent()); | 2742 return directionOfEnclosingBlock(left.deepEquivalent()) == LTR ? honorEditin
gBoundaryAtOrBefore(left, visiblePosition.deepEquivalent()) : honorEditingBounda
ryAtOrAfter(left, visiblePosition.deepEquivalent()); |
2747 } | 2743 } |
2748 | 2744 |
| 2745 VisiblePosition leftPositionOf(const VisiblePosition& visiblePosition) |
| 2746 { |
| 2747 return leftPositionOfAlgorithm<EditingStrategy>(visiblePosition); |
| 2748 } |
| 2749 |
| 2750 VisiblePositionInComposedTree leftPositionOf(const VisiblePositionInComposedTree
& visiblePosition) |
| 2751 { |
| 2752 return leftPositionOfAlgorithm<EditingInComposedTreeStrategy>(visiblePositio
n); |
| 2753 } |
| 2754 |
2749 static Position rightVisuallyDistinctCandidate(const VisiblePosition& visiblePos
ition) | 2755 static Position rightVisuallyDistinctCandidate(const VisiblePosition& visiblePos
ition) |
2750 { | 2756 { |
2751 const Position deepPosition = visiblePosition.deepEquivalent(); | 2757 const Position deepPosition = visiblePosition.deepEquivalent(); |
2752 Position p = deepPosition; | 2758 Position p = deepPosition; |
2753 if (p.isNull()) | 2759 if (p.isNull()) |
2754 return Position(); | 2760 return Position(); |
2755 | 2761 |
2756 Position downstreamStart = mostForwardCaretPosition(p); | 2762 Position downstreamStart = mostForwardCaretPosition(p); |
2757 TextDirection primaryDirection = primaryDirectionOf(*p.anchorNode()); | 2763 TextDirection primaryDirection = primaryDirectionOf(*p.anchorNode()); |
2758 const TextAffinity affinity = visiblePosition.affinity(); | 2764 const TextAffinity affinity = visiblePosition.affinity(); |
(...skipping 220 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2979 return honorEditingBoundaryAtOrBefore(prev, visiblePosition.deepEquivale
nt()); | 2985 return honorEditingBoundaryAtOrBefore(prev, visiblePosition.deepEquivale
nt()); |
2980 case CanSkipOverEditingBoundary: | 2986 case CanSkipOverEditingBoundary: |
2981 return skipToStartOfEditingBoundary(prev, visiblePosition.deepEquivalent
()); | 2987 return skipToStartOfEditingBoundary(prev, visiblePosition.deepEquivalent
()); |
2982 } | 2988 } |
2983 | 2989 |
2984 ASSERT_NOT_REACHED(); | 2990 ASSERT_NOT_REACHED(); |
2985 return honorEditingBoundaryAtOrBefore(prev, visiblePosition.deepEquivalent()
); | 2991 return honorEditingBoundaryAtOrBefore(prev, visiblePosition.deepEquivalent()
); |
2986 } | 2992 } |
2987 | 2993 |
2988 } // namespace blink | 2994 } // namespace blink |
OLD | NEW |