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

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

Issue 2962143002: [WIP] Find LayoutSelection start/end w/o VisibleSelection. (Closed)
Patch Set: update Created 3 years, 5 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/LayoutSelection.h ('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
1 /* 1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights 3 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights
4 * reserved. 4 * reserved.
5 * 5 *
6 * This library is free software; you can redistribute it and/or 6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Library General Public 7 * modify it under the terms of the GNU Library General Public
8 * License as published by the Free Software Foundation; either 8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version. 9 * version 2 of the License, or (at your option) any later version.
10 * 10 *
11 * This library is distributed in the hope that it will be useful, 11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Library General Public License for more details. 14 * Library General Public License for more details.
15 * 15 *
16 * You should have received a copy of the GNU Library General Public License 16 * You should have received a copy of the GNU Library General Public License
17 * along with this library; see the file COPYING.LIB. If not, write to 17 * along with this library; see the file COPYING.LIB. If not, write to
18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, 18 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19 * Boston, MA 02110-1301, USA. 19 * Boston, MA 02110-1301, USA.
20 */ 20 */
21 21
22 #include "core/editing/LayoutSelection.h" 22 #include "core/editing/LayoutSelection.h"
23 23
24 #include "core/dom/Document.h" 24 #include "core/dom/Document.h"
25 #include "core/editing/EditingUtilities.h" 25 #include "core/editing/EditingUtilities.h"
26 #include "core/editing/FrameSelection.h" 26 #include "core/editing/FrameSelection.h"
27 #include "core/editing/VisiblePosition.h" 27 #include "core/editing/VisiblePosition.h"
28 #include "core/editing/VisibleUnits.h" 28 #include "core/editing/VisibleUnits.h"
29 #include "core/html/TextControlElement.h" 29 #include "core/html/TextControlElement.h"
30 #include "core/layout/LayoutBlock.h"
31 #include "core/layout/LayoutObject.h"
30 #include "core/layout/LayoutView.h" 32 #include "core/layout/LayoutView.h"
31 #include "core/paint/PaintLayer.h" 33 #include "core/paint/PaintLayer.h"
32 34
33 namespace blink { 35 namespace blink {
34 36
35 SelectionPaintRange::SelectionPaintRange(LayoutObject* start_layout_object, 37 SelectionPaintRange::SelectionPaintRange(LayoutObject* start_layout_object,
36 int start_offset, 38 int start_offset,
37 LayoutObject* end_layout_object, 39 LayoutObject* end_layout_object,
38 int end_offset) 40 int end_offset)
39 : start_layout_object_(start_layout_object), 41 : start_layout_object_(start_layout_object),
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
102 104
103 current_ = nullptr; 105 current_ = nullptr;
104 return *this; 106 return *this;
105 } 107 }
106 108
107 LayoutSelection::LayoutSelection(FrameSelection& frame_selection) 109 LayoutSelection::LayoutSelection(FrameSelection& frame_selection)
108 : frame_selection_(&frame_selection), 110 : frame_selection_(&frame_selection),
109 has_pending_selection_(false), 111 has_pending_selection_(false),
110 paint_range_(SelectionPaintRange()) {} 112 paint_range_(SelectionPaintRange()) {}
111 113
114 static bool IsSelectionAtomicAndVisible(LayoutObject* layout_object) {
115 if (!layout_object)
116 return false;
117 // return true;/*
118 if (layout_object->CanBeSelectionLeaf())
119 return true;
120 if (layout_object->IsImage() || layout_object->IsLayoutEmbeddedContent())
121 return true;
122 Node* node = layout_object->GetNode();
123 if (!node || !node->IsHTMLElement())
124 return false;
125 if (isHTMLTableElement(node))
126 return true;
127 if (IsHTMLFormControlElement(ToHTMLElement(*node)) ||
128 isHTMLLegendElement(ToHTMLElement(*node)) ||
129 isHTMLImageElement(ToHTMLElement(*node)) ||
130 isHTMLMeterElement(ToHTMLElement(*node)) ||
131 isHTMLProgressElement(ToHTMLElement(*node)))
132 return true;
133 return false; //*/
134 }
135
136 static Vector<LayoutObject*> GetAncestors(LayoutObject* layout_object) {
137 Vector<LayoutObject*> ancestors;
138 for (LayoutObject* runner = layout_object; runner;) {
139 ancestors.push_back(runner);
140 LayoutObject* next = runner->Parent();
141 if (runner == next)
142 break;
143 runner = next;
144 }
145 return std::move(ancestors);
146 }
147
148 static Optional<int> compare(LayoutObject* a, LayoutObject* b) {
149 if (a == b)
150 return {0};
151 const Vector<LayoutObject*>& a_ancestors = GetAncestors(a);
152 const Vector<LayoutObject*>& b_ancestors = GetAncestors(b);
153 if (a_ancestors[a_ancestors.size() - 1] !=
154 b_ancestors[b_ancestors.size() - 1])
155 return {};
156 LayoutObject* recentAncestor = a_ancestors[a_ancestors.size() - 1];
157 size_t i = 0;
158 for (; i < std::min(a_ancestors.size(), b_ancestors.size()); ++i) {
159 if (a_ancestors[a_ancestors.size() - 1 - i] !=
160 b_ancestors[b_ancestors.size() - 1 - i])
161 break;
162 recentAncestor = a_ancestors[a_ancestors.size() - 1 - i];
163 }
164
165 if (i == a_ancestors.size())
166 return {-1}; // a is ancestor of b
167 if (i == b_ancestors.size())
168 return {1}; // b is ancestor of a
169 LayoutObject* const a_child_of_RA = a_ancestors[a_ancestors.size() - 1 - i];
170 LayoutObject* const b_child_of_RA = b_ancestors[b_ancestors.size() - 1 - i];
171 for (LayoutObject* runner = a_child_of_RA; runner;
172 runner = runner->NextSibling()) {
173 if (runner == b_child_of_RA)
174 return {-1};
175 }
176 return {1};
177 }
178
179 struct SelectionPosition {
180 STACK_ALLOCATED();
181
182 SelectionPosition() : SelectionPosition(nullptr, -1) {}
183 SelectionPosition(LayoutObject* layout_object, int offset)
184 : layout_object_(layout_object), offset_(offset) {}
185
186 SelectionPosition(const PositionInFlatTree& position) : SelectionPosition() {
187 if (position.IsNull())
188 return;
189 layout_object_ = position.AnchorNode()->GetLayoutObject();
190 offset_ = position.ComputeEditingOffset();
191 }
192
193 bool IsNull() const { return !layout_object_; }
194 PositionInFlatTree ToPositionInFlatTree() const {
195 if (IsNull())
196 return PositionInFlatTree();
197 return PositionInFlatTree(layout_object_->GetNode(), offset_);
198 }
199
200 LayoutObject* layout_object_;
201 int offset_;
202
203 bool operator==(const SelectionPosition& other) const {
204 return layout_object_ == other.layout_object_ && offset_ == other.offset_;
205 }
206 bool operator!=(const SelectionPosition& other) const {
207 return !operator==(other);
208 }
209 };
210
211 Node* ComputeNodeAfterPosition(const PositionInFlatTree& position) {
212 if (!position.AnchorNode())
213 return 0;
214
215 switch (position.AnchorType()) {
216 case PositionAnchorType::kBeforeChildren: {
217 if (Node* first_child =
218 FlatTreeTraversal::FirstChild(*position.AnchorNode()))
219 return first_child;
220 FlatTreeTraversal::NextSkippingChildren(*position.AnchorNode());
221 }
222 case PositionAnchorType::kAfterChildren:
223 return FlatTreeTraversal::NextSkippingChildren(*position.AnchorNode());
224 case PositionAnchorType::kOffsetInAnchor: {
225 if (position.AnchorNode()->IsCharacterDataNode())
226 return FlatTreeTraversal::Next(*position.AnchorNode());
227 if (Node* child_at = FlatTreeTraversal::ChildAt(
228 *position.AnchorNode(), position.OffsetInContainerNode()))
229 return child_at;
230 return FlatTreeTraversal::Next(*position.AnchorNode());
231 }
232 case PositionAnchorType::kBeforeAnchor:
233 return position.AnchorNode();
234 case PositionAnchorType::kAfterAnchor:
235 return FlatTreeTraversal::NextSkippingChildren(*position.AnchorNode());
236 }
237 NOTREACHED();
238 return 0;
239 }
240
241 static SelectionPosition FirstLayoutPosition(const PositionInFlatTree& start) {
242 if (start.AnchorNode()->IsTextNode() &&
243 start.AnchorNode()->GetLayoutObject()) {
244 return start;
245 }
246
247 LayoutObject* first_layout_object = nullptr;
248 for (Node* runner = ComputeNodeAfterPosition(start); runner;
249 runner = FlatTreeTraversal::Next(*runner)) {
250 if ((first_layout_object = runner->GetLayoutObject()))
251 break;
252 }
253 if (!first_layout_object)
254 return {};
255
256 for (LayoutObject* runner = first_layout_object; runner;
257 runner = runner->NextInPreOrder()) {
258 if (!IsSelectionAtomicAndVisible(runner))
259 continue;
260
261 return {runner, 0};
262 }
263 return {};
264 }
265
266 // Traverse FlatTree parent first backward.
267 // It looks mirror of Next().
268 static Node* Previous(const Node& node) {
269 if (FlatTreeTraversal::FirstChild(node))
270 return FlatTreeTraversal::LastWithin(node);
271 return FlatTreeTraversal::PreviousSkippingChildren(node);
272 }
273
274 // Traverse FlatTree parent first backward.
275 // It looks mirror of Next().
276 static LayoutObject* Previous(const LayoutObject& layout_object) {
277 if (LayoutObject* last_child = layout_object.SlowLastChild())
278 return last_child;
279 if (LayoutObject* previous_sibling = layout_object.PreviousSibling())
280 return previous_sibling;
281 for (LayoutObject* ancestor = layout_object.Parent(); ancestor;) {
282 LayoutObject* ancestor_prev_sib = ancestor->PreviousSibling();
283 if (ancestor_prev_sib)
284 return ancestor_prev_sib;
285 LayoutObject* parent = layout_object.Parent();
286 // LayoutTests/paint/invalidation/text-selection-rect-in-overflow-2.html
287 // makes infinite self-parent loop. Strange.
288 if (parent == ancestor)
289 return nullptr;
290 ancestor = parent;
291 }
292 return nullptr;
293 }
294
295 static Node* ComputeNodeBeforePosition(const PositionInFlatTree& position) {
296 if (!position.AnchorNode())
297 return nullptr;
298 switch (position.AnchorType()) {
299 case PositionAnchorType::kBeforeChildren:
300 return Previous(*position.AnchorNode());
301 case PositionAnchorType::kAfterChildren: {
302 if (Node* last_child =
303 FlatTreeTraversal::LastChild(*position.AnchorNode()))
304 return last_child;
305 return Previous(*position.AnchorNode());
306 }
307 case PositionAnchorType::kOffsetInAnchor: {
308 if (position.AnchorNode()->IsCharacterDataNode())
309 return Previous(*position.AnchorNode());
310 if (position.OffsetInContainerNode() == 0)
311 return Previous(*position.AnchorNode());
312 Node* child_before_offset = FlatTreeTraversal::ChildAt(
313 *position.AnchorNode(), position.OffsetInContainerNode() - 1);
314 return child_before_offset;
315 }
316 case PositionAnchorType::kBeforeAnchor:
317 return Previous(*position.AnchorNode());
318 case PositionAnchorType::kAfterAnchor:
319 return position.AnchorNode();
320 }
321 NOTREACHED();
322 return 0;
323 }
324
325 static SelectionPosition LastLayoutPosition(const PositionInFlatTree& end) {
326 if (end.AnchorNode()->IsTextNode() && end.AnchorNode()->GetLayoutObject()) {
327 return end;
328 }
329
330 LayoutObject* last_layout_object = nullptr;
331 for (Node* runner = ComputeNodeBeforePosition(end); runner;
332 runner = Previous(*runner)) {
333 if ((last_layout_object = runner->GetLayoutObject()))
334 break;
335 }
336 if (!last_layout_object)
337 return {};
338
339 for (LayoutObject* runner = last_layout_object; runner;
340 runner = Previous(*runner)) {
341 if (!IsSelectionAtomicAndVisible(runner))
342 continue;
343 if (Node* node = runner->GetNode()) {
344 if (node->IsTextNode()) {
345 return {runner, (int)ToText(runner->GetNode())->data().length()};
346 }
347 }
348
349 return {runner, 1};
350 }
351 return PositionInFlatTree();
352 }
353
354 static SelectionPosition ComputeStartRespectingGranularity(
355 const PositionInFlatTree passed_start,
356 TextGranularity granularity) {
357 DCHECK(passed_start.IsNotNull());
358
359 switch (granularity) {
360 case kCharacterGranularity:
361 // Don't do any expansion.
362 return FirstLayoutPosition(passed_start);
363 case kWordGranularity: {
364 // General case: Select the word the caret is positioned inside of.
365 // If the caret is on the word boundary, select the word according to
366 // |wordSide|.
367 // Edge case: If the caret is after the last word in a soft-wrapped line
368 // or the last word in the document, select that last word
369 // (LeftWordIfOnBoundary).
370 // Edge case: If the caret is after the last word in a paragraph, select
371 // from the the end of the last word to the line break (also
372 // RightWordIfOnBoundary);
373 const VisiblePositionInFlatTree& visible_start =
374 CreateVisiblePosition(passed_start);
375 if (IsEndOfEditableOrNonEditableContent(visible_start) ||
376 (IsEndOfLine(visible_start) && !IsStartOfLine(visible_start) &&
377 !IsEndOfParagraph(visible_start))) {
378 return StartOfWord(visible_start, kLeftWordIfOnBoundary)
379 .DeepEquivalent();
380 }
381 return StartOfWord(visible_start, kRightWordIfOnBoundary)
382 .DeepEquivalent();
383 }
384 case kLineGranularity:
385 return StartOfLine(CreateVisiblePosition(passed_start)).DeepEquivalent();
386 case kParagraphGranularity: {
387 const VisiblePositionInFlatTree pos = CreateVisiblePosition(passed_start);
388 if (IsStartOfLine(pos) && IsEndOfEditableOrNonEditableContent(pos))
389 return StartOfParagraph(PreviousPositionOf(pos)).DeepEquivalent();
390 return StartOfParagraph(pos).DeepEquivalent();
391 }
392 default:
393 break;
394 }
395
396 NOTREACHED();
397 return PositionInFlatTree();
398 }
399
400 static SelectionPosition ComputeEndRespectingGranularity(
401 const PositionInFlatTree& start,
402 const PositionInFlatTree& passed_end,
403 TextGranularity granularity) {
404 DCHECK(passed_end.IsNotNull());
405
406 switch (granularity) {
407 case kCharacterGranularity:
408 // Don't do any expansion.
409 return LastLayoutPosition(passed_end);
410 case kWordGranularity: {
411 // General case: Select the word the caret is positioned inside of.
412 // If the caret is on the word boundary, select the word according to
413 // |wordSide|.
414 // Edge case: If the caret is after the last word in a soft-wrapped line
415 // or the last word in the document, select that last word
416 // (|LeftWordIfOnBoundary|).
417 // Edge case: If the caret is after the last word in a paragraph, select
418 // from the the end of the last word to the line break (also
419 // |RightWordIfOnBoundary|);
420 const VisiblePositionInFlatTree& original_end =
421 CreateVisiblePosition(passed_end);
422 EWordSide side = kRightWordIfOnBoundary;
423 if (IsEndOfEditableOrNonEditableContent(original_end) ||
424 (IsEndOfLine(original_end) && !IsStartOfLine(original_end) &&
425 !IsEndOfParagraph(original_end)))
426 side = kLeftWordIfOnBoundary;
427
428 const VisiblePositionInFlatTree& word_end = EndOfWord(original_end, side);
429 if (!IsEndOfParagraph(original_end))
430 return word_end.DeepEquivalent();
431 if (IsEmptyTableCell(start.AnchorNode()))
432 return word_end.DeepEquivalent();
433
434 // Select the paragraph break (the space from the end of a paragraph
435 // to the start of the next one) to match TextEdit.
436 const VisiblePositionInFlatTree& end = NextPositionOf(word_end);
437 Element* const table = TableElementJustBefore(end);
438 if (!table) {
439 if (end.IsNull())
440 return word_end.DeepEquivalent();
441 return end.DeepEquivalent();
442 }
443
444 if (!IsEnclosingBlock(table))
445 return word_end.DeepEquivalent();
446
447 // The paragraph break after the last paragraph in the last cell
448 // of a block table ends at the start of the paragraph after the
449 // table.
450 const VisiblePositionInFlatTree next =
451 NextPositionOf(end, kCannotCrossEditingBoundary);
452 if (next.IsNull())
453 return word_end.DeepEquivalent();
454 return next.DeepEquivalent();
455 }
456 case kLineGranularity: {
457 const VisiblePositionInFlatTree& end =
458 EndOfLine(CreateVisiblePosition(passed_end));
459 if (!IsEndOfParagraph(end))
460 return end.DeepEquivalent();
461 // If the end of this line is at the end of a paragraph, include the
462 // space after the end of the line in the selection.
463 const VisiblePositionInFlatTree& next = NextPositionOf(end);
464 if (next.IsNull())
465 return end.DeepEquivalent();
466 return next.DeepEquivalent();
467 }
468 case kParagraphGranularity: {
469 const VisiblePositionInFlatTree& visible_paragraph_end =
470 EndOfParagraph(CreateVisiblePosition(passed_end));
471
472 // Include the "paragraph break" (the space from the end of this
473 // paragraph to the start of the next one) in the selection.
474 const VisiblePositionInFlatTree& end =
475 NextPositionOf(visible_paragraph_end);
476
477 Element* const table = TableElementJustBefore(end);
478 if (!table) {
479 if (end.IsNull())
480 return visible_paragraph_end.DeepEquivalent();
481 return end.DeepEquivalent();
482 }
483
484 if (!IsEnclosingBlock(table)) {
485 // There is no paragraph break after the last paragraph in the
486 // last cell of an inline table.
487 return visible_paragraph_end.DeepEquivalent();
488 }
489
490 // The paragraph break after the last paragraph in the last cell of
491 // a block table ends at the start of the paragraph after the table,
492 // not at the position just after the table.
493 const VisiblePositionInFlatTree& next =
494 NextPositionOf(end, kCannotCrossEditingBoundary);
495 if (next.IsNull())
496 return visible_paragraph_end.DeepEquivalent();
497 return next.DeepEquivalent();
498 }
499 default:
500 break;
501 }
502 NOTREACHED();
503 return PositionInFlatTree();
504 }
505
112 static bool ShouldShowBlockCursor(const FrameSelection& frame_selection, 506 static bool ShouldShowBlockCursor(const FrameSelection& frame_selection,
113 const VisibleSelectionInFlatTree& selection) { 507 const SelectionPosition& start,
508 const SelectionPosition& end) {
114 if (!frame_selection.ShouldShowBlockCursor()) 509 if (!frame_selection.ShouldShowBlockCursor())
115 return false; 510 return false;
116 if (selection.GetSelectionType() != SelectionType::kCaretSelection) 511 if (start != end)
117 return false; 512 return false;
118 if (IsLogicalEndOfLine(selection.VisibleEnd())) 513 if (IsLogicalEndOfLine(CreateVisiblePosition(start.ToPositionInFlatTree())))
119 return false; 514 return false;
120 return true; 515 return true;
121 } 516 }
122 517
123 static VisibleSelectionInFlatTree CalcSelection( 518 #define MYDEBUG
519
520 #ifdef MYDEBUG
521 static VisibleSelectionInFlatTree createFromDOM(
522 const SelectionInDOMTree& selection_) {
523 SelectionInFlatTree::Builder builder;
524 const PositionInFlatTree& base = ToPositionInFlatTree(selection_.Base());
525 const PositionInFlatTree& extent = ToPositionInFlatTree(selection_.Extent());
526 if (base.IsNotNull() && extent.IsNotNull())
527 builder.SetBaseAndExtent(base, extent);
528 else if (base.IsNotNull())
529 builder.Collapse(base);
530 else if (extent.IsNotNull())
531 builder.Collapse(extent);
532 builder.SetAffinity(selection_.Affinity())
533 .SetHasTrailingWhitespace(selection_.HasTrailingWhitespace())
534 .SetGranularity(selection_.Granularity())
535 .SetIsDirectional(selection_.IsDirectional());
536 return CreateVisibleSelection(builder.Build());
537 }
538 #endif
539
540 static std::pair<SelectionPosition, SelectionPosition> CalcSelection(
124 const FrameSelection& frame_selection) { 541 const FrameSelection& frame_selection) {
542 const SelectionInDOMTree& selection_in_dom =
543 frame_selection.GetSelectionInDOMTree();
544 #ifdef MYDEBUG
125 const VisibleSelectionInFlatTree& original_selection = 545 const VisibleSelectionInFlatTree& original_selection =
126 frame_selection.ComputeVisibleSelectionInFlatTree(); 546 createFromDOM(selection_in_dom);
127 547 const SelectionPosition original_start = original_selection.Start();
128 if (!ShouldShowBlockCursor(frame_selection, original_selection)) 548 const SelectionPosition original_end = original_selection.End();
129 return original_selection; 549 DCHECK(original_start.IsNull() || original_end.IsNull() ||
130 550 original_selection.IsNone() || true);
131 const PositionInFlatTree end_position = NextPositionOf( 551 #endif
132 original_selection.Start(), PositionMoveType::kGraphemeCluster); 552
133 return CreateVisibleSelection( 553 const PositionInFlatTree& base =
134 SelectionInFlatTree::Builder() 554 ToPositionInFlatTree(selection_in_dom.Base());
135 .SetBaseAndExtent(original_selection.Start(), end_position) 555 const PositionInFlatTree& extent =
136 .Build()); 556 ToPositionInFlatTree(selection_in_dom.Extent());
557 const bool is_base_first = base <= extent;
558 const PositionInFlatTree& start = is_base_first ? base : extent;
559 const PositionInFlatTree& end = is_base_first ? extent : base;
560 DCHECK_LE(start, end);
561 if (start.IsNull() || end.IsNull())
562 return {PositionInFlatTree(), PositionInFlatTree()};
563
564 SelectionPosition start_mod_granularity = start;
565 SelectionPosition end_mod_granularity = end;
566 if (selection_in_dom.Granularity() != kCharacterGranularity || start != end) {
567 start_mod_granularity = ComputeStartRespectingGranularity(
568 start, selection_in_dom.Granularity());
569 end_mod_granularity = ComputeEndRespectingGranularity(
570 start, end, selection_in_dom.Granularity());
571 }
572 // #define USE_ORIGINAL
573 #ifdef USE_ORIGINAL
574 start_mod_granularity = original_start;
575 end_mod_granularity = original_end;
576 #else
577 if (start_mod_granularity.IsNull() || end_mod_granularity.IsNull())
578 return {PositionInFlatTree(), PositionInFlatTree()};
579 Optional<int> comp = compare(start_mod_granularity.layout_object_,
580 end_mod_granularity.layout_object_);
581 DCHECK(comp.has_value());
582 if (comp.value() > 0)
583 end_mod_granularity = start_mod_granularity;
584 #endif
585 // DCHECK_LE(start_mod_granularity, end_mod_granularity);
586 /*const PositionInFlatTree& start_most_forward =
587 MostForwardCaretPosition(start_mod_granularity); const PositionInFlatTree&
588 end_most_backward = MostBackwardCaretPosition(end_mod_granularity);*/
589 if (!ShouldShowBlockCursor(frame_selection, start_mod_granularity,
590 end_mod_granularity))
591 return {start_mod_granularity, end_mod_granularity};
592
593 const PositionInFlatTree end_position =
594 NextPositionOf(start, PositionMoveType::kGraphemeCluster);
595 return {start, end_position};
137 } 596 }
138 597
139 // Objects each have a single selection rect to examine. 598 // Objects each have a single selection rect to examine.
140 using SelectedObjectMap = HashMap<LayoutObject*, SelectionState>; 599 using SelectedObjectMap = HashMap<LayoutObject*, SelectionState>;
141 // Blocks contain selected objects and fill gaps between them, either on the 600 // Blocks contain selected objects and fill gaps between them, either on the
142 // left, right, or in between lines and blocks. 601 // left, right, or in between lines and blocks.
143 // In order to get the visual rect right, we have to examine left, middle, and 602 // In order to get the visual rect right, we have to examine left, middle, and
144 // right rects individually, since otherwise the union of those rects might 603 // right rects individually, since otherwise the union of those rects might
145 // remain the same even when changes have occurred. 604 // remain the same even when changes have occurred.
146 using SelectedBlockMap = HashMap<LayoutBlock*, SelectionState>; 605 using SelectedBlockMap = HashMap<LayoutBlock*, SelectionState>;
(...skipping 143 matching lines...) Expand 10 before | Expand all | Expand 10 after
290 paint_range_ = SelectionPaintRange(); 749 paint_range_ = SelectionPaintRange();
291 } 750 }
292 751
293 static SelectionPaintRange CalcSelectionPaintRange( 752 static SelectionPaintRange CalcSelectionPaintRange(
294 const FrameSelection& frame_selection) { 753 const FrameSelection& frame_selection) {
295 const SelectionInDOMTree& selection_in_dom = 754 const SelectionInDOMTree& selection_in_dom =
296 frame_selection.GetSelectionInDOMTree(); 755 frame_selection.GetSelectionInDOMTree();
297 if (selection_in_dom.IsNone()) 756 if (selection_in_dom.IsNone())
298 return SelectionPaintRange(); 757 return SelectionPaintRange();
299 758
300 const VisibleSelectionInFlatTree& selection = CalcSelection(frame_selection); 759 const std::pair<SelectionPosition, SelectionPosition>& selection =
301 if (!selection.IsRange() || frame_selection.IsHidden()) 760 CalcSelection(frame_selection);
761 const SelectionPosition& start_pos = selection.first;
762 const SelectionPosition& end_pos = selection.second;
763 if (start_pos == end_pos || frame_selection.IsHidden())
302 return SelectionPaintRange(); 764 return SelectionPaintRange();
303 765
304 DCHECK(!selection.IsNone()); 766 // DCHECK_LE(start_pos, end_pos);
305 const PositionInFlatTree start_pos = selection.Start(); 767 LayoutObject* start_layout_object = start_pos.layout_object_;
306 const PositionInFlatTree end_pos = selection.End(); 768 LayoutObject* end_layout_object = end_pos.layout_object_;
307 DCHECK_LE(start_pos, end_pos);
308 LayoutObject* start_layout_object = start_pos.AnchorNode()->GetLayoutObject();
309 LayoutObject* end_layout_object = end_pos.AnchorNode()->GetLayoutObject();
310 DCHECK(start_layout_object); 769 DCHECK(start_layout_object);
311 DCHECK(end_layout_object); 770 DCHECK(end_layout_object);
312 DCHECK(start_layout_object->View() == end_layout_object->View()); 771 DCHECK(start_layout_object->View() == end_layout_object->View());
313 772
314 return SelectionPaintRange(start_layout_object, 773 return SelectionPaintRange(start_layout_object, start_pos.offset_,
315 start_pos.ComputeEditingOffset(), 774 end_layout_object, end_pos.offset_);
316 end_layout_object, end_pos.ComputeEditingOffset());
317 } 775 }
318 776
319 void LayoutSelection::Commit() { 777 void LayoutSelection::Commit() {
320 if (!HasPendingSelection()) 778 if (!HasPendingSelection())
321 return; 779 return;
322 has_pending_selection_ = false; 780 has_pending_selection_ = false;
323 781
324 const SelectionPaintRange& new_range = 782 const SelectionPaintRange& new_range =
325 CalcSelectionPaintRange(*frame_selection_); 783 CalcSelectionPaintRange(*frame_selection_);
326 if (new_range.IsNull()) { 784 if (new_range.IsNull()) {
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
378 836
379 runner->SetShouldInvalidateSelection(); 837 runner->SetShouldInvalidateSelection();
380 } 838 }
381 } 839 }
382 840
383 DEFINE_TRACE(LayoutSelection) { 841 DEFINE_TRACE(LayoutSelection) {
384 visitor->Trace(frame_selection_); 842 visitor->Trace(frame_selection_);
385 } 843 }
386 844
387 } // namespace blink 845 } // namespace blink
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/editing/LayoutSelection.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698