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

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

Issue 2934773002: Unify implementation of LeftPositionOf() and RightPositionOf() (Closed)
Patch Set: 2017-06-13T15:43:11 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
« no previous file with comments | « no previous file | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights 2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights
3 * reserved. 3 * reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
(...skipping 23 matching lines...) Expand all
34 #include "core/editing/VisibleUnits.h" 34 #include "core/editing/VisibleUnits.h"
35 #include "core/layout/api/LineLayoutAPIShim.h" 35 #include "core/layout/api/LineLayoutAPIShim.h"
36 #include "core/layout/api/LineLayoutItem.h" 36 #include "core/layout/api/LineLayoutItem.h"
37 #include "core/layout/line/InlineTextBox.h" 37 #include "core/layout/line/InlineTextBox.h"
38 #include "core/layout/line/RootInlineBox.h" 38 #include "core/layout/line/RootInlineBox.h"
39 39
40 namespace blink { 40 namespace blink {
41 41
42 namespace { 42 namespace {
43 43
44 // The traversal strategy for |LeftPositionOf()|.
44 template <typename Strategy> 45 template <typename Strategy>
45 static PositionTemplate<Strategy> LeftVisuallyDistinctCandidate( 46 struct TraversalLeft {
47 STATIC_ONLY(TraversalLeft);
48
49 static InlineBox* BackwardLeafChildOf(const InlineBox& box) {
50 return box.NextLeafChild();
51 }
52
53 static int CaretEndOffsetOf(const InlineBox& box) {
54 return box.CaretRightmostOffset();
55 }
56
57 static int CaretMinOffsetOf(TextDirection direction, const InlineBox& box) {
58 if (direction == TextDirection::kLtr)
59 return box.CaretMinOffset();
60 return box.CaretMaxOffset();
61 }
62
63 static int CaretStartOffsetOf(const InlineBox& box) {
64 return box.CaretLeftmostOffset();
65 }
66
67 static int ForwardGraphemeBoundaryOf(TextDirection direction,
68 Node* node,
69 int offset) {
70 if (direction == TextDirection::kLtr)
71 return PreviousGraphemeBoundaryOf(node, offset);
72 return NextGraphemeBoundaryOf(node, offset);
73 }
74
75 static InlineBox* ForwardLeafChildOf(const InlineBox& box) {
76 return box.PrevLeafChild();
77 }
78
79 static InlineBox* ForwardLeafChildIgnoringLineBreakOf(const InlineBox& box) {
80 return box.PrevLeafChildIgnoringLineBreak();
81 }
82
83 static PositionTemplate<Strategy> ForwardVisuallyDistinctCandidateOf(
84 TextDirection direction,
85 const PositionTemplate<Strategy>& position) {
86 if (direction == TextDirection::kLtr)
87 return PreviousVisuallyDistinctCandidate(position);
88 return NextVisuallyDistinctCandidate(position);
89 }
90
91 static VisiblePositionTemplate<Strategy> HonorEditingBoundary(
92 TextDirection direction,
93 const VisiblePositionTemplate<Strategy>& visible_position,
94 const PositionTemplate<Strategy>& anchor) {
95 if (direction == TextDirection::kLtr)
96 return HonorEditingBoundaryAtOrBefore(visible_position, anchor);
97 return HonorEditingBoundaryAtOrAfter(visible_position, anchor);
98 }
99
100 static Node* LogicalStartBoxOf(TextDirection direction,
101 const InlineBox& box,
102 InlineBox*& result_box) {
103 if (direction == TextDirection::kLtr)
104 return box.Root().GetLogicalStartBoxWithNode(result_box);
105 return box.Root().GetLogicalEndBoxWithNode(result_box);
106 }
107
108 static bool IsOvershot(int offset, const InlineBox& box) {
109 if (box.IsLeftToRightDirection())
110 return offset < box.CaretMinOffset();
111 return offset > box.CaretMaxOffset();
112 }
113 };
114
115 // The traversal strategy for |RightPositionOf()|.
116 template <typename Strategy>
117 struct TraversalRight {
118 STATIC_ONLY(TraversalRight);
119
120 static InlineBox* BackwardLeafChildOf(const InlineBox& box) {
121 return box.PrevLeafChild();
122 }
123
124 static int CaretEndOffsetOf(const InlineBox& box) {
125 return box.CaretLeftmostOffset();
126 }
127
128 static int CaretMinOffsetOf(TextDirection direction, const InlineBox& box) {
129 if (direction == TextDirection::kLtr)
130 return box.CaretMaxOffset();
131 return box.CaretMinOffset();
132 }
133
134 static int CaretStartOffsetOf(const InlineBox& box) {
135 return box.CaretRightmostOffset();
136 }
137
138 static int ForwardGraphemeBoundaryOf(TextDirection direction,
139 Node* node,
140 int offset) {
141 if (direction == TextDirection::kLtr)
142 return NextGraphemeBoundaryOf(node, offset);
143 return PreviousGraphemeBoundaryOf(node, offset);
144 }
145
146 static InlineBox* ForwardLeafChildOf(const InlineBox& box) {
147 return box.NextLeafChild();
148 }
149
150 static InlineBox* ForwardLeafChildIgnoringLineBreakOf(const InlineBox& box) {
151 return box.NextLeafChildIgnoringLineBreak();
152 }
153
154 static PositionTemplate<Strategy> ForwardVisuallyDistinctCandidateOf(
155 TextDirection direction,
156 const PositionTemplate<Strategy>& position) {
157 if (direction == TextDirection::kLtr)
158 return NextVisuallyDistinctCandidate(position);
159 return PreviousVisuallyDistinctCandidate(position);
160 }
161
162 static VisiblePositionTemplate<Strategy> HonorEditingBoundary(
163 TextDirection direction,
164 const VisiblePositionTemplate<Strategy>& visible_position,
165 const PositionTemplate<Strategy>& anchor) {
166 if (direction == TextDirection::kLtr)
167 return HonorEditingBoundaryAtOrAfter(visible_position, anchor);
168 return HonorEditingBoundaryAtOrBefore(visible_position, anchor);
169 }
170
171 static Node* LogicalStartBoxOf(TextDirection direction,
172 const InlineBox& box,
173 InlineBox*& result_box) {
174 if (direction == TextDirection::kLtr)
175 return box.Root().GetLogicalEndBoxWithNode(result_box);
176 return box.Root().GetLogicalStartBoxWithNode(result_box);
177 }
178
179 static bool IsOvershot(int offset, const InlineBox& box) {
180 if (box.IsLeftToRightDirection())
181 return offset > box.CaretMaxOffset();
182 return offset < box.CaretMinOffset();
183 }
184 };
185
186 // TODO(yosin): We should rename local variables and comments in
187 // |TraverseInternalAlgorithm()| to generic name based on |Traversal| instead of
188 // assuming right-to-left traversal.
189 template <typename Strategy, typename Traversal>
190 static PositionTemplate<Strategy> TraverseInternalAlgorithm(
46 const VisiblePositionTemplate<Strategy>& visible_position) { 191 const VisiblePositionTemplate<Strategy>& visible_position) {
47 DCHECK(visible_position.IsValid()) << visible_position; 192 DCHECK(visible_position.IsValid()) << visible_position;
48 const PositionTemplate<Strategy> deep_position = 193 const PositionTemplate<Strategy> deep_position =
49 visible_position.DeepEquivalent(); 194 visible_position.DeepEquivalent();
50 PositionTemplate<Strategy> p = deep_position; 195 PositionTemplate<Strategy> p = deep_position;
51 196
52 if (p.IsNull()) 197 if (p.IsNull())
53 return PositionTemplate<Strategy>(); 198 return PositionTemplate<Strategy>();
54 199
55 const PositionTemplate<Strategy> downstream_start = 200 const PositionTemplate<Strategy> downstream_start =
56 MostForwardCaretPosition(p); 201 MostForwardCaretPosition(p);
57 const TextDirection primary_direction = PrimaryDirectionOf(*p.AnchorNode()); 202 const TextDirection primary_direction = PrimaryDirectionOf(*p.AnchorNode());
58 const TextAffinity affinity = visible_position.Affinity(); 203 const TextAffinity affinity = visible_position.Affinity();
59 204
60 while (true) { 205 while (true) {
61 InlineBoxPosition box_position = 206 InlineBoxPosition box_position =
62 ComputeInlineBoxPosition(p, affinity, primary_direction); 207 ComputeInlineBoxPosition(p, affinity, primary_direction);
63 InlineBox* box = box_position.inline_box; 208 InlineBox* box = box_position.inline_box;
64 int offset = box_position.offset_in_box; 209 int offset = box_position.offset_in_box;
65 if (!box) { 210 if (!box) {
66 return primary_direction == TextDirection::kLtr 211 return Traversal::ForwardVisuallyDistinctCandidateOf(primary_direction,
67 ? PreviousVisuallyDistinctCandidate(deep_position) 212 deep_position);
68 : NextVisuallyDistinctCandidate(deep_position);
69 } 213 }
70 LineLayoutItem line_layout_item = box->GetLineLayoutItem(); 214 LineLayoutItem line_layout_item = box->GetLineLayoutItem();
71 215
72 while (true) { 216 while (true) {
73 if ((line_layout_item.IsAtomicInlineLevel() || line_layout_item.IsBR()) && 217 if ((line_layout_item.IsAtomicInlineLevel() || line_layout_item.IsBR()) &&
74 offset == box->CaretRightmostOffset()) { 218 offset == Traversal::CaretEndOffsetOf(*box)) {
75 return box->IsLeftToRightDirection() 219 return Traversal::ForwardVisuallyDistinctCandidateOf(box->Direction(),
76 ? PreviousVisuallyDistinctCandidate(deep_position) 220 deep_position);
77 : NextVisuallyDistinctCandidate(deep_position);
78 } 221 }
79 if (!line_layout_item.GetNode()) { 222 if (!line_layout_item.GetNode()) {
80 box = box->PrevLeafChild(); 223 box = Traversal::ForwardLeafChildOf(*box);
81 if (!box) { 224 if (!box) {
82 return primary_direction == TextDirection::kLtr 225 return Traversal::ForwardVisuallyDistinctCandidateOf(
83 ? PreviousVisuallyDistinctCandidate(deep_position) 226 primary_direction, deep_position);
84 : NextVisuallyDistinctCandidate(deep_position);
85 } 227 }
86 line_layout_item = box->GetLineLayoutItem(); 228 line_layout_item = box->GetLineLayoutItem();
87 offset = box->CaretRightmostOffset(); 229 offset = Traversal::CaretEndOffsetOf(*box);
88 continue; 230 continue;
89 } 231 }
90 232
91 offset = 233 offset = Traversal::ForwardGraphemeBoundaryOf(
92 box->IsLeftToRightDirection() 234 box->Direction(), line_layout_item.GetNode(), offset);
93 ? PreviousGraphemeBoundaryOf(line_layout_item.GetNode(), offset)
94 : NextGraphemeBoundaryOf(line_layout_item.GetNode(), offset);
95 235
96 const int caret_min_offset = box->CaretMinOffset(); 236 const int caret_min_offset = box->CaretMinOffset();
97 const int caret_max_offset = box->CaretMaxOffset(); 237 const int caret_max_offset = box->CaretMaxOffset();
98 238
99 if (offset > caret_min_offset && offset < caret_max_offset) 239 if (offset > caret_min_offset && offset < caret_max_offset)
100 break; 240 break;
101 241
102 if (box->IsLeftToRightDirection() ? offset < caret_min_offset 242 if (Traversal::IsOvershot(offset, *box)) {
103 : offset > caret_max_offset) {
104 // Overshot to the left. 243 // Overshot to the left.
105 InlineBox* const prev_box = box->PrevLeafChildIgnoringLineBreak(); 244 InlineBox* const prev_box =
245 Traversal::ForwardLeafChildIgnoringLineBreakOf(*box);
106 if (!prev_box) { 246 if (!prev_box) {
107 PositionTemplate<Strategy> position_on_left = 247 const PositionTemplate<Strategy>& position_on_left =
108 primary_direction == TextDirection::kLtr 248 Traversal::ForwardVisuallyDistinctCandidateOf(
109 ? PreviousVisuallyDistinctCandidate( 249 primary_direction, visible_position.DeepEquivalent());
110 visible_position.DeepEquivalent())
111 : NextVisuallyDistinctCandidate(
112 visible_position.DeepEquivalent());
113 if (position_on_left.IsNull()) 250 if (position_on_left.IsNull())
114 return PositionTemplate<Strategy>(); 251 return PositionTemplate<Strategy>();
115 252
116 InlineBox* box_on_left = 253 InlineBox* box_on_left =
117 ComputeInlineBoxPosition(position_on_left, affinity, 254 ComputeInlineBoxPosition(position_on_left, affinity,
118 primary_direction) 255 primary_direction)
119 .inline_box; 256 .inline_box;
120 if (box_on_left && box_on_left->Root() == box->Root()) 257 if (box_on_left && box_on_left->Root() == box->Root())
121 return PositionTemplate<Strategy>(); 258 return PositionTemplate<Strategy>();
122 return position_on_left; 259 return position_on_left;
123 } 260 }
124 261
125 // Reposition at the other logical position corresponding to our 262 // Reposition at the other logical position corresponding to our
126 // edge's visual position and go for another round. 263 // edge's visual position and go for another round.
127 box = prev_box; 264 box = prev_box;
128 line_layout_item = box->GetLineLayoutItem(); 265 line_layout_item = box->GetLineLayoutItem();
129 offset = prev_box->CaretRightmostOffset(); 266 offset = Traversal::CaretEndOffsetOf(*prev_box);
130 continue; 267 continue;
131 } 268 }
132 269
133 DCHECK_EQ(offset, box->CaretLeftmostOffset()); 270 DCHECK_EQ(offset, Traversal::CaretStartOffsetOf(*box));
134 271
135 unsigned char level = box->BidiLevel(); 272 unsigned char level = box->BidiLevel();
136 InlineBox* prev_box = box->PrevLeafChild(); 273 InlineBox* prev_box = Traversal::ForwardLeafChildOf(*box);
137 274
138 if (box->Direction() == primary_direction) { 275 if (box->Direction() == primary_direction) {
139 if (!prev_box) { 276 if (!prev_box) {
140 InlineBox* logical_start = nullptr; 277 InlineBox* logical_start = nullptr;
141 if (primary_direction == TextDirection::kLtr 278 if (Traversal::LogicalStartBoxOf(primary_direction, *box,
142 ? box->Root().GetLogicalStartBoxWithNode(logical_start) 279 logical_start)) {
143 : box->Root().GetLogicalEndBoxWithNode(logical_start)) {
144 box = logical_start; 280 box = logical_start;
145 line_layout_item = box->GetLineLayoutItem(); 281 line_layout_item = box->GetLineLayoutItem();
146 offset = primary_direction == TextDirection::kLtr 282 offset = Traversal::CaretMinOffsetOf(primary_direction, *box);
147 ? box->CaretMinOffset()
148 : box->CaretMaxOffset();
149 } 283 }
150 break; 284 break;
151 } 285 }
152 if (prev_box->BidiLevel() >= level) 286 if (prev_box->BidiLevel() >= level)
153 break; 287 break;
154 288
155 level = prev_box->BidiLevel(); 289 level = prev_box->BidiLevel();
156 290
157 InlineBox* next_box = box; 291 InlineBox* next_box = box;
158 do { 292 do {
159 next_box = next_box->NextLeafChild(); 293 next_box = Traversal::BackwardLeafChildOf(*next_box);
160 } while (next_box && next_box->BidiLevel() > level); 294 } while (next_box && next_box->BidiLevel() > level);
161 295
162 if (next_box && next_box->BidiLevel() == level) 296 if (next_box && next_box->BidiLevel() == level)
163 break; 297 break;
164 298
165 box = prev_box; 299 box = prev_box;
166 line_layout_item = box->GetLineLayoutItem(); 300 line_layout_item = box->GetLineLayoutItem();
167 offset = box->CaretRightmostOffset(); 301 offset = Traversal::CaretEndOffsetOf(*box);
168 if (box->Direction() == primary_direction) 302 if (box->Direction() == primary_direction)
169 break; 303 break;
170 continue; 304 continue;
171 } 305 }
172 306
173 while (prev_box && !prev_box->GetLineLayoutItem().GetNode()) 307 while (prev_box && !prev_box->GetLineLayoutItem().GetNode())
174 prev_box = prev_box->PrevLeafChild(); 308 prev_box = Traversal::ForwardLeafChildOf(*prev_box);
175 309
176 if (prev_box) { 310 if (prev_box) {
177 box = prev_box; 311 box = prev_box;
178 line_layout_item = box->GetLineLayoutItem(); 312 line_layout_item = box->GetLineLayoutItem();
179 offset = box->CaretRightmostOffset(); 313 offset = Traversal::CaretEndOffsetOf(*box);
180 if (box->BidiLevel() > level) { 314 if (box->BidiLevel() > level) {
181 do { 315 do {
182 prev_box = prev_box->PrevLeafChild(); 316 prev_box = Traversal::ForwardLeafChildOf(*prev_box);
183 } while (prev_box && prev_box->BidiLevel() > level); 317 } while (prev_box && prev_box->BidiLevel() > level);
184 318
185 if (!prev_box || prev_box->BidiLevel() < level) 319 if (!prev_box || prev_box->BidiLevel() < level)
186 continue; 320 continue;
187 } 321 }
188 } else { 322 } else {
189 // Trailing edge of a secondary run. Set to the leading edge of 323 // Trailing edge of a secondary run. Set to the leading edge of
190 // the entire run. 324 // the entire run.
191 while (true) { 325 while (true) {
192 while (InlineBox* next_box = box->NextLeafChild()) { 326 while (InlineBox* next_box = Traversal::BackwardLeafChildOf(*box)) {
193 if (next_box->BidiLevel() < level) 327 if (next_box->BidiLevel() < level)
194 break; 328 break;
195 box = next_box; 329 box = next_box;
196 } 330 }
197 if (box->BidiLevel() == level) 331 if (box->BidiLevel() == level)
198 break; 332 break;
199 level = box->BidiLevel(); 333 level = box->BidiLevel();
200 while (InlineBox* prev_box = box->PrevLeafChild()) { 334 while (InlineBox* prev_box = Traversal::ForwardLeafChildOf(*box)) {
201 if (prev_box->BidiLevel() < level) 335 if (prev_box->BidiLevel() < level)
202 break; 336 break;
203 box = prev_box; 337 box = prev_box;
204 } 338 }
205 if (box->BidiLevel() == level) 339 if (box->BidiLevel() == level)
206 break; 340 break;
207 level = box->BidiLevel(); 341 level = box->BidiLevel();
208 } 342 }
209 line_layout_item = box->GetLineLayoutItem(); 343 line_layout_item = box->GetLineLayoutItem();
210 offset = primary_direction == TextDirection::kLtr 344 offset = Traversal::CaretMinOffsetOf(primary_direction, *box);
211 ? box->CaretMinOffset()
212 : box->CaretMaxOffset();
213 } 345 }
214 break; 346 break;
215 } 347 }
216 348
217 p = PositionTemplate<Strategy>::EditingPositionOf( 349 p = PositionTemplate<Strategy>::EditingPositionOf(
218 line_layout_item.GetNode(), offset); 350 line_layout_item.GetNode(), offset);
219 351
220 if ((IsVisuallyEquivalentCandidate(p) && 352 if ((IsVisuallyEquivalentCandidate(p) &&
221 MostForwardCaretPosition(p) != downstream_start) || 353 MostForwardCaretPosition(p) != downstream_start) ||
222 p.AtStartOfTree() || p.AtEndOfTree()) 354 p.AtStartOfTree() || p.AtEndOfTree())
223 return p; 355 return p;
224 356
225 DCHECK_NE(p, deep_position); 357 DCHECK_NE(p, deep_position);
226 } 358 }
227 } 359 }
228 360
229 template <typename Strategy> 361 template <typename Strategy, typename Traversal>
230 VisiblePositionTemplate<Strategy> LeftPositionOfAlgorithm( 362 VisiblePositionTemplate<Strategy> TraverseAlgorithm(
231 const VisiblePositionTemplate<Strategy>& visible_position) { 363 const VisiblePositionTemplate<Strategy>& visible_position) {
232 DCHECK(visible_position.IsValid()) << visible_position; 364 DCHECK(visible_position.IsValid()) << visible_position;
233 const PositionTemplate<Strategy> pos = 365 const PositionTemplate<Strategy> pos =
234 LeftVisuallyDistinctCandidate(visible_position); 366 TraverseInternalAlgorithm<Strategy, Traversal>(visible_position);
235 // TODO(yosin) Why can't we move left from the last position in a tree? 367 // TODO(yosin) Why can't we move left from the last position in a tree?
236 if (pos.AtStartOfTree() || pos.AtEndOfTree()) 368 if (pos.AtStartOfTree() || pos.AtEndOfTree())
237 return VisiblePositionTemplate<Strategy>(); 369 return VisiblePositionTemplate<Strategy>();
238 370
239 const VisiblePositionTemplate<Strategy> left = CreateVisiblePosition(pos); 371 const VisiblePositionTemplate<Strategy> result = CreateVisiblePosition(pos);
240 DCHECK_NE(left.DeepEquivalent(), visible_position.DeepEquivalent()); 372 DCHECK_NE(result.DeepEquivalent(), visible_position.DeepEquivalent());
241 373
242 return DirectionOfEnclosingBlockOf(left.DeepEquivalent()) == 374 return Traversal::HonorEditingBoundary(
243 TextDirection::kLtr 375 DirectionOfEnclosingBlockOf(result.DeepEquivalent()), result,
244 ? HonorEditingBoundaryAtOrBefore(left, 376 visible_position.DeepEquivalent());
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 } 377 }
463 378
464 } // namespace 379 } // namespace
465 380
466 VisiblePosition LeftPositionOf(const VisiblePosition& visible_position) { 381 VisiblePosition LeftPositionOf(const VisiblePosition& visible_position) {
467 return LeftPositionOfAlgorithm<EditingStrategy>(visible_position); 382 return TraverseAlgorithm<EditingStrategy, TraversalLeft<EditingStrategy>>(
383 visible_position);
468 } 384 }
469 385
470 VisiblePositionInFlatTree LeftPositionOf( 386 VisiblePositionInFlatTree LeftPositionOf(
471 const VisiblePositionInFlatTree& visible_position) { 387 const VisiblePositionInFlatTree& visible_position) {
472 return LeftPositionOfAlgorithm<EditingInFlatTreeStrategy>(visible_position); 388 return TraverseAlgorithm<EditingInFlatTreeStrategy,
389 TraversalLeft<EditingInFlatTreeStrategy>>(
390 visible_position);
473 } 391 }
474 392
475 VisiblePosition RightPositionOf(const VisiblePosition& visible_position) { 393 VisiblePosition RightPositionOf(const VisiblePosition& visible_position) {
476 return RightPositionOfAlgorithm<EditingStrategy>(visible_position); 394 return TraverseAlgorithm<EditingStrategy, TraversalRight<EditingStrategy>>(
395 visible_position);
477 } 396 }
478 397
479 VisiblePositionInFlatTree RightPositionOf( 398 VisiblePositionInFlatTree RightPositionOf(
480 const VisiblePositionInFlatTree& visible_position) { 399 const VisiblePositionInFlatTree& visible_position) {
481 return RightPositionOfAlgorithm<EditingInFlatTreeStrategy>(visible_position); 400 return TraverseAlgorithm<EditingInFlatTreeStrategy,
401 TraversalRight<EditingInFlatTreeStrategy>>(
402 visible_position);
482 } 403 }
483 404
484 } // namespace blink 405 } // namespace blink
OLDNEW
« no previous file with comments | « no previous file | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698