Chromium Code Reviews| OLD | NEW |
|---|---|
| 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 Loading... | |
| 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 in | |
|
Xiaocheng
2017/06/12 18:28:15
nit: And also comments.
yosin_UTC9
2017/06/13 06:44:46
Done.
| |
| 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. |
|
Xiaocheng
2017/06/12 18:28:15
Like this.
yosin_UTC9
2017/06/13 06:44:46
Good catch!
| |
| 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 |
| OLD | NEW |