Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(279)

Side by Side Diff: third_party/WebKit/Source/core/editing/VisibleUnits.cpp

Issue 1756763002: 2016-03-02T18:53:01 LayoutPosition Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 2016-04-25T19:02:18 Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
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 15 matching lines...) Expand all
26 #include "core/editing/VisibleUnits.h" 26 #include "core/editing/VisibleUnits.h"
27 27
28 #include "core/HTMLNames.h" 28 #include "core/HTMLNames.h"
29 #include "core/dom/Document.h" 29 #include "core/dom/Document.h"
30 #include "core/dom/Element.h" 30 #include "core/dom/Element.h"
31 #include "core/dom/FirstLetterPseudoElement.h" 31 #include "core/dom/FirstLetterPseudoElement.h"
32 #include "core/dom/NodeTraversal.h" 32 #include "core/dom/NodeTraversal.h"
33 #include "core/dom/Text.h" 33 #include "core/dom/Text.h"
34 #include "core/editing/EditingUtilities.h" 34 #include "core/editing/EditingUtilities.h"
35 #include "core/editing/FrameSelection.h" 35 #include "core/editing/FrameSelection.h"
36 #include "core/editing/LayoutPosition.h"
36 #include "core/editing/Position.h" 37 #include "core/editing/Position.h"
37 #include "core/editing/PositionIterator.h" 38 #include "core/editing/PositionIterator.h"
38 #include "core/editing/RenderedPosition.h" 39 #include "core/editing/RenderedPosition.h"
39 #include "core/editing/TextAffinity.h" 40 #include "core/editing/TextAffinity.h"
40 #include "core/editing/VisiblePosition.h" 41 #include "core/editing/VisiblePosition.h"
41 #include "core/editing/iterators/BackwardsCharacterIterator.h" 42 #include "core/editing/iterators/BackwardsCharacterIterator.h"
42 #include "core/editing/iterators/BackwardsTextBuffer.h" 43 #include "core/editing/iterators/BackwardsTextBuffer.h"
43 #include "core/editing/iterators/CharacterIterator.h" 44 #include "core/editing/iterators/CharacterIterator.h"
44 #include "core/editing/iterators/ForwardsTextBuffer.h" 45 #include "core/editing/iterators/ForwardsTextBuffer.h"
45 #include "core/editing/iterators/SimplifiedBackwardsTextIterator.h" 46 #include "core/editing/iterators/SimplifiedBackwardsTextIterator.h"
(...skipping 21 matching lines...) Expand all
67 #include "platform/heap/Handle.h" 68 #include "platform/heap/Handle.h"
68 #include "platform/text/TextBoundaries.h" 69 #include "platform/text/TextBoundaries.h"
69 70
70 namespace blink { 71 namespace blink {
71 72
72 template <typename PositionType> 73 template <typename PositionType>
73 static PositionType canonicalizeCandidate(const PositionType& candidate) 74 static PositionType canonicalizeCandidate(const PositionType& candidate)
74 { 75 {
75 if (candidate.isNull()) 76 if (candidate.isNull())
76 return PositionType(); 77 return PositionType();
77 DCHECK(isVisuallyEquivalentCandidate(candidate)); 78 ASSERT(isVisuallyEquivalentCandidate(candidate));
78 PositionType upstream = mostBackwardCaretPosition(candidate); 79 PositionType upstream = mostBackwardCaretPosition(candidate);
79 if (isVisuallyEquivalentCandidate(upstream)) 80 if (isVisuallyEquivalentCandidate(upstream))
80 return upstream; 81 return upstream;
81 return candidate; 82 return candidate;
82 } 83 }
83 84
84 template <typename PositionType> 85 template <typename PositionType>
85 static PositionType canonicalPosition(const PositionType& passedPosition) 86 static PositionType canonicalPosition(const PositionType& passedPosition)
86 { 87 {
87 // Sometimes updating selection positions can be extremely expensive and 88 // Sometimes updating selection positions can be extremely expensive and
88 // occur frequently. Often calling preventDefault on mousedown events can 89 // occur frequently. Often calling preventDefault on mousedown events can
89 // avoid doing unnecessary text selection work. http://crbug.com/472258. 90 // avoid doing unnecessary text selection work. http://crbug.com/472258.
90 TRACE_EVENT0("input", "VisibleUnits::canonicalPosition"); 91 TRACE_EVENT0("input", "VisibleUnits::canonicalPosition");
91 92
92 // The updateLayout call below can do so much that even the position passed 93 // The updateLayout call below can do so much that even the position passed
93 // in to us might get changed as a side effect. Specifically, there are code 94 // in to us might get changed as a side effect. Specifically, there are code
94 // paths that pass selection endpoints, and updateLayout can change the 95 // paths that pass selection endpoints, and updateLayout can change the
95 // selection. 96 // selection.
96 PositionType position = passedPosition; 97 PositionType position = passedPosition;
97 98
98 // FIXME (9535): Canonicalizing to the leftmost candidate means that if 99 // FIXME (9535): Canonicalizing to the leftmost candidate means that if
99 // we're at a line wrap, we will ask layoutObjects to paint downstream 100 // we're at a line wrap, we will ask layoutObjects to paint downstream
100 // carets for other layoutObjects. To fix this, we need to either a) add 101 // carets for other layoutObjects. To fix this, we need to either a) add
101 // code to all paintCarets to pass the responsibility off to the appropriate 102 // code to all paintCarets to pass the responsibility off to the appropriate
102 // layoutObject for VisiblePosition's like these, or b) canonicalize to the 103 // layoutObject for VisiblePosition's like these, or b) canonicalize to the
103 // rightmost candidate unless the affinity is upstream. 104 // rightmost candidate unless the affinity is upstream.
104 if (position.isNull()) 105 if (position.isNull())
105 return PositionType(); 106 return PositionType();
106 107
107 DCHECK(position.document()); 108 ASSERT(position.document());
108 position.document()->updateLayoutIgnorePendingStylesheets(); 109 position.document()->updateLayoutIgnorePendingStylesheets();
109 110
110 Node* node = position.computeContainerNode(); 111 Node* node = position.computeContainerNode();
111 112
112 PositionType candidate = mostBackwardCaretPosition(position); 113 PositionType candidate = mostBackwardCaretPosition(position);
113 if (isVisuallyEquivalentCandidate(candidate)) 114 if (isVisuallyEquivalentCandidate(candidate))
114 return candidate; 115 return candidate;
115 candidate = mostForwardCaretPosition(position); 116 candidate = mostForwardCaretPosition(position);
116 if (isVisuallyEquivalentCandidate(candidate)) 117 if (isVisuallyEquivalentCandidate(candidate))
117 return candidate; 118 return candidate;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
152 // The new position should be in the same block flow element. Favor that. 153 // The new position should be in the same block flow element. Favor that.
153 Element* originalBlock = node ? enclosingBlockFlowElement(*node) : 0; 154 Element* originalBlock = node ? enclosingBlockFlowElement(*node) : 0;
154 bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) & & nextNode != originalBlock; 155 bool nextIsOutsideOriginalBlock = !nextNode->isDescendantOf(originalBlock) & & nextNode != originalBlock;
155 bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) & & prevNode != originalBlock; 156 bool prevIsOutsideOriginalBlock = !prevNode->isDescendantOf(originalBlock) & & prevNode != originalBlock;
156 if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock) 157 if (nextIsOutsideOriginalBlock && !prevIsOutsideOriginalBlock)
157 return prev; 158 return prev;
158 159
159 return next; 160 return next;
160 } 161 }
161 162
163 template <typename Strategy>
164 struct BackwardMovement {
165 using PositionType = PositionTemplate<Strategy>;
166
167 static LayoutPosition advance(const LayoutPosition& position)
168 {
169 return previousPositionOf(position);
170 }
171
172 // TODO(yosin): |previousPositionOf()| should be implemented as
173 // |BackwardMovement::advance()|.
174 static PositionTemplate<Strategy> advance(const PositionTemplate<Strategy>& position)
175 {
176 ASSERT(position.isNotNull());
177 Node* const anchorNode = position.anchorNode();
178 switch (position.anchorType()) {
179 case PositionAnchorType::AfterAnchor:
180 if (anchorNode->isTextNode())
181 return advance(PositionTemplate<Strategy>(anchorNode, toText(anc horNode)->length()));
182 // fallthrough
183 case PositionAnchorType::AfterChildren:
184 if (Node* lastChild = Strategy::lastChild(*anchorNode))
185 return PositionTemplate<Strategy>::afterNode(lastChild);
186 return PositionTemplate<Strategy>::beforeNode(anchorNode);
187 case PositionAnchorType::BeforeAnchor: {
188 Node* const previous = Strategy::previous(*anchorNode);
189 if (!previous || previous->isDocumentNode())
190 return PositionTemplate<Strategy>();
191 if (previous == Strategy::parent(*anchorNode))
192 return PositionTemplate<Strategy>::beforeNode(previous);
193 return PositionTemplate<Strategy>::afterNode(previous);
194 }
195 case PositionAnchorType::BeforeChildren:
196 return PositionTemplate<Strategy>::beforeNode(anchorNode);
197 case PositionAnchorType::OffsetInAnchor: {
198 const int offsetInAnchor = position.offsetInContainerNode();
199 if (anchorNode->isTextNode()) {
200 if (offsetInAnchor > 0) {
201 // TODO(yosin): Should we check Unicode surrogate pair?
202 return PositionTemplate<Strategy>(anchorNode, offsetInAnchor - 1);
203 }
204 return advance(PositionTemplate<Strategy>::beforeNode(anchorNode ));
205 }
206 if (Node* child = Strategy::childAt(*anchorNode, offsetInAnchor))
207 return advance(PositionTemplate<Strategy>::beforeNode(child));
208 if (Node* lastChild = Strategy::lastChild(*anchorNode))
209 return advance(PositionTemplate<Strategy>::afterNode(lastChild)) ;
210 if (anchorNode->isDocumentNode())
211 return PositionTemplate<Strategy>();
212 return PositionTemplate<Strategy>::beforeNode(anchorNode);
213 }
214 }
215 NOTREACHED() << position.anchorType();
216 return PositionTemplate<Strategy>();
217 }
218 };
219
220 template <typename Strategy>
221 struct ForwardMovement {
222 using PositionType = PositionTemplate<Strategy>;
223
224 static LayoutPosition advance(const LayoutPosition& position)
225 {
226 return nextPositionOf(position);
227 }
228
229 // TODO(yosin): |nextPositionOf()| should be implemented as
230 // |ForwardMovement::advance()|.
231 static PositionTemplate<Strategy> advance(const PositionTemplate<Strategy>& position)
232 {
233 ASSERT(position.isNotNull());
234 Node* const anchorNode = position.anchorNode();
235 switch (position.anchorType()) {
236 case PositionAnchorType::AfterAnchor:
237 case PositionAnchorType::AfterChildren:
238 if (Node* nextNode = Strategy::nextSkippingChildren(*anchorNode))
239 return PositionTemplate<Strategy>::beforeNode(nextNode);
240 return PositionTemplate<Strategy>();
241 case PositionAnchorType::BeforeAnchor:
242 if (anchorNode->isTextNode())
243 return PositionTemplate<Strategy>(anchorNode, 0);
244 // fallthrough
245 case PositionAnchorType::BeforeChildren:
246 if (Node* nextNode = Strategy::next(*anchorNode))
247 return PositionTemplate<Strategy>::beforeNode(nextNode);
248 return PositionTemplate<Strategy>();
249 case PositionAnchorType::OffsetInAnchor: {
250 const int offsetInAnchor = position.offsetInContainerNode();
251 if (anchorNode->isTextNode()) {
252 if (offsetInAnchor < static_cast<int>(toText(anchorNode)->length ())) {
253 // TODO(yosin): Should we check Unicode surrogate pair?
254 return PositionTemplate<Strategy>(anchorNode, offsetInAnchor + 1);
255 }
256 return advance(PositionTemplate<Strategy>::afterNode(anchorNode) );
257 }
258 if (Node* child = Strategy::childAt(*anchorNode, offsetInAnchor)) {
259 if (child->isTextNode())
260 return advance(PositionTemplate<Strategy>(child, 0));
261 return advance(PositionTemplate<Strategy>::beforeNode(child));
262 }
263 if (Node* lastChild = Strategy::lastChild(*anchorNode))
264 return advance(PositionTemplate<Strategy>::afterNode(lastChild)) ;
265 if (anchorNode->isDocumentNode())
266 return PositionTemplate<Strategy>();
267 return PositionTemplate<Strategy>::afterNode(anchorNode);
268 }
269 }
270 NOTREACHED() << position.anchorType();
271 return PositionTemplate<Strategy>();
272 }
273 };
274
275 // |Direction| is specified tree traversal direction. There are
276 // - |BackwardMovement<Strategy>|
277 // - |ForwardMovement<Strategy>|
278 // for backward/forward with DOM tree/flat tree traversal.
279 //
280 // |Rule| corresponds to |enum EditingBoundaryCrossingRule|.
281 // There are:
282 // - |CanCrossEditingBoundaryRule|,
283 // - |CannotCrossEditingBoundaryRule|
284 // - |CanSkipOverEditingBoundary|
285 template <typename Direction, typename Rule>
286 class CaretPositionFinder final {
287 STATIC_ONLY(CaretPositionFinder);
288
289 public:
290 using PositionType = typename Direction::PositionType;
291
292 static LayoutPosition find(const PositionType&);
293
294 private:
295 static LayoutPosition advance(const LayoutPosition& position)
296 {
297 return Direction::advance(position);
298 }
299
300 static PositionType advance(const PositionType& position)
301 {
302 return Direction::advance(position);
303 }
304 static LayoutPosition findStart(const PositionType&);
305 static LayoutPosition locate(const LayoutPosition&);
306 };
307
308 template <typename Direction, typename Rule>
309 LayoutPosition CaretPositionFinder<Direction, Rule>::find(const PositionType& po sition)
310 {
311 DCHECK(position.isNotNull());
312 const LayoutPosition& start = findStart(position);
313 if (start.isNull())
314 return LayoutPosition();
315 LayoutPosition candidate = locate(start);
316 if (candidate.isNull())
317 return LayoutPosition();
318 Rule rule(candidate);
319 for (LayoutPosition runner = advance(candidate); runner.isNotNull(); runner = advance(runner)) {
320 if (!runner.canBePosition())
321 continue;
322 if (!rule.satisfies(runner))
323 return candidate;
324 if (!candidate.isCaretEquivalent(runner))
325 return candidate;
326 candidate = runner;
327 }
328 return candidate;
329 }
330
331 template <typename Direction, typename Rule>
332 LayoutPosition CaretPositionFinder<Direction, Rule>::findStart(const PositionTyp e& position)
333 {
334 Rule rule(position);
335 for (PositionType runner = position; runner.isNotNull(); runner = advance(ru nner)) {
336 const LayoutPosition& layoutPosition = LayoutPosition::create(runner);
337 if (!layoutPosition.canBePosition())
338 continue;
339 if (!rule.satisfies(runner))
340 return LayoutPosition();
341 if (layoutPosition.isNotNull())
342 return layoutPosition;
343 }
344 return LayoutPosition();
345 }
346
347 template <typename Direction, typename Rule>
348 LayoutPosition CaretPositionFinder<Direction, Rule>::locate(const LayoutPosition & position)
349 {
350 DCHECK(position.isNotNull());
351 Rule rule(position);
352 for (LayoutPosition runner = position; runner.isNotNull(); runner = advance( runner)) {
353 if (!runner.canBePosition())
354 continue;
355 if (!rule.satisfies(runner))
356 return LayoutPosition();
357 if (runner.canPlaceCaret())
358 return runner;
359 }
360 return LayoutPosition();
361 }
362
363 template <typename Strategy>
364 class CannotCrossEditingBoundaryRule final {
365 WTF_MAKE_NONCOPYABLE(CannotCrossEditingBoundaryRule);
366 STACK_ALLOCATED();
367
368 public:
369 explicit CannotCrossEditingBoundaryRule(const LayoutPosition& position)
370 : CannotCrossEditingBoundaryRule(position.toPosition(PositionTemplate<St rategy>()))
371 {
372 }
373
374 explicit CannotCrossEditingBoundaryRule(const PositionTemplate<Strategy>& po sition)
375 : m_rootEditableElement(rootEditableElementOf(position))
376 {
377 }
378
379 bool satisfies(const PositionTemplate<Strategy>& position) const
380 {
381 return m_rootEditableElement == rootEditableElementOf(position);
382 }
383
384 bool satisfies(const LayoutPosition& position) const
385 {
386 return satisfies(position.toPosition(PositionTemplate<Strategy>()));
387 }
388
389 private:
390 Element* const m_rootEditableElement;
391 };
392
393 template <typename Strategy>
394 static PositionTemplate<Strategy> caretPositionOfTemplate(const PositionTemplate <Strategy>& position)
395 {
396 if (position.isNull())
397 return PositionTemplate<Strategy>();
398 position.document()->updateLayoutIgnorePendingStylesheets();
399 const auto& backwardCandidate = CaretPositionFinder<BackwardMovement<Strateg y>, CannotCrossEditingBoundaryRule<Strategy>>::find(position);
400 if (backwardCandidate.isNotNull())
401 return backwardCandidate.toPosition(PositionTemplate<Strategy>());
402 const auto& forwardCandidate = CaretPositionFinder<ForwardMovement<Strategy> , CannotCrossEditingBoundaryRule<Strategy>>::find(position);
403 // |forwardCandidate| can be null if |position| in uneditable and parent
404 // is editable, e.g.
405 // <div contentEditable><span contentEditable=false>|</span></div>
406 return forwardCandidate.toPosition(PositionTemplate<Strategy>());
407 }
408
409 Position caretPositionOf(const Position& position)
410 {
411 return caretPositionOfTemplate<EditingStrategy>(position);
412 }
413
414 PositionInFlatTree caretPositionOf(const PositionInFlatTree& position)
415 {
416 return caretPositionOfTemplate<EditingInFlatTreeStrategy>(position);
417 }
418
162 Position canonicalPositionOf(const Position& position) 419 Position canonicalPositionOf(const Position& position)
163 { 420 {
164 return canonicalPosition(position); 421 #if 0
422 const auto& expected = canonicalPosition(position);
423 #endif
424 const auto& actual = caretPositionOf(position);
425 return actual;
165 } 426 }
166 427
167 PositionInFlatTree canonicalPositionOf(const PositionInFlatTree& position) 428 PositionInFlatTree canonicalPositionOf(const PositionInFlatTree& position)
168 { 429 {
169 return canonicalPosition(position); 430 #if 0
170 } 431 const auto& expected = canonicalPosition(position);
171 432 #endif
172 template <typename Strategy> 433 const auto& actual = caretPositionOf(position);
434 return actual;
435 }
436
437 template <typename Strategy>
173 static PositionWithAffinityTemplate<Strategy> honorEditingBoundaryAtOrBefore(con st PositionWithAffinityTemplate<Strategy>& pos, const PositionTemplate<Strategy> & anchor) 438 static PositionWithAffinityTemplate<Strategy> honorEditingBoundaryAtOrBefore(con st PositionWithAffinityTemplate<Strategy>& pos, const PositionTemplate<Strategy> & anchor)
174 { 439 {
175 if (pos.isNull()) 440 if (pos.isNull())
176 return pos; 441 return pos;
177 442
178 ContainerNode* highestRoot = highestEditableRoot(anchor); 443 ContainerNode* highestRoot = highestEditableRoot(anchor);
179 444
180 // Return empty position if |pos| is not somewhere inside the editable 445 // Return empty position if |pos| is not somewhere inside the editable
181 // region containing this position 446 // region containing this position
182 if (highestRoot && !pos.position().anchorNode()->isDescendantOf(highestRoot) ) 447 if (highestRoot && !pos.position().anchorNode()->isDescendantOf(highestRoot) )
(...skipping 536 matching lines...) Expand 10 before | Expand all | Expand 10 after
719 next = 0; 984 next = 0;
720 } 985 }
721 it.advance(); 986 it.advance();
722 } 987 }
723 if (needMoreContext) { 988 if (needMoreContext) {
724 // The last search returned the beginning of the buffer and asked for 989 // The last search returned the beginning of the buffer and asked for
725 // more context, but there is no earlier text. Force a search with 990 // more context, but there is no earlier text. Force a search with
726 // what's available. 991 // what's available.
727 // TODO(xiaochengh): Do we have to search the whole string? 992 // TODO(xiaochengh): Do we have to search the whole string?
728 next = searchFunction(string.data(), string.size(), string.size() - suff ixLength, DontHaveMoreContext, needMoreContext); 993 next = searchFunction(string.data(), string.size(), string.size() - suff ixLength, DontHaveMoreContext, needMoreContext);
729 DCHECK(!needMoreContext); 994 ASSERT(!needMoreContext);
730 } 995 }
731 996
732 if (!next) 997 if (!next)
733 return createVisiblePosition(it.atEnd() ? it.startPosition() : pos); 998 return createVisiblePosition(it.atEnd() ? it.startPosition() : pos);
734 999
735 Node* node = it.startContainer(); 1000 Node* node = it.startContainer();
736 int boundaryOffset = remainingLength + next; 1001 int boundaryOffset = remainingLength + next;
737 if (node->isTextNode() && boundaryOffset <= node->maxCharacterOffset()) { 1002 if (node->isTextNode() && boundaryOffset <= node->maxCharacterOffset()) {
738 // The next variable contains a usable index into a text node 1003 // The next variable contains a usable index into a text node
739 return createVisiblePosition(PositionTemplate<Strategy>(node, boundaryOf fset)); 1004 return createVisiblePosition(PositionTemplate<Strategy>(node, boundaryOf fset));
(...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after
813 next = string.size(); 1078 next = string.size();
814 } 1079 }
815 it.advance(); 1080 it.advance();
816 } 1081 }
817 if (needMoreContext) { 1082 if (needMoreContext) {
818 // The last search returned the end of the buffer and asked for more 1083 // The last search returned the end of the buffer and asked for more
819 // context, but there is no further text. Force a search with what's 1084 // context, but there is no further text. Force a search with what's
820 // available. 1085 // available.
821 // TODO(xiaochengh): Do we still have to search the whole string? 1086 // TODO(xiaochengh): Do we still have to search the whole string?
822 next = searchFunction(string.data(), string.size(), prefixLength, DontHa veMoreContext, needMoreContext); 1087 next = searchFunction(string.data(), string.size(), prefixLength, DontHa veMoreContext, needMoreContext);
823 DCHECK(!needMoreContext); 1088 ASSERT(!needMoreContext);
824 } 1089 }
825 1090
826 if (it.atEnd() && next == string.size()) { 1091 if (it.atEnd() && next == string.size()) {
827 pos = it.startPositionInCurrentContainer(); 1092 pos = it.startPositionInCurrentContainer();
828 } else if (next != invalidOffset && next != prefixLength) { 1093 } else if (next != invalidOffset && next != prefixLength) {
829 // TODO(dglazkov): The use of updateLayoutIgnorePendingStylesheets needs to be audited. 1094 // TODO(dglazkov): The use of updateLayoutIgnorePendingStylesheets needs to be audited.
830 // see http://crbug.com/590369 for more details. 1095 // see http://crbug.com/590369 for more details.
831 searchStart.document()->updateLayoutIgnorePendingStylesheets(); 1096 searchStart.document()->updateLayoutIgnorePendingStylesheets();
832 // Use the character iterator to translate the next value into a DOM 1097 // Use the character iterator to translate the next value into a DOM
833 // position. 1098 // position.
(...skipping 15 matching lines...) Expand all
849 1114
850 // generate VisiblePosition, use TextAffinity::Upstream affinity if possible 1115 // generate VisiblePosition, use TextAffinity::Upstream affinity if possible
851 return createVisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE); 1116 return createVisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE);
852 } 1117 }
853 1118
854 // --------- 1119 // ---------
855 1120
856 static unsigned startWordBoundary(const UChar* characters, unsigned length, unsi gned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMor eContext) 1121 static unsigned startWordBoundary(const UChar* characters, unsigned length, unsi gned offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMor eContext)
857 { 1122 {
858 TRACE_EVENT0("blink", "startWordBoundary"); 1123 TRACE_EVENT0("blink", "startWordBoundary");
859 DCHECK(offset); 1124 ASSERT(offset);
860 if (mayHaveMoreContext && !startOfLastWordBoundaryContext(characters, offset )) { 1125 if (mayHaveMoreContext && !startOfLastWordBoundaryContext(characters, offset )) {
861 needMoreContext = true; 1126 needMoreContext = true;
862 return 0; 1127 return 0;
863 } 1128 }
864 needMoreContext = false; 1129 needMoreContext = false;
865 int start, end; 1130 int start, end;
866 U16_BACK_1(characters, 0, offset); 1131 U16_BACK_1(characters, 0, offset);
867 findWordBoundary(characters, length, offset, &start, &end); 1132 findWordBoundary(characters, length, offset, &start, &end);
868 return start; 1133 return start;
869 } 1134 }
(...skipping 21 matching lines...) Expand all
891 return startOfWordAlgorithm<EditingStrategy>(c, side); 1156 return startOfWordAlgorithm<EditingStrategy>(c, side);
892 } 1157 }
893 1158
894 VisiblePositionInFlatTree startOfWord(const VisiblePositionInFlatTree& c, EWordS ide side) 1159 VisiblePositionInFlatTree startOfWord(const VisiblePositionInFlatTree& c, EWordS ide side)
895 { 1160 {
896 return startOfWordAlgorithm<EditingInFlatTreeStrategy>(c, side); 1161 return startOfWordAlgorithm<EditingInFlatTreeStrategy>(c, side);
897 } 1162 }
898 1163
899 static unsigned endWordBoundary(const UChar* characters, unsigned length, unsign ed offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreC ontext) 1164 static unsigned endWordBoundary(const UChar* characters, unsigned length, unsign ed offset, BoundarySearchContextAvailability mayHaveMoreContext, bool& needMoreC ontext)
900 { 1165 {
901 DCHECK_LE(offset, length); 1166 ASSERT(offset <= length);
902 if (mayHaveMoreContext && endOfFirstWordBoundaryContext(characters + offset, length - offset) == static_cast<int>(length - offset)) { 1167 if (mayHaveMoreContext && endOfFirstWordBoundaryContext(characters + offset, length - offset) == static_cast<int>(length - offset)) {
903 needMoreContext = true; 1168 needMoreContext = true;
904 return length; 1169 return length;
905 } 1170 }
906 needMoreContext = false; 1171 needMoreContext = false;
907 return findWordEndBoundary(characters, length, offset); 1172 return findWordEndBoundary(characters, length, offset);
908 } 1173 }
909 1174
910 template <typename Strategy> 1175 template <typename Strategy>
911 static VisiblePositionTemplate<Strategy> endOfWordAlgorithm(const VisiblePositio nTemplate<Strategy>& c, EWordSide side) 1176 static VisiblePositionTemplate<Strategy> endOfWordAlgorithm(const VisiblePositio nTemplate<Strategy>& c, EWordSide side)
(...skipping 367 matching lines...) Expand 10 before | Expand all | Expand 10 after
1279 return isLogicalEndOfLineAlgorithm<EditingStrategy>(p); 1544 return isLogicalEndOfLineAlgorithm<EditingStrategy>(p);
1280 } 1545 }
1281 1546
1282 bool isLogicalEndOfLine(const VisiblePositionInFlatTree& p) 1547 bool isLogicalEndOfLine(const VisiblePositionInFlatTree& p)
1283 { 1548 {
1284 return isLogicalEndOfLineAlgorithm<EditingInFlatTreeStrategy>(p); 1549 return isLogicalEndOfLineAlgorithm<EditingInFlatTreeStrategy>(p);
1285 } 1550 }
1286 1551
1287 static inline LayoutPoint absoluteLineDirectionPointToLocalPointInBlock(RootInli neBox* root, LayoutUnit lineDirectionPoint) 1552 static inline LayoutPoint absoluteLineDirectionPointToLocalPointInBlock(RootInli neBox* root, LayoutUnit lineDirectionPoint)
1288 { 1553 {
1289 DCHECK(root); 1554 ASSERT(root);
1290 LineLayoutBlockFlow containingBlock = root->block(); 1555 LineLayoutBlockFlow containingBlock = root->block();
1291 FloatPoint absoluteBlockPoint = containingBlock.localToAbsolute(FloatPoint() ); 1556 FloatPoint absoluteBlockPoint = containingBlock.localToAbsolute(FloatPoint() );
1292 if (containingBlock.hasOverflowClip()) 1557 if (containingBlock.hasOverflowClip())
1293 absoluteBlockPoint -= FloatSize(containingBlock.scrolledContentOffset()) ; 1558 absoluteBlockPoint -= FloatSize(containingBlock.scrolledContentOffset()) ;
1294 1559
1295 if (root->block().isHorizontalWritingMode()) 1560 if (root->block().isHorizontalWritingMode())
1296 return LayoutPoint(LayoutUnit(lineDirectionPoint - absoluteBlockPoint.x( )), root->blockDirectionPointInLine()); 1561 return LayoutPoint(LayoutUnit(lineDirectionPoint - absoluteBlockPoint.x( )), root->blockDirectionPointInLine());
1297 1562
1298 return LayoutPoint(root->blockDirectionPointInLine(), LayoutUnit(lineDirecti onPoint - absoluteBlockPoint.y())); 1563 return LayoutPoint(root->blockDirectionPointInLine(), LayoutUnit(lineDirecti onPoint - absoluteBlockPoint.y()));
1299 } 1564 }
(...skipping 913 matching lines...) Expand 10 before | Expand all | Expand 10 after
2213 // appeared in layout tree. 2478 // appeared in layout tree.
2214 // 2479 //
2215 // When |Text| node contains only first-letter characters and whitespaces, e.g. 2480 // When |Text| node contains only first-letter characters and whitespaces, e.g.
2216 // "B\n", associated |LayoutTextFragment| is first-letter part instead of 2481 // "B\n", associated |LayoutTextFragment| is first-letter part instead of
2217 // remaining part. 2482 // remaining part.
2218 // 2483 //
2219 // Punctuation characters are considered as first-letter. For "(1)ab", 2484 // Punctuation characters are considered as first-letter. For "(1)ab",
2220 // "(1)" are first-letter part and "ab" are remaining part. 2485 // "(1)" are first-letter part and "ab" are remaining part.
2221 LayoutObject* associatedLayoutObjectOf(const Node& node, int offsetInNode) 2486 LayoutObject* associatedLayoutObjectOf(const Node& node, int offsetInNode)
2222 { 2487 {
2223 DCHECK_GE(offsetInNode, 0); 2488 ASSERT(offsetInNode >= 0);
2224 LayoutObject* layoutObject = node.layoutObject(); 2489 LayoutObject* layoutObject = node.layoutObject();
2225 if (!node.isTextNode() || !layoutObject || !toLayoutText(layoutObject)->isTe xtFragment()) 2490 if (!node.isTextNode() || !layoutObject || !toLayoutText(layoutObject)->isTe xtFragment())
2226 return layoutObject; 2491 return layoutObject;
2227 LayoutTextFragment* layoutTextFragment = toLayoutTextFragment(layoutObject); 2492 LayoutTextFragment* layoutTextFragment = toLayoutTextFragment(layoutObject);
2228 if (!layoutTextFragment->isRemainingTextLayoutObject()) { 2493 if (!layoutTextFragment->isRemainingTextLayoutObject()) {
2229 DCHECK_LE(static_cast<unsigned>(offsetInNode), layoutTextFragment->start () + layoutTextFragment->fragmentLength()); 2494 ASSERT(static_cast<unsigned>(offsetInNode) <= layoutTextFragment->start( ) + layoutTextFragment->fragmentLength());
2230 return layoutTextFragment; 2495 return layoutTextFragment;
2231 } 2496 }
2232 if (layoutTextFragment->fragmentLength() && static_cast<unsigned>(offsetInNo de) >= layoutTextFragment->start()) 2497 if (layoutTextFragment->fragmentLength() && static_cast<unsigned>(offsetInNo de) >= layoutTextFragment->start())
2233 return layoutObject; 2498 return layoutObject;
2234 LayoutObject* firstLetterLayoutObject = layoutTextFragment->firstLetterPseud oElement()->layoutObject(); 2499 LayoutObject* firstLetterLayoutObject = layoutTextFragment->firstLetterPseud oElement()->layoutObject();
2235 // TODO(yosin): We're not sure when |firstLetterLayoutObject| has 2500 // TODO(yosin): We're not sure when |firstLetterLayoutObject| has
2236 // multiple child layout object. 2501 // multiple child layout object.
2237 DCHECK_EQ(firstLetterLayoutObject->slowFirstChild(), firstLetterLayoutObject ->slowLastChild()); 2502 ASSERT(firstLetterLayoutObject->slowFirstChild() == firstLetterLayoutObject- >slowLastChild());
2238 return firstLetterLayoutObject->slowFirstChild(); 2503 return firstLetterLayoutObject->slowFirstChild();
2239 } 2504 }
2240 2505
2241 int caretMinOffset(const Node* node) 2506 int caretMinOffset(const Node* node)
2242 { 2507 {
2243 LayoutObject* layoutObject = associatedLayoutObjectOf(*node, 0); 2508 LayoutObject* layoutObject = associatedLayoutObjectOf(*node, 0);
2244 return layoutObject ? layoutObject->caretMinOffset() : 0; 2509 return layoutObject ? layoutObject->caretMinOffset() : 0;
2245 } 2510 }
2246 2511
2247 int caretMaxOffset(const Node* n) 2512 int caretMaxOffset(const Node* n)
(...skipping 174 matching lines...) Expand 10 before | Expand all | Expand 10 after
2422 2687
2423 // return current position if it is in laid out text 2688 // return current position if it is in laid out text
2424 if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox() ) { 2689 if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox() ) {
2425 LayoutText* const textLayoutObject = toLayoutText(layoutObject); 2690 LayoutText* const textLayoutObject = toLayoutText(layoutObject);
2426 const unsigned textStartOffset = textLayoutObject->textStartOffset() ; 2691 const unsigned textStartOffset = textLayoutObject->textStartOffset() ;
2427 if (currentNode != startNode) { 2692 if (currentNode != startNode) {
2428 // This assertion fires in layout tests in the case-transform.ht ml test because 2693 // This assertion fires in layout tests in the case-transform.ht ml test because
2429 // of a mix-up between offsets in the text in the DOM tree with text in the 2694 // of a mix-up between offsets in the text in the DOM tree with text in the
2430 // layout tree which can have a different length due to case tra nsformation. 2695 // layout tree which can have a different length due to case tra nsformation.
2431 // Until we resolve that, disable this so we can run the layout tests! 2696 // Until we resolve that, disable this so we can run the layout tests!
2432 // DCHECK_GE(currentOffset, layoutObject->caretMaxOffset()); 2697 // ASSERT(currentOffset >= layoutObject->caretMaxOffset());
2433 return PositionTemplate<Strategy>(currentNode, layoutObject->car etMaxOffset() + textStartOffset); 2698 return PositionTemplate<Strategy>(currentNode, layoutObject->car etMaxOffset() + textStartOffset);
2434 } 2699 }
2435 2700
2436 // Map offset in DOM node to offset in InlineBox. 2701 // Map offset in DOM node to offset in InlineBox.
2437 DCHECK_GE(currentPos.offsetInLeafNode(), static_cast<int>(textStartO ffset)); 2702 ASSERT(currentPos.offsetInLeafNode() >= static_cast<int>(textStartOf fset));
2438 const unsigned textOffset = currentPos.offsetInLeafNode() - textStar tOffset; 2703 const unsigned textOffset = currentPos.offsetInLeafNode() - textStar tOffset;
2439 InlineTextBox* lastTextBox = textLayoutObject->lastTextBox(); 2704 InlineTextBox* lastTextBox = textLayoutObject->lastTextBox();
2440 for (InlineTextBox* box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox()) { 2705 for (InlineTextBox* box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox()) {
2441 if (textOffset == box->start()) { 2706 if (textOffset == box->start()) {
2442 if (textLayoutObject->isTextFragment() && toLayoutTextFragme nt(layoutObject)->isRemainingTextLayoutObject()) { 2707 if (textLayoutObject->isTextFragment() && toLayoutTextFragme nt(layoutObject)->isRemainingTextLayoutObject()) {
2443 // |currentPos| is at start of remaining text of 2708 // |currentPos| is at start of remaining text of
2444 // |Text| node with :first-letter. 2709 // |Text| node with :first-letter.
2445 DCHECK_GE(currentPos.offsetInLeafNode(), 1); 2710 ASSERT(currentPos.offsetInLeafNode() >= 1);
2446 LayoutObject* firstLetterLayoutObject = toLayoutTextFrag ment(layoutObject)->firstLetterPseudoElement()->layoutObject(); 2711 LayoutObject* firstLetterLayoutObject = toLayoutTextFrag ment(layoutObject)->firstLetterPseudoElement()->layoutObject();
2447 if (firstLetterLayoutObject && firstLetterLayoutObject-> style()->visibility() == VISIBLE) 2712 if (firstLetterLayoutObject && firstLetterLayoutObject-> style()->visibility() == VISIBLE)
2448 return currentPos.computePosition(); 2713 return currentPos.computePosition();
2449 } 2714 }
2450 continue; 2715 continue;
2451 } 2716 }
2452 if (textOffset <= box->start() + box->len()) { 2717 if (textOffset <= box->start() + box->len()) {
2453 if (textOffset > box->start()) 2718 if (textOffset > box->start())
2454 return currentPos.computePosition(); 2719 return currentPos.computePosition();
2455 continue; 2720 continue;
(...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after
2564 if (currentPos.offsetInLeafNode() <= layoutObject->caretMinOffset()) 2829 if (currentPos.offsetInLeafNode() <= layoutObject->caretMinOffset())
2565 return PositionTemplate<Strategy>::editingPositionOf(currentNode , layoutObject->caretMinOffset()); 2830 return PositionTemplate<Strategy>::editingPositionOf(currentNode , layoutObject->caretMinOffset());
2566 continue; 2831 continue;
2567 } 2832 }
2568 2833
2569 // return current position if it is in laid out text 2834 // return current position if it is in laid out text
2570 if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox() ) { 2835 if (layoutObject->isText() && toLayoutText(layoutObject)->firstTextBox() ) {
2571 LayoutText* const textLayoutObject = toLayoutText(layoutObject); 2836 LayoutText* const textLayoutObject = toLayoutText(layoutObject);
2572 const unsigned textStartOffset = textLayoutObject->textStartOffset() ; 2837 const unsigned textStartOffset = textLayoutObject->textStartOffset() ;
2573 if (currentNode != startNode) { 2838 if (currentNode != startNode) {
2574 DCHECK(currentPos.atStartOfNode()); 2839 ASSERT(currentPos.atStartOfNode());
2575 return PositionTemplate<Strategy>(currentNode, layoutObject->car etMinOffset() + textStartOffset); 2840 return PositionTemplate<Strategy>(currentNode, layoutObject->car etMinOffset() + textStartOffset);
2576 } 2841 }
2577 2842
2578 // Map offset in DOM node to offset in InlineBox. 2843 // Map offset in DOM node to offset in InlineBox.
2579 DCHECK_GE(currentPos.offsetInLeafNode(), static_cast<int>(textStartO ffset)); 2844 ASSERT(currentPos.offsetInLeafNode() >= static_cast<int>(textStartOf fset));
2580 const unsigned textOffset = currentPos.offsetInLeafNode() - textStar tOffset; 2845 const unsigned textOffset = currentPos.offsetInLeafNode() - textStar tOffset;
2581 InlineTextBox* lastTextBox = textLayoutObject->lastTextBox(); 2846 InlineTextBox* lastTextBox = textLayoutObject->lastTextBox();
2582 for (InlineTextBox* box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox()) { 2847 for (InlineTextBox* box = textLayoutObject->firstTextBox(); box; box = box->nextTextBox()) {
2583 if (textOffset <= box->end()) { 2848 if (textOffset <= box->end()) {
2584 if (textOffset >= box->start()) 2849 if (textOffset >= box->start())
2585 return currentPos.computePosition(); 2850 return currentPos.computePosition();
2586 continue; 2851 continue;
2587 } 2852 }
2588 2853
2589 if (box == lastTextBox || textOffset != box->start() + box->len( )) 2854 if (box == lastTextBox || textOffset != box->start() + box->len( ))
(...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after
2762 // or both are non-editable. 3027 // or both are non-editable.
2763 if (highestRootOfPos == highestRoot) 3028 if (highestRootOfPos == highestRoot)
2764 return pos; 3029 return pos;
2765 3030
2766 // If this is not editable but |pos| has an editable root, skip to the end 3031 // If this is not editable but |pos| has an editable root, skip to the end
2767 if (!highestRoot && highestRootOfPos) 3032 if (!highestRoot && highestRootOfPos)
2768 return createVisiblePosition(PositionTemplate<Strategy>(highestRootOfPos , PositionAnchorType::AfterAnchor).parentAnchoredEquivalent()); 3033 return createVisiblePosition(PositionTemplate<Strategy>(highestRootOfPos , PositionAnchorType::AfterAnchor).parentAnchoredEquivalent());
2769 3034
2770 // That must mean that |pos| is not editable. Return the next position after 3035 // That must mean that |pos| is not editable. Return the next position after
2771 // |pos| that is in the same editable region as this position 3036 // |pos| that is in the same editable region as this position
2772 DCHECK(highestRoot); 3037 ASSERT(highestRoot);
2773 return firstEditableVisiblePositionAfterPositionInRoot(pos.deepEquivalent(), *highestRoot); 3038 return firstEditableVisiblePositionAfterPositionInRoot(pos.deepEquivalent(), *highestRoot);
2774 } 3039 }
2775 3040
2776 template <typename Strategy> 3041 template <typename Strategy>
2777 static UChar32 characterAfterAlgorithm(const VisiblePositionTemplate<Strategy>& visiblePosition) 3042 static UChar32 characterAfterAlgorithm(const VisiblePositionTemplate<Strategy>& visiblePosition)
2778 { 3043 {
2779 // We canonicalize to the first of two equivalent candidates, but the second 3044 // We canonicalize to the first of two equivalent candidates, but the second
2780 // of the two candidates is the one that will be inside the text node 3045 // of the two candidates is the one that will be inside the text node
2781 // containing the character after this visible position. 3046 // containing the character after this visible position.
2782 const PositionTemplate<Strategy> pos = mostForwardCaretPosition(visiblePosit ion.deepEquivalent()); 3047 const PositionTemplate<Strategy> pos = mostForwardCaretPosition(visiblePosit ion.deepEquivalent());
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
2814 { 3079 {
2815 return characterBeforeAlgorithm<EditingStrategy>(visiblePosition); 3080 return characterBeforeAlgorithm<EditingStrategy>(visiblePosition);
2816 } 3081 }
2817 3082
2818 UChar32 characterBefore(const VisiblePositionInFlatTree& visiblePosition) 3083 UChar32 characterBefore(const VisiblePositionInFlatTree& visiblePosition)
2819 { 3084 {
2820 return characterBeforeAlgorithm<EditingInFlatTreeStrategy>(visiblePosition); 3085 return characterBeforeAlgorithm<EditingInFlatTreeStrategy>(visiblePosition);
2821 } 3086 }
2822 3087
2823 template <typename Strategy> 3088 template <typename Strategy>
2824 static PositionTemplate<Strategy> leftVisuallyDistinctCandidate(const VisiblePos itionTemplate<Strategy>& visiblePosition)
2825 {
2826 const PositionTemplate<Strategy> deepPosition = visiblePosition.deepEquivale nt();
2827 PositionTemplate<Strategy> p = deepPosition;
2828
2829 if (p.isNull())
2830 return PositionTemplate<Strategy>();
2831
2832 const PositionTemplate<Strategy> downstreamStart = mostForwardCaretPosition( p);
2833 TextDirection primaryDirection = primaryDirectionOf(*p.anchorNode());
2834 const TextAffinity affinity = visiblePosition.affinity();
2835
2836 while (true) {
2837 InlineBoxPosition boxPosition = computeInlineBoxPosition(p, affinity, pr imaryDirection);
2838 InlineBox* box = boxPosition.inlineBox;
2839 int offset = boxPosition.offsetInBox;
2840 if (!box)
2841 return primaryDirection == LTR ? previousVisuallyDistinctCandidate(d eepPosition) : nextVisuallyDistinctCandidate(deepPosition);
2842
2843 LineLayoutItem lineLayoutItem = box->getLineLayoutItem();
2844
2845 while (true) {
2846 if ((lineLayoutItem.isAtomicInlineLevel() || lineLayoutItem.isBR()) && offset == box->caretRightmostOffset())
2847 return box->isLeftToRightDirection() ? previousVisuallyDistinctC andidate(deepPosition) : nextVisuallyDistinctCandidate(deepPosition);
2848
2849 if (!lineLayoutItem.node()) {
2850 box = box->prevLeafChild();
2851 if (!box)
2852 return primaryDirection == LTR ? previousVisuallyDistinctCan didate(deepPosition) : nextVisuallyDistinctCandidate(deepPosition);
2853 lineLayoutItem = box->getLineLayoutItem();
2854 offset = box->caretRightmostOffset();
2855 continue;
2856 }
2857
2858 offset = box->isLeftToRightDirection() ? previousGraphemeBoundaryOf( lineLayoutItem.node(), offset) : nextGraphemeBoundaryOf(lineLayoutItem.node(), o ffset);
2859
2860 int caretMinOffset = box->caretMinOffset();
2861 int caretMaxOffset = box->caretMaxOffset();
2862
2863 if (offset > caretMinOffset && offset < caretMaxOffset)
2864 break;
2865
2866 if (box->isLeftToRightDirection() ? offset < caretMinOffset : offset > caretMaxOffset) {
2867 // Overshot to the left.
2868 InlineBox* prevBox = box->prevLeafChildIgnoringLineBreak();
2869 if (!prevBox) {
2870 PositionTemplate<Strategy> positionOnLeft = primaryDirection == LTR ? previousVisuallyDistinctCandidate(visiblePosition.deepEquivalent()) : nextVisuallyDistinctCandidate(visiblePosition.deepEquivalent());
2871 if (positionOnLeft.isNull())
2872 return PositionTemplate<Strategy>();
2873
2874 InlineBox* boxOnLeft = computeInlineBoxPosition(positionOnLe ft, affinity, primaryDirection).inlineBox;
2875 if (boxOnLeft && boxOnLeft->root() == box->root())
2876 return PositionTemplate<Strategy>();
2877 return positionOnLeft;
2878 }
2879
2880 // Reposition at the other logical position corresponding to our
2881 // edge's visual position and go for another round.
2882 box = prevBox;
2883 lineLayoutItem = box->getLineLayoutItem();
2884 offset = prevBox->caretRightmostOffset();
2885 continue;
2886 }
2887
2888 DCHECK_EQ(offset, box->caretLeftmostOffset());
2889
2890 unsigned char level = box->bidiLevel();
2891 InlineBox* prevBox = box->prevLeafChild();
2892
2893 if (box->direction() == primaryDirection) {
2894 if (!prevBox) {
2895 InlineBox* logicalStart = 0;
2896 if (primaryDirection == LTR ? box->root().getLogicalStartBox WithNode(logicalStart) : box->root().getLogicalEndBoxWithNode(logicalStart)) {
2897 box = logicalStart;
2898 lineLayoutItem = box->getLineLayoutItem();
2899 offset = primaryDirection == LTR ? box->caretMinOffset() : box->caretMaxOffset();
2900 }
2901 break;
2902 }
2903 if (prevBox->bidiLevel() >= level)
2904 break;
2905
2906 level = prevBox->bidiLevel();
2907
2908 InlineBox* nextBox = box;
2909 do {
2910 nextBox = nextBox->nextLeafChild();
2911 } while (nextBox && nextBox->bidiLevel() > level);
2912
2913 if (nextBox && nextBox->bidiLevel() == level)
2914 break;
2915
2916 box = prevBox;
2917 lineLayoutItem = box->getLineLayoutItem();
2918 offset = box->caretRightmostOffset();
2919 if (box->direction() == primaryDirection)
2920 break;
2921 continue;
2922 }
2923
2924 while (prevBox && !prevBox->getLineLayoutItem().node())
2925 prevBox = prevBox->prevLeafChild();
2926
2927 if (prevBox) {
2928 box = prevBox;
2929 lineLayoutItem = box->getLineLayoutItem();
2930 offset = box->caretRightmostOffset();
2931 if (box->bidiLevel() > level) {
2932 do {
2933 prevBox = prevBox->prevLeafChild();
2934 } while (prevBox && prevBox->bidiLevel() > level);
2935
2936 if (!prevBox || prevBox->bidiLevel() < level)
2937 continue;
2938 }
2939 } else {
2940 // Trailing edge of a secondary run. Set to the leading edge of
2941 // the entire run.
2942 while (true) {
2943 while (InlineBox* nextBox = box->nextLeafChild()) {
2944 if (nextBox->bidiLevel() < level)
2945 break;
2946 box = nextBox;
2947 }
2948 if (box->bidiLevel() == level)
2949 break;
2950 level = box->bidiLevel();
2951 while (InlineBox* prevBox = box->prevLeafChild()) {
2952 if (prevBox->bidiLevel() < level)
2953 break;
2954 box = prevBox;
2955 }
2956 if (box->bidiLevel() == level)
2957 break;
2958 level = box->bidiLevel();
2959 }
2960 lineLayoutItem = box->getLineLayoutItem();
2961 offset = primaryDirection == LTR ? box->caretMinOffset() : box-> caretMaxOffset();
2962 }
2963 break;
2964 }
2965
2966 p = PositionTemplate<Strategy>::editingPositionOf(lineLayoutItem.node(), offset);
2967
2968 if ((isVisuallyEquivalentCandidate(p) && mostForwardCaretPosition(p) != downstreamStart) || p.atStartOfTree() || p.atEndOfTree())
2969 return p;
2970
2971 DCHECK_NE(p, deepPosition);
2972 }
2973 }
2974
2975 template <typename Strategy>
2976 VisiblePositionTemplate<Strategy> leftPositionOfAlgorithm(const VisiblePositionT emplate<Strategy>& visiblePosition) 3089 VisiblePositionTemplate<Strategy> leftPositionOfAlgorithm(const VisiblePositionT emplate<Strategy>& visiblePosition)
2977 { 3090 {
2978 const PositionTemplate<Strategy> pos = leftVisuallyDistinctCandidate(visible Position); 3091 if (visiblePosition.isNull())
2979 // TODO(yosin) Why can't we move left from the last position in a tree?
2980 if (pos.atStartOfTree() || pos.atEndOfTree())
2981 return VisiblePositionTemplate<Strategy>(); 3092 return VisiblePositionTemplate<Strategy>();
2982 3093 const PositionTemplate<Strategy>& startPosition = visiblePosition.deepEquiva lent();
2983 const VisiblePositionTemplate<Strategy> left = createVisiblePosition(pos); 3094 const LayoutPosition& startLayoutPostion = LayoutPosition::create(startPosit ion);
2984 DCHECK_NE(left.deepEquivalent(), visiblePosition.deepEquivalent()); 3095 for (LayoutPosition runner = leftPositionOf(startLayoutPostion);
2985 3096 runner.isNotNull();
2986 return directionOfEnclosingBlock(left.deepEquivalent()) == LTR ? honorEditin gBoundaryAtOrBefore(left, visiblePosition.deepEquivalent()) : honorEditingBounda ryAtOrAfter(left, visiblePosition.deepEquivalent()); 3097 runner = leftPositionOf(runner)) {
3098 if (!runner.canPlaceCaret() || runner.isCaretEquivalent(startLayoutPosti on))
3099 continue;
3100 const PositionTemplate<Strategy>& position = runner.toPosition(PositionT emplate<Strategy>());
3101 // TODO(yosin): Why can't we move left from the last position in a tree?
3102 if (position.atStartOfTree() || position.atEndOfTree())
3103 return VisiblePositionTemplate<Strategy>();
3104 const VisiblePositionTemplate<Strategy>& visibleLeft = createVisiblePosi tion(position);
3105 if (visibleLeft.isNull())
3106 return VisiblePositionTemplate<Strategy>();
3107 const PositionTemplate<Strategy>& left = visibleLeft.deepEquivalent();
3108 if (left == startPosition) {
3109 // |runner| is a member of canonical position set of |startPosition| .
3110 continue;
3111 }
3112 if (directionOfEnclosingBlock(left) == LTR)
3113 return honorEditingBoundaryAtOrBefore(visibleLeft, startPosition);
3114 return honorEditingBoundaryAtOrAfter(visibleLeft, startPosition);
3115 }
3116 return VisiblePositionTemplate<Strategy>();
2987 } 3117 }
2988 3118
2989 VisiblePosition leftPositionOf(const VisiblePosition& visiblePosition) 3119 VisiblePosition leftPositionOf(const VisiblePosition& visiblePosition)
2990 { 3120 {
2991 return leftPositionOfAlgorithm<EditingStrategy>(visiblePosition); 3121 return leftPositionOfAlgorithm<EditingStrategy>(visiblePosition);
2992 } 3122 }
2993 3123
2994 VisiblePositionInFlatTree leftPositionOf(const VisiblePositionInFlatTree& visibl ePosition) 3124 VisiblePositionInFlatTree leftPositionOf(const VisiblePositionInFlatTree& visibl ePosition)
2995 { 3125 {
2996 return leftPositionOfAlgorithm<EditingInFlatTreeStrategy>(visiblePosition); 3126 return leftPositionOfAlgorithm<EditingInFlatTreeStrategy>(visiblePosition);
2997 } 3127 }
2998 3128
2999 template <typename Strategy> 3129 template <typename Strategy>
3000 static PositionTemplate<Strategy> rightVisuallyDistinctCandidate(const VisiblePo sitionTemplate<Strategy>& visiblePosition)
3001 {
3002 const PositionTemplate<Strategy> deepPosition = visiblePosition.deepEquivale nt();
3003 PositionTemplate<Strategy> p = deepPosition;
3004 if (p.isNull())
3005 return PositionTemplate<Strategy>();
3006
3007 const PositionTemplate<Strategy> downstreamStart = mostForwardCaretPosition( p);
3008 TextDirection primaryDirection = primaryDirectionOf(*p.anchorNode());
3009 const TextAffinity affinity = visiblePosition.affinity();
3010
3011 while (true) {
3012 InlineBoxPosition boxPosition = computeInlineBoxPosition(p, affinity, pr imaryDirection);
3013 InlineBox* box = boxPosition.inlineBox;
3014 int offset = boxPosition.offsetInBox;
3015 if (!box)
3016 return primaryDirection == LTR ? nextVisuallyDistinctCandidate(deepP osition) : previousVisuallyDistinctCandidate(deepPosition);
3017
3018 LayoutObject* layoutObject = LineLayoutAPIShim::layoutObjectFrom(box->ge tLineLayoutItem());
3019
3020 while (true) {
3021 if ((layoutObject->isAtomicInlineLevel() || layoutObject->isBR()) && offset == box->caretLeftmostOffset())
3022 return box->isLeftToRightDirection() ? nextVisuallyDistinctCandi date(deepPosition) : previousVisuallyDistinctCandidate(deepPosition);
3023
3024 if (!layoutObject->node()) {
3025 box = box->nextLeafChild();
3026 if (!box)
3027 return primaryDirection == LTR ? nextVisuallyDistinctCandida te(deepPosition) : previousVisuallyDistinctCandidate(deepPosition);
3028 layoutObject = LineLayoutAPIShim::layoutObjectFrom(box->getLineL ayoutItem());
3029 offset = box->caretLeftmostOffset();
3030 continue;
3031 }
3032
3033 offset = box->isLeftToRightDirection() ? nextGraphemeBoundaryOf(layo utObject->node(), offset) : previousGraphemeBoundaryOf(layoutObject->node(), off set);
3034
3035 int caretMinOffset = box->caretMinOffset();
3036 int caretMaxOffset = box->caretMaxOffset();
3037
3038 if (offset > caretMinOffset && offset < caretMaxOffset)
3039 break;
3040
3041 if (box->isLeftToRightDirection() ? offset > caretMaxOffset : offset < caretMinOffset) {
3042 // Overshot to the right.
3043 InlineBox* nextBox = box->nextLeafChildIgnoringLineBreak();
3044 if (!nextBox) {
3045 PositionTemplate<Strategy> positionOnRight = primaryDirectio n == LTR ? nextVisuallyDistinctCandidate(deepPosition) : previousVisuallyDistinc tCandidate(deepPosition);
3046 if (positionOnRight.isNull())
3047 return PositionTemplate<Strategy>();
3048
3049 InlineBox* boxOnRight = computeInlineBoxPosition(positionOnR ight, affinity, primaryDirection).inlineBox;
3050 if (boxOnRight && boxOnRight->root() == box->root())
3051 return PositionTemplate<Strategy>();
3052 return positionOnRight;
3053 }
3054
3055 // Reposition at the other logical position corresponding to our
3056 // edge's visual position and go for another round.
3057 box = nextBox;
3058 layoutObject = LineLayoutAPIShim::layoutObjectFrom(box->getLineL ayoutItem());
3059 offset = nextBox->caretLeftmostOffset();
3060 continue;
3061 }
3062
3063 DCHECK_EQ(offset, box->caretRightmostOffset());
3064
3065 unsigned char level = box->bidiLevel();
3066 InlineBox* nextBox = box->nextLeafChild();
3067
3068 if (box->direction() == primaryDirection) {
3069 if (!nextBox) {
3070 InlineBox* logicalEnd = 0;
3071 if (primaryDirection == LTR ? box->root().getLogicalEndBoxWi thNode(logicalEnd) : box->root().getLogicalStartBoxWithNode(logicalEnd)) {
3072 box = logicalEnd;
3073 layoutObject = LineLayoutAPIShim::layoutObjectFrom(box-> getLineLayoutItem());
3074 offset = primaryDirection == LTR ? box->caretMaxOffset() : box->caretMinOffset();
3075 }
3076 break;
3077 }
3078
3079 if (nextBox->bidiLevel() >= level)
3080 break;
3081
3082 level = nextBox->bidiLevel();
3083
3084 InlineBox* prevBox = box;
3085 do {
3086 prevBox = prevBox->prevLeafChild();
3087 } while (prevBox && prevBox->bidiLevel() > level);
3088
3089 // For example, abc FED 123 ^ CBA
3090 if (prevBox && prevBox->bidiLevel() == level)
3091 break;
3092
3093 // For example, abc 123 ^ CBA or 123 ^ CBA abc
3094 box = nextBox;
3095 layoutObject = LineLayoutAPIShim::layoutObjectFrom(box->getLineL ayoutItem());
3096 offset = box->caretLeftmostOffset();
3097 if (box->direction() == primaryDirection)
3098 break;
3099 continue;
3100 }
3101
3102 while (nextBox && !nextBox->getLineLayoutItem().node())
3103 nextBox = nextBox->nextLeafChild();
3104
3105 if (nextBox) {
3106 box = nextBox;
3107 layoutObject = LineLayoutAPIShim::layoutObjectFrom(box->getLineL ayoutItem());
3108 offset = box->caretLeftmostOffset();
3109
3110 if (box->bidiLevel() > level) {
3111 do {
3112 nextBox = nextBox->nextLeafChild();
3113 } while (nextBox && nextBox->bidiLevel() > level);
3114
3115 if (!nextBox || nextBox->bidiLevel() < level)
3116 continue;
3117 }
3118 } else {
3119 // Trailing edge of a secondary run. Set to the leading edge of the entire run.
3120 while (true) {
3121 while (InlineBox* prevBox = box->prevLeafChild()) {
3122 if (prevBox->bidiLevel() < level)
3123 break;
3124 box = prevBox;
3125 }
3126 if (box->bidiLevel() == level)
3127 break;
3128 level = box->bidiLevel();
3129 while (InlineBox* nextBox = box->nextLeafChild()) {
3130 if (nextBox->bidiLevel() < level)
3131 break;
3132 box = nextBox;
3133 }
3134 if (box->bidiLevel() == level)
3135 break;
3136 level = box->bidiLevel();
3137 }
3138 layoutObject = LineLayoutAPIShim::layoutObjectFrom(box->getLineL ayoutItem());
3139 offset = primaryDirection == LTR ? box->caretMaxOffset() : box-> caretMinOffset();
3140 }
3141 break;
3142 }
3143
3144 p = PositionTemplate<Strategy>::editingPositionOf(layoutObject->node(), offset);
3145
3146 if ((isVisuallyEquivalentCandidate(p) && mostForwardCaretPosition(p) != downstreamStart) || p.atStartOfTree() || p.atEndOfTree())
3147 return p;
3148
3149 DCHECK_NE(p, deepPosition);
3150 }
3151 }
3152
3153 template <typename Strategy>
3154 static VisiblePositionTemplate<Strategy> rightPositionOfAlgorithm(const VisibleP ositionTemplate<Strategy>& visiblePosition) 3130 static VisiblePositionTemplate<Strategy> rightPositionOfAlgorithm(const VisibleP ositionTemplate<Strategy>& visiblePosition)
3155 { 3131 {
3156 const PositionTemplate<Strategy> pos = rightVisuallyDistinctCandidate(visibl ePosition); 3132 if (visiblePosition.isNull())
3157 // FIXME: Why can't we move left from the last position in a tree?
3158 if (pos.atStartOfTree() || pos.atEndOfTree())
3159 return VisiblePositionTemplate<Strategy>(); 3133 return VisiblePositionTemplate<Strategy>();
3160 3134 const PositionTemplate<Strategy>& startPosition = visiblePosition.deepEquiva lent();
3161 const VisiblePositionTemplate<Strategy> right = createVisiblePosition(pos); 3135 const LayoutPosition& startLayoutPostion = LayoutPosition::create(startPosit ion);
3162 DCHECK_NE(right.deepEquivalent(), visiblePosition.deepEquivalent()); 3136 for (LayoutPosition runner = rightPositionOf(startLayoutPostion);
3163 3137 runner.isNotNull();
3164 return directionOfEnclosingBlock(right.deepEquivalent()) == LTR ? honorEditi ngBoundaryAtOrAfter(right, visiblePosition.deepEquivalent()) : honorEditingBound aryAtOrBefore(right, visiblePosition.deepEquivalent()); 3138 runner = rightPositionOf(runner)) {
3139 if (!runner.canPlaceCaret() || runner.isCaretEquivalent(startLayoutPosti on))
3140 continue;
3141 const PositionTemplate<Strategy>& position = runner.toPosition(PositionT emplate<Strategy>());
3142 // TODO(yosin): Why can't we move left from the last position in a tree?
3143 if (position.atStartOfTree() || position.atEndOfTree())
3144 return VisiblePositionTemplate<Strategy>();
3145 // We should always be able to make the affinity
3146 // |TextAffinity::Downstream|, because going right from an
3147 // |TextAffinity::Upstream| position can never yield another
3148 // |TextAffinity::Upstream position| (unless line wrap length is 0).
3149 const VisiblePositionTemplate<Strategy>& visibleRight = createVisiblePos ition(position);
3150 if (visibleRight.isNull())
3151 return VisiblePositionTemplate<Strategy>();
3152 const PositionTemplate<Strategy>& right = visibleRight.deepEquivalent();
3153 if (right == startPosition) {
3154 // |runner| is a member of canonical position set of |startPosition| .
3155 continue;
3156 }
3157 if (directionOfEnclosingBlock(right) == LTR)
3158 return honorEditingBoundaryAtOrAfter(visibleRight, startPosition);
3159 return honorEditingBoundaryAtOrBefore(visibleRight, startPosition);
3160 }
3161 return VisiblePositionTemplate<Strategy>();
3165 } 3162 }
3166 3163
3167 VisiblePosition rightPositionOf(const VisiblePosition& visiblePosition) 3164 VisiblePosition rightPositionOf(const VisiblePosition& visiblePosition)
3168 { 3165 {
3169 return rightPositionOfAlgorithm<EditingStrategy>(visiblePosition); 3166 return rightPositionOfAlgorithm<EditingStrategy>(visiblePosition);
3170 } 3167 }
3171 3168
3172 VisiblePositionInFlatTree rightPositionOf(const VisiblePositionInFlatTree& visib lePosition) 3169 VisiblePositionInFlatTree rightPositionOf(const VisiblePositionInFlatTree& visib lePosition)
3173 { 3170 {
3174 return rightPositionOfAlgorithm<EditingInFlatTreeStrategy>(visiblePosition); 3171 return rightPositionOfAlgorithm<EditingInFlatTreeStrategy>(visiblePosition);
3175 } 3172 }
3176 3173
3177 template <typename Strategy> 3174 template <typename Strategy>
3178 static VisiblePositionTemplate<Strategy> nextPositionOfAlgorithm(const VisiblePo sitionTemplate<Strategy>& visiblePosition, EditingBoundaryCrossingRule rule) 3175 static VisiblePositionTemplate<Strategy> nextPositionOfAlgorithm(const VisiblePo sitionTemplate<Strategy>& visiblePosition, EditingBoundaryCrossingRule rule)
3179 { 3176 {
3180 const VisiblePositionTemplate<Strategy> next = createVisiblePosition(nextVis uallyDistinctCandidate(visiblePosition.deepEquivalent()), visiblePosition.affini ty()); 3177 if (visiblePosition.isNull())
3178 return VisiblePositionTemplate<Strategy>();
3179 const PositionTemplate<Strategy>& startPosition = visiblePosition.deepEquiva lent();
3180 const LayoutPosition& startLayoutPostion = LayoutPosition::create(startPosit ion);
3181 for (LayoutPosition runner = nextPositionOf(startLayoutPostion);
3182 runner.isNotNull();
3183 runner = nextPositionOf(runner)) {
3184 if (!runner.canPlaceCaret() || runner.isCaretEquivalent(startLayoutPosti on))
3185 continue;
3186 const PositionTemplate<Strategy>& position = runner.toPosition(PositionT emplate<Strategy>());
3187 const VisiblePositionTemplate<Strategy>& visibleNext = createVisiblePosi tion(position);
3188 if (visibleNext.isNull())
3189 return VisiblePositionTemplate<Strategy>();
3190 if (visibleNext.deepEquivalent() == startPosition) {
3191 // |runner| is a member of canonical position set of |startPosition| .
3192 continue;
3193 }
3194 switch (rule) {
3195 case CanCrossEditingBoundary:
3196 return visibleNext;
3197 case CannotCrossEditingBoundary:
3198 return honorEditingBoundaryAtOrAfter(visibleNext, startPosition);
3199 case CanSkipOverEditingBoundary:
3200 return skipToEndOfEditingBoundary(visibleNext, startPosition);
3201 }
3181 3202
3182 switch (rule) { 3203 ASSERT_NOT_REACHED();
3183 case CanCrossEditingBoundary: 3204 return honorEditingBoundaryAtOrAfter(visibleNext, startPosition);
3184 return next;
3185 case CannotCrossEditingBoundary:
3186 return honorEditingBoundaryAtOrAfter(next, visiblePosition.deepEquivalen t());
3187 case CanSkipOverEditingBoundary:
3188 return skipToEndOfEditingBoundary(next, visiblePosition.deepEquivalent() );
3189 } 3205 }
3190 ASSERT_NOT_REACHED(); 3206 return VisiblePositionTemplate<Strategy>();
3191 return honorEditingBoundaryAtOrAfter(next, visiblePosition.deepEquivalent()) ;
3192 } 3207 }
3193 3208
3194 VisiblePosition nextPositionOf(const VisiblePosition& visiblePosition, EditingBo undaryCrossingRule rule) 3209 VisiblePosition nextPositionOf(const VisiblePosition& visiblePosition, EditingBo undaryCrossingRule rule)
3195 { 3210 {
3196 return nextPositionOfAlgorithm<EditingStrategy>(visiblePosition, rule); 3211 return nextPositionOfAlgorithm<EditingStrategy>(visiblePosition, rule);
3197 } 3212 }
3198 3213
3199 VisiblePositionInFlatTree nextPositionOf(const VisiblePositionInFlatTree& visibl ePosition, EditingBoundaryCrossingRule rule) 3214 VisiblePositionInFlatTree nextPositionOf(const VisiblePositionInFlatTree& visibl ePosition, EditingBoundaryCrossingRule rule)
3200 { 3215 {
3201 return nextPositionOfAlgorithm<EditingInFlatTreeStrategy>(visiblePosition, r ule); 3216 return nextPositionOfAlgorithm<EditingInFlatTreeStrategy>(visiblePosition, r ule);
(...skipping 12 matching lines...) Expand all
3214 // both are non-editable. 3229 // both are non-editable.
3215 if (highestRootOfPos == highestRoot) 3230 if (highestRootOfPos == highestRoot)
3216 return pos; 3231 return pos;
3217 3232
3218 // If this is not editable but |pos| has an editable root, skip to the start 3233 // If this is not editable but |pos| has an editable root, skip to the start
3219 if (!highestRoot && highestRootOfPos) 3234 if (!highestRoot && highestRootOfPos)
3220 return createVisiblePosition(previousVisuallyDistinctCandidate(PositionT emplate<Strategy>(highestRootOfPos, PositionAnchorType::BeforeAnchor).parentAnch oredEquivalent())); 3235 return createVisiblePosition(previousVisuallyDistinctCandidate(PositionT emplate<Strategy>(highestRootOfPos, PositionAnchorType::BeforeAnchor).parentAnch oredEquivalent()));
3221 3236
3222 // That must mean that |pos| is not editable. Return the last position 3237 // That must mean that |pos| is not editable. Return the last position
3223 // before |pos| that is in the same editable region as this position 3238 // before |pos| that is in the same editable region as this position
3224 DCHECK(highestRoot); 3239 ASSERT(highestRoot);
3225 return lastEditableVisiblePositionBeforePositionInRoot(pos.deepEquivalent(), *highestRoot); 3240 return lastEditableVisiblePositionBeforePositionInRoot(pos.deepEquivalent(), *highestRoot);
3226 } 3241 }
3227 3242
3228 template <typename Strategy> 3243 template <typename Strategy>
3229 static VisiblePositionTemplate<Strategy> previousPositionOfAlgorithm(const Visib lePositionTemplate<Strategy>& visiblePosition, EditingBoundaryCrossingRule rule) 3244 static VisiblePositionTemplate<Strategy> previousPositionOfAlgorithm(const Visib lePositionTemplate<Strategy>& visiblePosition, EditingBoundaryCrossingRule rule)
3230 { 3245 {
3231 const PositionTemplate<Strategy> pos = previousVisuallyDistinctCandidate(vis iblePosition.deepEquivalent()); 3246 if (visiblePosition.isNull())
3247 return VisiblePositionTemplate<Strategy>();
3248 const PositionTemplate<Strategy>& startPosition = visiblePosition.deepEquiva lent();
3249 const LayoutPosition& startLayoutPosition = LayoutPosition::create(startPosi tion);
3250 for (LayoutPosition runner = previousPositionOf(startLayoutPosition);
3251 runner.isNotNull();
3252 runner = previousPositionOf(runner)) {
3253 if (!runner.canPlaceCaret() || runner.isCaretEquivalent(startLayoutPosit ion))
3254 continue;
3255 const PositionTemplate<Strategy>& position = runner.toPosition(PositionT emplate<Strategy>());
3256 if (position.atStartOfTree())
3257 return VisiblePositionTemplate<Strategy>();
3258 // We should always be able to make the affinity
3259 // |TextAffinity::Downstream|, because going previous from an
3260 // |TextAffinity::Upstream| position can never yield another
3261 // |TextAffinity::Upstream position| (unless line wrap length is 0).
3262 const VisiblePositionTemplate<Strategy>& visiblePrevious = createVisible Position(position);
3263 if (visiblePrevious.isNull())
3264 return VisiblePositionTemplate<Strategy>();
3265 if (visiblePrevious.deepEquivalent() == startPosition) {
3266 // |runner| is a member of canonical position set of |startPosition| .
3267 continue;
3268 }
3269 switch (rule) {
3270 case CanCrossEditingBoundary:
3271 return visiblePrevious;
3272 case CannotCrossEditingBoundary:
3273 return honorEditingBoundaryAtOrBefore(visiblePrevious, startPosition );
3274 case CanSkipOverEditingBoundary:
3275 return skipToStartOfEditingBoundary(visiblePrevious, startPosition);
3276 }
3232 3277
3233 // return null visible position if there is no previous visible position 3278 ASSERT_NOT_REACHED();
3234 if (pos.atStartOfTree()) 3279 return honorEditingBoundaryAtOrBefore(visiblePrevious, startPosition);
3235 return VisiblePositionTemplate<Strategy>();
3236
3237 // we should always be able to make the affinity |TextAffinity::Downstream|,
3238 // because going previous from an |TextAffinity::Upstream| position can
3239 // never yield another |TextAffinity::Upstream position| (unless line wrap
3240 // length is 0!).
3241 const VisiblePositionTemplate<Strategy> prev = createVisiblePosition(pos);
3242 DCHECK_NE(prev.deepEquivalent(), visiblePosition.deepEquivalent());
3243
3244 switch (rule) {
3245 case CanCrossEditingBoundary:
3246 return prev;
3247 case CannotCrossEditingBoundary:
3248 return honorEditingBoundaryAtOrBefore(prev, visiblePosition.deepEquivale nt());
3249 case CanSkipOverEditingBoundary:
3250 return skipToStartOfEditingBoundary(prev, visiblePosition.deepEquivalent ());
3251 } 3280 }
3252 3281 return VisiblePositionTemplate<Strategy>();
3253 ASSERT_NOT_REACHED();
3254 return honorEditingBoundaryAtOrBefore(prev, visiblePosition.deepEquivalent() );
3255 } 3282 }
3256 3283
3257 VisiblePosition previousPositionOf(const VisiblePosition& visiblePosition, Editi ngBoundaryCrossingRule rule) 3284 VisiblePosition previousPositionOf(const VisiblePosition& visiblePosition, Editi ngBoundaryCrossingRule rule)
3258 { 3285 {
3259 return previousPositionOfAlgorithm<EditingStrategy>(visiblePosition, rule); 3286 return previousPositionOfAlgorithm<EditingStrategy>(visiblePosition, rule);
3260 } 3287 }
3261 3288
3262 VisiblePositionInFlatTree previousPositionOf(const VisiblePositionInFlatTree& vi siblePosition, EditingBoundaryCrossingRule rule) 3289 VisiblePositionInFlatTree previousPositionOf(const VisiblePositionInFlatTree& vi siblePosition, EditingBoundaryCrossingRule rule)
3263 { 3290 {
3264 return previousPositionOfAlgorithm<EditingInFlatTreeStrategy>(visiblePositio n, rule); 3291 return previousPositionOfAlgorithm<EditingInFlatTreeStrategy>(visiblePositio n, rule);
3265 } 3292 }
3266 3293
3267 } // namespace blink 3294 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/editing/VisibleUnits.h ('k') | third_party/WebKit/Source/core/editing/VisibleUnitsTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698