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

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

Issue 2930863002: Move LeftPositionOf() and RightPositionOf() to SelectionModifierCharacter.cpp (Closed)
Patch Set: 2017-06-08T18:53:47 Created 3 years, 6 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
(Empty)
1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights
3 * reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27 // Copyright 2017 The Chromium Authors. All rights reserved.
28 // Use of this source code is governed by a BSD-style license that can be
29 // found in the LICENSE file.
30
31 #include "core/editing/SelectionModifier.h"
32
33 #include "core/editing/EditingUtilities.h"
34 #include "core/editing/VisibleUnits.h"
35 #include "core/layout/api/LineLayoutAPIShim.h"
36 #include "core/layout/api/LineLayoutItem.h"
37 #include "core/layout/line/InlineTextBox.h"
38 #include "core/layout/line/RootInlineBox.h"
39
40 namespace blink {
41
42 namespace {
43
44 template <typename Strategy>
45 static PositionTemplate<Strategy> LeftVisuallyDistinctCandidate(
46 const VisiblePositionTemplate<Strategy>& visible_position) {
47 DCHECK(visible_position.IsValid()) << visible_position;
48 const PositionTemplate<Strategy> deep_position =
49 visible_position.DeepEquivalent();
50 PositionTemplate<Strategy> p = deep_position;
51
52 if (p.IsNull())
53 return PositionTemplate<Strategy>();
54
55 const PositionTemplate<Strategy> downstream_start =
56 MostForwardCaretPosition(p);
57 const TextDirection primary_direction = PrimaryDirectionOf(*p.AnchorNode());
58 const TextAffinity affinity = visible_position.Affinity();
59
60 while (true) {
61 InlineBoxPosition box_position =
62 ComputeInlineBoxPosition(p, affinity, primary_direction);
63 InlineBox* box = box_position.inline_box;
64 int offset = box_position.offset_in_box;
65 if (!box) {
66 return primary_direction == TextDirection::kLtr
67 ? PreviousVisuallyDistinctCandidate(deep_position)
68 : NextVisuallyDistinctCandidate(deep_position);
69 }
70 LineLayoutItem line_layout_item = box->GetLineLayoutItem();
71
72 while (true) {
73 if ((line_layout_item.IsAtomicInlineLevel() || line_layout_item.IsBR()) &&
74 offset == box->CaretRightmostOffset()) {
75 return box->IsLeftToRightDirection()
76 ? PreviousVisuallyDistinctCandidate(deep_position)
77 : NextVisuallyDistinctCandidate(deep_position);
78 }
79 if (!line_layout_item.GetNode()) {
80 box = box->PrevLeafChild();
81 if (!box) {
82 return primary_direction == TextDirection::kLtr
83 ? PreviousVisuallyDistinctCandidate(deep_position)
84 : NextVisuallyDistinctCandidate(deep_position);
85 }
86 line_layout_item = box->GetLineLayoutItem();
87 offset = box->CaretRightmostOffset();
88 continue;
89 }
90
91 offset =
92 box->IsLeftToRightDirection()
93 ? PreviousGraphemeBoundaryOf(line_layout_item.GetNode(), offset)
94 : NextGraphemeBoundaryOf(line_layout_item.GetNode(), offset);
95
96 const int caret_min_offset = box->CaretMinOffset();
97 const int caret_max_offset = box->CaretMaxOffset();
98
99 if (offset > caret_min_offset && offset < caret_max_offset)
100 break;
101
102 if (box->IsLeftToRightDirection() ? offset < caret_min_offset
103 : offset > caret_max_offset) {
104 // Overshot to the left.
105 InlineBox* const prev_box = box->PrevLeafChildIgnoringLineBreak();
106 if (!prev_box) {
107 PositionTemplate<Strategy> position_on_left =
108 primary_direction == TextDirection::kLtr
109 ? PreviousVisuallyDistinctCandidate(
110 visible_position.DeepEquivalent())
111 : NextVisuallyDistinctCandidate(
112 visible_position.DeepEquivalent());
113 if (position_on_left.IsNull())
114 return PositionTemplate<Strategy>();
115
116 InlineBox* box_on_left =
117 ComputeInlineBoxPosition(position_on_left, affinity,
118 primary_direction)
119 .inline_box;
120 if (box_on_left && box_on_left->Root() == box->Root())
121 return PositionTemplate<Strategy>();
122 return position_on_left;
123 }
124
125 // Reposition at the other logical position corresponding to our
126 // edge's visual position and go for another round.
127 box = prev_box;
128 line_layout_item = box->GetLineLayoutItem();
129 offset = prev_box->CaretRightmostOffset();
130 continue;
131 }
132
133 DCHECK_EQ(offset, box->CaretLeftmostOffset());
134
135 unsigned char level = box->BidiLevel();
136 InlineBox* prev_box = box->PrevLeafChild();
137
138 if (box->Direction() == primary_direction) {
139 if (!prev_box) {
140 InlineBox* logical_start = nullptr;
141 if (primary_direction == TextDirection::kLtr
142 ? box->Root().GetLogicalStartBoxWithNode(logical_start)
143 : box->Root().GetLogicalEndBoxWithNode(logical_start)) {
144 box = logical_start;
145 line_layout_item = box->GetLineLayoutItem();
146 offset = primary_direction == TextDirection::kLtr
147 ? box->CaretMinOffset()
148 : box->CaretMaxOffset();
149 }
150 break;
151 }
152 if (prev_box->BidiLevel() >= level)
153 break;
154
155 level = prev_box->BidiLevel();
156
157 InlineBox* next_box = box;
158 do {
159 next_box = next_box->NextLeafChild();
160 } while (next_box && next_box->BidiLevel() > level);
161
162 if (next_box && next_box->BidiLevel() == level)
163 break;
164
165 box = prev_box;
166 line_layout_item = box->GetLineLayoutItem();
167 offset = box->CaretRightmostOffset();
168 if (box->Direction() == primary_direction)
169 break;
170 continue;
171 }
172
173 while (prev_box && !prev_box->GetLineLayoutItem().GetNode())
174 prev_box = prev_box->PrevLeafChild();
175
176 if (prev_box) {
177 box = prev_box;
178 line_layout_item = box->GetLineLayoutItem();
179 offset = box->CaretRightmostOffset();
180 if (box->BidiLevel() > level) {
181 do {
182 prev_box = prev_box->PrevLeafChild();
183 } while (prev_box && prev_box->BidiLevel() > level);
184
185 if (!prev_box || prev_box->BidiLevel() < level)
186 continue;
187 }
188 } else {
189 // Trailing edge of a secondary run. Set to the leading edge of
190 // the entire run.
191 while (true) {
192 while (InlineBox* next_box = box->NextLeafChild()) {
193 if (next_box->BidiLevel() < level)
194 break;
195 box = next_box;
196 }
197 if (box->BidiLevel() == level)
198 break;
199 level = box->BidiLevel();
200 while (InlineBox* prev_box = box->PrevLeafChild()) {
201 if (prev_box->BidiLevel() < level)
202 break;
203 box = prev_box;
204 }
205 if (box->BidiLevel() == level)
206 break;
207 level = box->BidiLevel();
208 }
209 line_layout_item = box->GetLineLayoutItem();
210 offset = primary_direction == TextDirection::kLtr
211 ? box->CaretMinOffset()
212 : box->CaretMaxOffset();
213 }
214 break;
215 }
216
217 p = PositionTemplate<Strategy>::EditingPositionOf(
218 line_layout_item.GetNode(), offset);
219
220 if ((IsVisuallyEquivalentCandidate(p) &&
221 MostForwardCaretPosition(p) != downstream_start) ||
222 p.AtStartOfTree() || p.AtEndOfTree())
223 return p;
224
225 DCHECK_NE(p, deep_position);
226 }
227 }
228
229 template <typename Strategy>
230 VisiblePositionTemplate<Strategy> LeftPositionOfAlgorithm(
231 const VisiblePositionTemplate<Strategy>& visible_position) {
232 DCHECK(visible_position.IsValid()) << visible_position;
233 const PositionTemplate<Strategy> pos =
234 LeftVisuallyDistinctCandidate(visible_position);
235 // TODO(yosin) Why can't we move left from the last position in a tree?
236 if (pos.AtStartOfTree() || pos.AtEndOfTree())
237 return VisiblePositionTemplate<Strategy>();
238
239 const VisiblePositionTemplate<Strategy> left = CreateVisiblePosition(pos);
240 DCHECK_NE(left.DeepEquivalent(), visible_position.DeepEquivalent());
241
242 return DirectionOfEnclosingBlockOf(left.DeepEquivalent()) ==
243 TextDirection::kLtr
244 ? HonorEditingBoundaryAtOrBefore(left,
245 visible_position.DeepEquivalent())
246 : HonorEditingBoundaryAtOrAfter(left,
247 visible_position.DeepEquivalent());
248 }
249
250 template <typename Strategy>
251 PositionTemplate<Strategy> RightVisuallyDistinctCandidate(
252 const VisiblePositionTemplate<Strategy>& visible_position) {
253 DCHECK(visible_position.IsValid()) << visible_position;
254 const PositionTemplate<Strategy> deep_position =
255 visible_position.DeepEquivalent();
256 PositionTemplate<Strategy> p = deep_position;
257 if (p.IsNull())
258 return PositionTemplate<Strategy>();
259
260 const PositionTemplate<Strategy> downstream_start =
261 MostForwardCaretPosition(p);
262 const TextDirection primary_direction = PrimaryDirectionOf(*p.AnchorNode());
263 const TextAffinity affinity = visible_position.Affinity();
264
265 while (true) {
266 InlineBoxPosition box_position =
267 ComputeInlineBoxPosition(p, affinity, primary_direction);
268 InlineBox* box = box_position.inline_box;
269 int offset = box_position.offset_in_box;
270 if (!box) {
271 return primary_direction == TextDirection::kLtr
272 ? NextVisuallyDistinctCandidate(deep_position)
273 : PreviousVisuallyDistinctCandidate(deep_position);
274 }
275 LayoutObject* layout_object =
276 LineLayoutAPIShim::LayoutObjectFrom(box->GetLineLayoutItem());
277
278 while (true) {
279 if ((layout_object->IsAtomicInlineLevel() || layout_object->IsBR()) &&
280 offset == box->CaretLeftmostOffset()) {
281 return box->IsLeftToRightDirection()
282 ? NextVisuallyDistinctCandidate(deep_position)
283 : PreviousVisuallyDistinctCandidate(deep_position);
284 }
285 if (!layout_object->GetNode()) {
286 box = box->NextLeafChild();
287 if (!box) {
288 return primary_direction == TextDirection::kLtr
289 ? NextVisuallyDistinctCandidate(deep_position)
290 : PreviousVisuallyDistinctCandidate(deep_position);
291 }
292 layout_object =
293 LineLayoutAPIShim::LayoutObjectFrom(box->GetLineLayoutItem());
294 offset = box->CaretLeftmostOffset();
295 continue;
296 }
297
298 offset =
299 box->IsLeftToRightDirection()
300 ? NextGraphemeBoundaryOf(layout_object->GetNode(), offset)
301 : PreviousGraphemeBoundaryOf(layout_object->GetNode(), offset);
302
303 const int caret_min_offset = box->CaretMinOffset();
304 const int caret_max_offset = box->CaretMaxOffset();
305
306 if (offset > caret_min_offset && offset < caret_max_offset)
307 break;
308
309 if (box->IsLeftToRightDirection() ? offset > caret_max_offset
310 : offset < caret_min_offset) {
311 // Overshot to the right.
312 InlineBox* const next_box = box->NextLeafChildIgnoringLineBreak();
313 if (!next_box) {
314 PositionTemplate<Strategy> position_on_right =
315 primary_direction == TextDirection::kLtr
316 ? NextVisuallyDistinctCandidate(deep_position)
317 : PreviousVisuallyDistinctCandidate(deep_position);
318 if (position_on_right.IsNull())
319 return PositionTemplate<Strategy>();
320
321 InlineBox* box_on_right =
322 ComputeInlineBoxPosition(position_on_right, affinity,
323 primary_direction)
324 .inline_box;
325 if (box_on_right && box_on_right->Root() == box->Root())
326 return PositionTemplate<Strategy>();
327 return position_on_right;
328 }
329
330 // Reposition at the other logical position corresponding to our
331 // edge's visual position and go for another round.
332 box = next_box;
333 layout_object =
334 LineLayoutAPIShim::LayoutObjectFrom(box->GetLineLayoutItem());
335 offset = next_box->CaretLeftmostOffset();
336 continue;
337 }
338
339 DCHECK_EQ(offset, box->CaretRightmostOffset());
340
341 unsigned char level = box->BidiLevel();
342 InlineBox* next_box = box->NextLeafChild();
343
344 if (box->Direction() == primary_direction) {
345 if (!next_box) {
346 InlineBox* logical_end = nullptr;
347 if (primary_direction == TextDirection::kLtr
348 ? box->Root().GetLogicalEndBoxWithNode(logical_end)
349 : box->Root().GetLogicalStartBoxWithNode(logical_end)) {
350 box = logical_end;
351 layout_object =
352 LineLayoutAPIShim::LayoutObjectFrom(box->GetLineLayoutItem());
353 offset = primary_direction == TextDirection::kLtr
354 ? box->CaretMaxOffset()
355 : box->CaretMinOffset();
356 }
357 break;
358 }
359
360 if (next_box->BidiLevel() >= level)
361 break;
362
363 level = next_box->BidiLevel();
364
365 InlineBox* prev_box = box;
366 do {
367 prev_box = prev_box->PrevLeafChild();
368 } while (prev_box && prev_box->BidiLevel() > level);
369
370 // For example, abc FED 123 ^ CBA
371 if (prev_box && prev_box->BidiLevel() == level)
372 break;
373
374 // For example, abc 123 ^ CBA or 123 ^ CBA abc
375 box = next_box;
376 layout_object =
377 LineLayoutAPIShim::LayoutObjectFrom(box->GetLineLayoutItem());
378 offset = box->CaretLeftmostOffset();
379 if (box->Direction() == primary_direction)
380 break;
381 continue;
382 }
383
384 while (next_box && !next_box->GetLineLayoutItem().GetNode())
385 next_box = next_box->NextLeafChild();
386
387 if (next_box) {
388 box = next_box;
389 layout_object =
390 LineLayoutAPIShim::LayoutObjectFrom(box->GetLineLayoutItem());
391 offset = box->CaretLeftmostOffset();
392
393 if (box->BidiLevel() > level) {
394 do {
395 next_box = next_box->NextLeafChild();
396 } while (next_box && next_box->BidiLevel() > level);
397
398 if (!next_box || next_box->BidiLevel() < level)
399 continue;
400 }
401 } else {
402 // Trailing edge of a secondary run. Set to the leading edge of the
403 // entire run.
404 while (true) {
405 while (InlineBox* prev_box = box->PrevLeafChild()) {
406 if (prev_box->BidiLevel() < level)
407 break;
408 box = prev_box;
409 }
410 if (box->BidiLevel() == level)
411 break;
412 level = box->BidiLevel();
413 while (InlineBox* next_box = box->NextLeafChild()) {
414 if (next_box->BidiLevel() < level)
415 break;
416 box = next_box;
417 }
418 if (box->BidiLevel() == level)
419 break;
420 level = box->BidiLevel();
421 }
422 layout_object =
423 LineLayoutAPIShim::LayoutObjectFrom(box->GetLineLayoutItem());
424 offset = primary_direction == TextDirection::kLtr
425 ? box->CaretMaxOffset()
426 : box->CaretMinOffset();
427 }
428 break;
429 }
430
431 p = PositionTemplate<Strategy>::EditingPositionOf(layout_object->GetNode(),
432 offset);
433
434 if ((IsVisuallyEquivalentCandidate(p) &&
435 MostForwardCaretPosition(p) != downstream_start) ||
436 p.AtStartOfTree() || p.AtEndOfTree())
437 return p;
438
439 DCHECK_NE(p, deep_position);
440 }
441 }
442
443 template <typename Strategy>
444 VisiblePositionTemplate<Strategy> RightPositionOfAlgorithm(
445 const VisiblePositionTemplate<Strategy>& visible_position) {
446 DCHECK(visible_position.IsValid()) << visible_position;
447 const PositionTemplate<Strategy> pos =
448 RightVisuallyDistinctCandidate(visible_position);
449 // TODO(editing-dev): Why can't we move left from the last position in a tree?
450 if (pos.AtStartOfTree() || pos.AtEndOfTree())
451 return VisiblePositionTemplate<Strategy>();
452
453 const VisiblePositionTemplate<Strategy> right = CreateVisiblePosition(pos);
454 DCHECK_NE(right.DeepEquivalent(), visible_position.DeepEquivalent());
455
456 return DirectionOfEnclosingBlockOf(right.DeepEquivalent()) ==
457 TextDirection::kLtr
458 ? HonorEditingBoundaryAtOrAfter(right,
459 visible_position.DeepEquivalent())
460 : HonorEditingBoundaryAtOrBefore(
461 right, visible_position.DeepEquivalent());
462 }
463
464 } // namespace
465
466 VisiblePosition LeftPositionOf(const VisiblePosition& visible_position) {
467 return LeftPositionOfAlgorithm<EditingStrategy>(visible_position);
468 }
469
470 VisiblePositionInFlatTree LeftPositionOf(
471 const VisiblePositionInFlatTree& visible_position) {
472 return LeftPositionOfAlgorithm<EditingInFlatTreeStrategy>(visible_position);
473 }
474
475 VisiblePosition RightPositionOf(const VisiblePosition& visible_position) {
476 return RightPositionOfAlgorithm<EditingStrategy>(visible_position);
477 }
478
479 VisiblePositionInFlatTree RightPositionOf(
480 const VisiblePositionInFlatTree& visible_position) {
481 return RightPositionOfAlgorithm<EditingInFlatTreeStrategy>(visible_position);
482 }
483
484 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698