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

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