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

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

Issue 2914793002: Move "line" granularity related functions to VisibleUnitLine.cpp (Closed)
Patch Set: 2017-05-31T18:13:41 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 | « third_party/WebKit/Source/core/editing/VisibleUnits.cpp ('k') | 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
(Empty)
1 /*
2 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights
Xiaocheng 2017/05/31 18:12:21 We should use the Chromium Authors ... copyright n
yosin_UTC9 2017/06/01 01:09:16 No, we should use original copyright header. Diss
tkent 2017/06/01 01:15:58 yeah, I agree about this case.
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 #include "core/editing/VisibleUnits.h"
28
29 #include "core/editing/EditingUtilities.h"
30 #include "core/editing/RenderedPosition.h"
31 #include "core/layout/api/LineLayoutBlockFlow.h"
32 #include "core/layout/line/InlineTextBox.h"
33 #include "core/layout/line/RootInlineBox.h"
34
35 namespace blink {
36
37 namespace {
38
39 bool HasEditableStyle(const Node& node, EditableType editable_type) {
40 if (editable_type == kHasEditableAXRole) {
41 if (AXObjectCache* cache = node.GetDocument().ExistingAXObjectCache()) {
42 if (cache->RootAXEditableElement(&node))
43 return true;
44 }
45 }
46
47 return HasEditableStyle(node);
48 }
49
50 Element* RootEditableElement(const Node& node, EditableType editable_type) {
51 if (editable_type == kHasEditableAXRole) {
52 if (AXObjectCache* cache = node.GetDocument().ExistingAXObjectCache())
53 return const_cast<Element*>(cache->RootAXEditableElement(&node));
54 }
55
56 return RootEditableElement(node);
57 }
58
59 Element* RootAXEditableElementOf(const Position& position) {
60 Node* node = position.ComputeContainerNode();
61 if (!node)
62 return nullptr;
63
64 if (IsDisplayInsideTable(node))
65 node = node->parentNode();
66
67 return RootEditableElement(*node, kHasEditableAXRole);
68 }
69
70 bool HasAXEditableStyle(const Node& node) {
71 return HasEditableStyle(node, kHasEditableAXRole);
72 }
73
74 ContainerNode* HighestEditableRoot(const Position& position,
75 EditableType editable_type) {
76 if (editable_type == kHasEditableAXRole) {
77 return HighestEditableRoot(position, RootAXEditableElementOf,
78 HasAXEditableStyle);
79 }
80
81 return HighestEditableRoot(position);
82 }
83
84 Node* PreviousLeafWithSameEditability(Node* node, EditableType editable_type) {
85 bool editable = HasEditableStyle(*node, editable_type);
86 node = PreviousAtomicLeafNode(*node);
87 while (node) {
88 if (editable == HasEditableStyle(*node, editable_type))
89 return node;
90 node = PreviousAtomicLeafNode(*node);
91 }
92 return nullptr;
93 }
94
95 Node* NextLeafWithSameEditability(
96 Node* node,
97 EditableType editable_type = kContentIsEditable) {
98 if (!node)
99 return nullptr;
100
101 bool editable = HasEditableStyle(*node, editable_type);
102 node = NextAtomicLeafNode(*node);
103 while (node) {
104 if (editable == HasEditableStyle(*node, editable_type))
105 return node;
106 node = NextAtomicLeafNode(*node);
107 }
108 return nullptr;
109 }
110
111 enum LineEndpointComputationMode { kUseLogicalOrdering, kUseInlineBoxOrdering };
112 template <typename Strategy>
113 PositionWithAffinityTemplate<Strategy> StartPositionForLine(
114 const PositionWithAffinityTemplate<Strategy>& c,
115 LineEndpointComputationMode mode) {
116 if (c.IsNull())
117 return PositionWithAffinityTemplate<Strategy>();
118
119 RootInlineBox* root_box =
120 RenderedPosition(c.GetPosition(), c.Affinity()).RootBox();
121 if (!root_box) {
122 // There are VisiblePositions at offset 0 in blocks without
123 // RootInlineBoxes, like empty editable blocks and bordered blocks.
124 PositionTemplate<Strategy> p = c.GetPosition();
125 if (p.AnchorNode()->GetLayoutObject() &&
126 p.AnchorNode()->GetLayoutObject()->IsLayoutBlock() &&
127 !p.ComputeEditingOffset())
128 return c;
129
130 return PositionWithAffinityTemplate<Strategy>();
131 }
132
133 Node* start_node;
134 InlineBox* start_box;
135 if (mode == kUseLogicalOrdering) {
136 start_node = root_box->GetLogicalStartBoxWithNode(start_box);
137 if (!start_node)
138 return PositionWithAffinityTemplate<Strategy>();
139 } else {
140 // Generated content (e.g. list markers and CSS :before and :after
141 // pseudoelements) have no corresponding DOM element, and so cannot be
142 // represented by a VisiblePosition. Use whatever follows instead.
143 start_box = root_box->FirstLeafChild();
144 while (true) {
145 if (!start_box)
146 return PositionWithAffinityTemplate<Strategy>();
147
148 start_node = start_box->GetLineLayoutItem().NonPseudoNode();
149 if (start_node)
150 break;
151
152 start_box = start_box->NextLeafChild();
153 }
154 }
155
156 return PositionWithAffinityTemplate<Strategy>(
157 start_node->IsTextNode()
158 ? PositionTemplate<Strategy>(ToText(start_node),
159 ToInlineTextBox(start_box)->Start())
160 : PositionTemplate<Strategy>::BeforeNode(start_node));
161 }
162
163 template <typename Strategy>
164 PositionWithAffinityTemplate<Strategy> StartOfLineAlgorithm(
165 const PositionWithAffinityTemplate<Strategy>& c) {
166 // TODO: this is the current behavior that might need to be fixed.
167 // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
168 PositionWithAffinityTemplate<Strategy> vis_pos =
169 StartPositionForLine(c, kUseInlineBoxOrdering);
170 return HonorEditingBoundaryAtOrBefore(vis_pos, c.GetPosition());
171 }
172
173 PositionWithAffinity StartOfLine(const PositionWithAffinity& current_position) {
174 return StartOfLineAlgorithm<EditingStrategy>(current_position);
175 }
176
177 PositionInFlatTreeWithAffinity StartOfLine(
178 const PositionInFlatTreeWithAffinity& current_position) {
179 return StartOfLineAlgorithm<EditingInFlatTreeStrategy>(current_position);
180 }
181
182 LayoutPoint AbsoluteLineDirectionPointToLocalPointInBlock(
183 RootInlineBox* root,
184 LayoutUnit line_direction_point) {
185 DCHECK(root);
186 LineLayoutBlockFlow containing_block = root->Block();
187 FloatPoint absolute_block_point =
188 containing_block.LocalToAbsolute(FloatPoint());
189 if (containing_block.HasOverflowClip())
190 absolute_block_point -= FloatSize(containing_block.ScrolledContentOffset());
191
192 if (root->Block().IsHorizontalWritingMode()) {
193 return LayoutPoint(
194 LayoutUnit(line_direction_point - absolute_block_point.X()),
195 root->BlockDirectionPointInLine());
196 }
197
198 return LayoutPoint(
199 root->BlockDirectionPointInLine(),
200 LayoutUnit(line_direction_point - absolute_block_point.Y()));
201 }
202
203 } // namespace
204
205 // FIXME: consolidate with code in previousLinePosition.
206 Position PreviousRootInlineBoxCandidatePosition(
207 Node* node,
208 const VisiblePosition& visible_position,
209 EditableType editable_type) {
210 DCHECK(visible_position.IsValid()) << visible_position;
211 ContainerNode* highest_root =
212 HighestEditableRoot(visible_position.DeepEquivalent(), editable_type);
213 Node* previous_node = PreviousLeafWithSameEditability(node, editable_type);
214
215 while (previous_node &&
216 (!previous_node->GetLayoutObject() ||
217 InSameLine(
218 CreateVisiblePosition(FirstPositionInOrBeforeNode(previous_node)),
219 visible_position))) {
220 previous_node =
221 PreviousLeafWithSameEditability(previous_node, editable_type);
222 }
223
224 while (previous_node && !previous_node->IsShadowRoot()) {
225 if (HighestEditableRoot(FirstPositionInOrBeforeNode(previous_node),
226 editable_type) != highest_root)
227 break;
228
229 Position pos = isHTMLBRElement(*previous_node)
230 ? Position::BeforeNode(previous_node)
231 : Position::EditingPositionOf(
232 previous_node, CaretMaxOffset(previous_node));
233
234 if (IsVisuallyEquivalentCandidate(pos))
235 return pos;
236
237 previous_node =
238 PreviousLeafWithSameEditability(previous_node, editable_type);
239 }
240 return Position();
241 }
242
243 Position NextRootInlineBoxCandidatePosition(
244 Node* node,
245 const VisiblePosition& visible_position,
246 EditableType editable_type) {
247 DCHECK(visible_position.IsValid()) << visible_position;
248 ContainerNode* highest_root =
249 HighestEditableRoot(visible_position.DeepEquivalent(), editable_type);
250 Node* next_node = NextLeafWithSameEditability(node, editable_type);
251 while (next_node && (!next_node->GetLayoutObject() ||
252 InSameLine(CreateVisiblePosition(
253 FirstPositionInOrBeforeNode(next_node)),
254 visible_position)))
255 next_node = NextLeafWithSameEditability(next_node, kContentIsEditable);
256
257 while (next_node && !next_node->IsShadowRoot()) {
258 if (HighestEditableRoot(FirstPositionInOrBeforeNode(next_node),
259 editable_type) != highest_root)
260 break;
261
262 Position pos;
263 pos = Position::EditingPositionOf(next_node, CaretMinOffset(next_node));
264
265 if (IsVisuallyEquivalentCandidate(pos))
266 return pos;
267
268 next_node = NextLeafWithSameEditability(next_node, editable_type);
269 }
270 return Position();
271 }
272
273 // FIXME: Rename this function to reflect the fact it ignores bidi levels.
274 VisiblePosition StartOfLine(const VisiblePosition& current_position) {
275 DCHECK(current_position.IsValid()) << current_position;
276 return CreateVisiblePosition(
277 StartOfLine(current_position.ToPositionWithAffinity()));
278 }
279
280 VisiblePositionInFlatTree StartOfLine(
281 const VisiblePositionInFlatTree& current_position) {
282 DCHECK(current_position.IsValid()) << current_position;
283 return CreateVisiblePosition(
284 StartOfLine(current_position.ToPositionWithAffinity()));
285 }
286
287 template <typename Strategy>
288 static PositionWithAffinityTemplate<Strategy> LogicalStartOfLineAlgorithm(
289 const PositionWithAffinityTemplate<Strategy>& c) {
290 // TODO: this is the current behavior that might need to be fixed.
291 // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
292 PositionWithAffinityTemplate<Strategy> vis_pos =
293 StartPositionForLine(c, kUseLogicalOrdering);
294
295 if (ContainerNode* editable_root = HighestEditableRoot(c.GetPosition())) {
296 if (!editable_root->contains(
297 vis_pos.GetPosition().ComputeContainerNode())) {
298 return PositionWithAffinityTemplate<Strategy>(
299 PositionTemplate<Strategy>::FirstPositionInNode(editable_root));
300 }
301 }
302
303 return HonorEditingBoundaryAtOrBefore(vis_pos, c.GetPosition());
304 }
305
306 VisiblePosition LogicalStartOfLine(const VisiblePosition& current_position) {
307 DCHECK(current_position.IsValid()) << current_position;
308 return CreateVisiblePosition(LogicalStartOfLineAlgorithm<EditingStrategy>(
309 current_position.ToPositionWithAffinity()));
310 }
311
312 VisiblePositionInFlatTree LogicalStartOfLine(
313 const VisiblePositionInFlatTree& current_position) {
314 DCHECK(current_position.IsValid()) << current_position;
315 return CreateVisiblePosition(
316 LogicalStartOfLineAlgorithm<EditingInFlatTreeStrategy>(
317 current_position.ToPositionWithAffinity()));
318 }
319
320 template <typename Strategy>
321 static VisiblePositionTemplate<Strategy> EndPositionForLine(
322 const VisiblePositionTemplate<Strategy>& c,
323 LineEndpointComputationMode mode) {
324 DCHECK(c.IsValid()) << c;
325 if (c.IsNull())
326 return VisiblePositionTemplate<Strategy>();
327
328 RootInlineBox* root_box = RenderedPosition(c).RootBox();
329 if (!root_box) {
330 // There are VisiblePositions at offset 0 in blocks without
331 // RootInlineBoxes, like empty editable blocks and bordered blocks.
332 const PositionTemplate<Strategy> p = c.DeepEquivalent();
333 if (p.AnchorNode()->GetLayoutObject() &&
334 p.AnchorNode()->GetLayoutObject()->IsLayoutBlock() &&
335 !p.ComputeEditingOffset())
336 return c;
337 return VisiblePositionTemplate<Strategy>();
338 }
339
340 Node* end_node;
341 InlineBox* end_box;
342 if (mode == kUseLogicalOrdering) {
343 end_node = root_box->GetLogicalEndBoxWithNode(end_box);
344 if (!end_node)
345 return VisiblePositionTemplate<Strategy>();
346 } else {
347 // Generated content (e.g. list markers and CSS :before and :after
348 // pseudo elements) have no corresponding DOM element, and so cannot be
349 // represented by a VisiblePosition. Use whatever precedes instead.
350 end_box = root_box->LastLeafChild();
351 while (true) {
352 if (!end_box)
353 return VisiblePositionTemplate<Strategy>();
354
355 end_node = end_box->GetLineLayoutItem().NonPseudoNode();
356 if (end_node)
357 break;
358
359 end_box = end_box->PrevLeafChild();
360 }
361 }
362
363 PositionTemplate<Strategy> pos;
364 if (isHTMLBRElement(*end_node)) {
365 pos = PositionTemplate<Strategy>::BeforeNode(end_node);
366 } else if (end_box->IsInlineTextBox() && end_node->IsTextNode()) {
367 InlineTextBox* end_text_box = ToInlineTextBox(end_box);
368 int end_offset = end_text_box->Start();
369 if (!end_text_box->IsLineBreak())
370 end_offset += end_text_box->Len();
371 pos = PositionTemplate<Strategy>(ToText(end_node), end_offset);
372 } else {
373 pos = PositionTemplate<Strategy>::AfterNode(end_node);
374 }
375
376 return CreateVisiblePosition(pos, VP_UPSTREAM_IF_POSSIBLE);
377 }
378
379 // TODO(yosin) Rename this function to reflect the fact it ignores bidi levels.
380 template <typename Strategy>
381 static VisiblePositionTemplate<Strategy> EndOfLineAlgorithm(
382 const VisiblePositionTemplate<Strategy>& current_position) {
383 DCHECK(current_position.IsValid()) << current_position;
384 // TODO(yosin) this is the current behavior that might need to be fixed.
385 // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
386 VisiblePositionTemplate<Strategy> vis_pos =
387 EndPositionForLine(current_position, kUseInlineBoxOrdering);
388
389 // Make sure the end of line is at the same line as the given input
390 // position. Else use the previous position to obtain end of line. This
391 // condition happens when the input position is before the space character
392 // at the end of a soft-wrapped non-editable line. In this scenario,
393 // |endPositionForLine()| would incorrectly hand back a position in the next
394 // line instead. This fix is to account for the discrepancy between lines
395 // with "webkit-line-break:after-white-space" style versus lines without
396 // that style, which would break before a space by default.
397 if (!InSameLine(current_position, vis_pos)) {
398 vis_pos = PreviousPositionOf(current_position);
399 if (vis_pos.IsNull())
400 return VisiblePositionTemplate<Strategy>();
401 vis_pos = EndPositionForLine(vis_pos, kUseInlineBoxOrdering);
402 }
403
404 return HonorEditingBoundaryAtOrAfter(vis_pos,
405 current_position.DeepEquivalent());
406 }
407
408 // TODO(yosin) Rename this function to reflect the fact it ignores bidi levels.
409 VisiblePosition EndOfLine(const VisiblePosition& current_position) {
410 return EndOfLineAlgorithm<EditingStrategy>(current_position);
411 }
412
413 VisiblePositionInFlatTree EndOfLine(
414 const VisiblePositionInFlatTree& current_position) {
415 return EndOfLineAlgorithm<EditingInFlatTreeStrategy>(current_position);
416 }
417
418 template <typename Strategy>
419 static bool InSameLogicalLine(const VisiblePositionTemplate<Strategy>& a,
420 const VisiblePositionTemplate<Strategy>& b) {
421 DCHECK(a.IsValid()) << a;
422 DCHECK(b.IsValid()) << b;
423 return a.IsNotNull() && LogicalStartOfLine(a).DeepEquivalent() ==
424 LogicalStartOfLine(b).DeepEquivalent();
425 }
426
427 template <typename Strategy>
428 static VisiblePositionTemplate<Strategy> LogicalEndOfLineAlgorithm(
429 const VisiblePositionTemplate<Strategy>& current_position) {
430 DCHECK(current_position.IsValid()) << current_position;
431 // TODO(yosin) this is the current behavior that might need to be fixed.
432 // Please refer to https://bugs.webkit.org/show_bug.cgi?id=49107 for detail.
433 VisiblePositionTemplate<Strategy> vis_pos =
434 EndPositionForLine(current_position, kUseLogicalOrdering);
435
436 // Make sure the end of line is at the same line as the given input
437 // position. For a wrapping line, the logical end position for the
438 // not-last-2-lines might incorrectly hand back the logical beginning of the
439 // next line. For example,
440 // <div contenteditable dir="rtl" style="line-break:before-white-space">xyz
441 // a xyz xyz xyz xyz xyz xyz xyz xyz xyz xyz </div>
442 // In this case, use the previous position of the computed logical end
443 // position.
444 if (!InSameLogicalLine(current_position, vis_pos))
445 vis_pos = PreviousPositionOf(vis_pos);
446
447 if (ContainerNode* editable_root =
448 HighestEditableRoot(current_position.DeepEquivalent())) {
449 if (!editable_root->contains(
450 vis_pos.DeepEquivalent().ComputeContainerNode())) {
451 return CreateVisiblePosition(
452 PositionTemplate<Strategy>::LastPositionInNode(editable_root));
453 }
454 }
455
456 return HonorEditingBoundaryAtOrAfter(vis_pos,
457 current_position.DeepEquivalent());
458 }
459
460 VisiblePosition LogicalEndOfLine(const VisiblePosition& current_position) {
461 return LogicalEndOfLineAlgorithm<EditingStrategy>(current_position);
462 }
463
464 VisiblePositionInFlatTree LogicalEndOfLine(
465 const VisiblePositionInFlatTree& current_position) {
466 return LogicalEndOfLineAlgorithm<EditingInFlatTreeStrategy>(current_position);
467 }
468
469 template <typename Strategy>
470 static bool InSameLineAlgorithm(
471 const PositionWithAffinityTemplate<Strategy>& position1,
472 const PositionWithAffinityTemplate<Strategy>& position2) {
473 if (position1.IsNull() || position2.IsNull())
474 return false;
475 DCHECK_EQ(position1.GetDocument(), position2.GetDocument());
476 DCHECK(!position1.GetDocument()->NeedsLayoutTreeUpdate());
477
478 PositionWithAffinityTemplate<Strategy> start_of_line1 =
479 StartOfLine(position1);
480 PositionWithAffinityTemplate<Strategy> start_of_line2 =
481 StartOfLine(position2);
482 if (start_of_line1 == start_of_line2)
483 return true;
484 PositionTemplate<Strategy> canonicalized1 =
485 CanonicalPositionOf(start_of_line1.GetPosition());
486 if (canonicalized1 == start_of_line2.GetPosition())
487 return true;
488 return canonicalized1 == CanonicalPositionOf(start_of_line2.GetPosition());
489 }
490
491 bool InSameLine(const PositionWithAffinity& a, const PositionWithAffinity& b) {
492 return InSameLineAlgorithm<EditingStrategy>(a, b);
493 }
494
495 bool InSameLine(const PositionInFlatTreeWithAffinity& position1,
496 const PositionInFlatTreeWithAffinity& position2) {
497 return InSameLineAlgorithm<EditingInFlatTreeStrategy>(position1, position2);
498 }
499
500 bool InSameLine(const VisiblePosition& position1,
501 const VisiblePosition& position2) {
502 DCHECK(position1.IsValid()) << position1;
503 DCHECK(position2.IsValid()) << position2;
504 return InSameLine(position1.ToPositionWithAffinity(),
505 position2.ToPositionWithAffinity());
506 }
507
508 bool InSameLine(const VisiblePositionInFlatTree& position1,
509 const VisiblePositionInFlatTree& position2) {
510 DCHECK(position1.IsValid()) << position1;
511 DCHECK(position2.IsValid()) << position2;
512 return InSameLine(position1.ToPositionWithAffinity(),
513 position2.ToPositionWithAffinity());
514 }
515
516 template <typename Strategy>
517 static bool IsStartOfLineAlgorithm(const VisiblePositionTemplate<Strategy>& p) {
518 DCHECK(p.IsValid()) << p;
519 return p.IsNotNull() && p.DeepEquivalent() == StartOfLine(p).DeepEquivalent();
520 }
521
522 bool IsStartOfLine(const VisiblePosition& p) {
523 return IsStartOfLineAlgorithm<EditingStrategy>(p);
524 }
525
526 bool IsStartOfLine(const VisiblePositionInFlatTree& p) {
527 return IsStartOfLineAlgorithm<EditingInFlatTreeStrategy>(p);
528 }
529
530 template <typename Strategy>
531 static bool IsEndOfLineAlgorithm(const VisiblePositionTemplate<Strategy>& p) {
532 DCHECK(p.IsValid()) << p;
533 return p.IsNotNull() && p.DeepEquivalent() == EndOfLine(p).DeepEquivalent();
534 }
535
536 bool IsEndOfLine(const VisiblePosition& p) {
537 return IsEndOfLineAlgorithm<EditingStrategy>(p);
538 }
539
540 bool IsEndOfLine(const VisiblePositionInFlatTree& p) {
541 return IsEndOfLineAlgorithm<EditingInFlatTreeStrategy>(p);
542 }
543
544 template <typename Strategy>
545 static bool IsLogicalEndOfLineAlgorithm(
546 const VisiblePositionTemplate<Strategy>& p) {
547 DCHECK(p.IsValid()) << p;
548 return p.IsNotNull() &&
549 p.DeepEquivalent() == LogicalEndOfLine(p).DeepEquivalent();
550 }
551
552 bool IsLogicalEndOfLine(const VisiblePosition& p) {
553 return IsLogicalEndOfLineAlgorithm<EditingStrategy>(p);
554 }
555
556 bool IsLogicalEndOfLine(const VisiblePositionInFlatTree& p) {
557 return IsLogicalEndOfLineAlgorithm<EditingInFlatTreeStrategy>(p);
558 }
559
560 VisiblePosition PreviousLinePosition(const VisiblePosition& visible_position,
561 LayoutUnit line_direction_point,
562 EditableType editable_type) {
563 DCHECK(visible_position.IsValid()) << visible_position;
564
565 Position p = visible_position.DeepEquivalent();
566 Node* node = p.AnchorNode();
567
568 if (!node)
569 return VisiblePosition();
570
571 LayoutObject* layout_object = node->GetLayoutObject();
572 if (!layout_object)
573 return VisiblePosition();
574
575 RootInlineBox* root = nullptr;
576 InlineBox* box = ComputeInlineBoxPosition(visible_position).inline_box;
577 if (box) {
578 root = box->Root().PrevRootBox();
579 // We want to skip zero height boxes.
580 // This could happen in case it is a TrailingFloatsRootInlineBox.
581 if (!root || !root->LogicalHeight() || !root->FirstLeafChild())
582 root = nullptr;
583 }
584
585 if (!root) {
586 Position position = PreviousRootInlineBoxCandidatePosition(
587 node, visible_position, editable_type);
588 if (position.IsNotNull()) {
589 RenderedPosition rendered_position((CreateVisiblePosition(position)));
590 root = rendered_position.RootBox();
591 if (!root)
592 return CreateVisiblePosition(position);
593 }
594 }
595
596 if (root) {
597 // FIXME: Can be wrong for multi-column layout and with transforms.
598 LayoutPoint point_in_line = AbsoluteLineDirectionPointToLocalPointInBlock(
599 root, line_direction_point);
600 LineLayoutItem line_layout_item =
601 root->ClosestLeafChildForPoint(point_in_line, IsEditablePosition(p))
602 ->GetLineLayoutItem();
603 Node* node = line_layout_item.GetNode();
604 if (node && EditingIgnoresContent(*node))
605 return VisiblePosition::InParentBeforeNode(*node);
606 return CreateVisiblePosition(
607 line_layout_item.PositionForPoint(point_in_line));
608 }
609
610 // Could not find a previous line. This means we must already be on the first
611 // line. Move to the start of the content in this block, which effectively
612 // moves us to the start of the line we're on.
613 Element* root_element = HasEditableStyle(*node, editable_type)
614 ? RootEditableElement(*node, editable_type)
615 : node->GetDocument().documentElement();
616 if (!root_element)
617 return VisiblePosition();
618 return VisiblePosition::FirstPositionInNode(root_element);
619 }
620
621 VisiblePosition NextLinePosition(const VisiblePosition& visible_position,
622 LayoutUnit line_direction_point,
623 EditableType editable_type) {
624 DCHECK(visible_position.IsValid()) << visible_position;
625
626 Position p = visible_position.DeepEquivalent();
627 Node* node = p.AnchorNode();
628
629 if (!node)
630 return VisiblePosition();
631
632 LayoutObject* layout_object = node->GetLayoutObject();
633 if (!layout_object)
634 return VisiblePosition();
635
636 RootInlineBox* root = nullptr;
637 InlineBox* box = ComputeInlineBoxPosition(visible_position).inline_box;
638 if (box) {
639 root = box->Root().NextRootBox();
640 // We want to skip zero height boxes.
641 // This could happen in case it is a TrailingFloatsRootInlineBox.
642 if (!root || !root->LogicalHeight() || !root->FirstLeafChild())
643 root = nullptr;
644 }
645
646 if (!root) {
647 // FIXME: We need do the same in previousLinePosition.
648 Node* child = NodeTraversal::ChildAt(*node, p.ComputeEditingOffset());
649 node = child ? child : &NodeTraversal::LastWithinOrSelf(*node);
650 Position position = NextRootInlineBoxCandidatePosition(
651 node, visible_position, editable_type);
652 if (position.IsNotNull()) {
653 RenderedPosition rendered_position((CreateVisiblePosition(position)));
654 root = rendered_position.RootBox();
655 if (!root)
656 return CreateVisiblePosition(position);
657 }
658 }
659
660 if (root) {
661 // FIXME: Can be wrong for multi-column layout and with transforms.
662 LayoutPoint point_in_line = AbsoluteLineDirectionPointToLocalPointInBlock(
663 root, line_direction_point);
664 LineLayoutItem line_layout_item =
665 root->ClosestLeafChildForPoint(point_in_line, IsEditablePosition(p))
666 ->GetLineLayoutItem();
667 Node* node = line_layout_item.GetNode();
668 if (node && EditingIgnoresContent(*node))
669 return VisiblePosition::InParentBeforeNode(*node);
670 return CreateVisiblePosition(
671 line_layout_item.PositionForPoint(point_in_line));
672 }
673
674 // Could not find a next line. This means we must already be on the last line.
675 // Move to the end of the content in this block, which effectively moves us
676 // to the end of the line we're on.
677 Element* root_element = HasEditableStyle(*node, editable_type)
678 ? RootEditableElement(*node, editable_type)
679 : node->GetDocument().documentElement();
680 if (!root_element)
681 return VisiblePosition();
682 return VisiblePosition::LastPositionInNode(root_element);
683 }
684
685 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/editing/VisibleUnits.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698