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

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

Issue 2913773002: [WIP][b:eae_mywip_paint] Paint Selection NG.
Patch Set: update 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
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 *
(...skipping 10 matching lines...) Expand all
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/LayoutView.h" 30 #include "core/layout/LayoutView.h"
31 #include "core/layout/ng/inline/ng_inline_items_builder.h"
32 #include "core/layout/ng/inline/ng_inline_node.h"
33 #include "core/layout/ng/inline/ng_inline_node_data.h"
34 #include "core/layout/ng/layout_ng_block_flow.h"
31 #include "core/paint/PaintLayer.h" 35 #include "core/paint/PaintLayer.h"
32 36
33 namespace blink { 37 namespace blink {
34 38
35 SelectionPaintRange::SelectionPaintRange(LayoutObject* start_layout_object, 39 SelectionPaintRange::SelectionPaintRange(LayoutObject* start_layout_object,
36 int start_offset, 40 int start_offset,
37 LayoutObject* end_layout_object, 41 LayoutObject* end_layout_object,
38 int end_offset) 42 int end_offset)
39 : start_layout_object_(start_layout_object), 43 : start_layout_object_(start_layout_object),
40 start_offset_(start_offset), 44 start_offset_(start_offset),
41 end_layout_object_(end_layout_object), 45 end_layout_object_(end_layout_object),
42 end_offset_(end_offset) { 46 end_offset_(end_offset) {
43 DCHECK(start_layout_object_); 47 DCHECK(start_layout_object_);
44 DCHECK(end_layout_object_); 48 DCHECK(end_layout_object_);
45 if (start_layout_object_ != end_layout_object_) 49 if (start_layout_object_ != end_layout_object_)
46 return; 50 return;
47 DCHECK_LT(start_offset_, end_offset_); 51 DCHECK_LT(start_offset_, end_offset_);
48 } 52 }
49 53
50 bool SelectionPaintRange::operator==(const SelectionPaintRange& other) const { 54 bool SelectionPaintRange::operator==(const SelectionPaintRange& other) const {
51 return start_layout_object_ == other.start_layout_object_ && 55 return start_layout_object_ == other.start_layout_object_ &&
52 start_offset_ == other.start_offset_ && 56 start_offset_ == other.start_offset_ &&
53 end_layout_object_ == other.end_layout_object_ && 57 end_layout_object_ == other.end_layout_object_ &&
54 end_offset_ == other.end_offset_; 58 end_offset_ == other.end_offset_;
55 } 59 }
56 60
57 LayoutObject* SelectionPaintRange::StartLayoutObject() const { 61 LayoutObject* SelectionPaintRange::StartLayoutObject() const {
58 DCHECK(!IsNull());
59 return start_layout_object_; 62 return start_layout_object_;
60 } 63 }
61 64
62 int SelectionPaintRange::StartOffset() const { 65 int SelectionPaintRange::StartOffset() const {
63 DCHECK(!IsNull());
64 return start_offset_; 66 return start_offset_;
65 } 67 }
66 68
67 LayoutObject* SelectionPaintRange::EndLayoutObject() const { 69 LayoutObject* SelectionPaintRange::EndLayoutObject() const {
68 DCHECK(!IsNull());
69 return end_layout_object_; 70 return end_layout_object_;
70 } 71 }
71 72
72 int SelectionPaintRange::EndOffset() const { 73 int SelectionPaintRange::EndOffset() const {
73 DCHECK(!IsNull());
74 return end_offset_; 74 return end_offset_;
75 } 75 }
76 76
77 LayoutSelection::LayoutSelection(FrameSelection& frame_selection) 77 LayoutSelection::LayoutSelection(FrameSelection& frame_selection)
78 : frame_selection_(&frame_selection), 78 : frame_selection_(&frame_selection),
79 has_pending_selection_(false), 79 has_pending_selection_(false),
80 paint_range_(SelectionPaintRange()) {} 80 paint_range_(nullptr) {}
81 81
82 static SelectionInFlatTree CalcSelection( 82 static SelectionInFlatTree CalcSelection(
83 const VisibleSelectionInFlatTree& original_selection, 83 const VisibleSelectionInFlatTree& original_selection,
84 bool should_show_blok_cursor) { 84 bool should_show_blok_cursor) {
85 const PositionInFlatTree& start = original_selection.Start(); 85 const PositionInFlatTree& start = original_selection.Start();
86 const PositionInFlatTree& end = original_selection.End(); 86 const PositionInFlatTree& end = original_selection.End();
87 SelectionType selection_type = original_selection.GetSelectionType(); 87 SelectionType selection_type = original_selection.GetSelectionType();
88 const TextAffinity affinity = original_selection.Affinity(); 88 const TextAffinity affinity = original_selection.Affinity();
89 89
90 bool paint_block_cursor = 90 bool paint_block_cursor =
(...skipping 72 matching lines...) Expand 10 before | Expand all | Expand 10 after
163 DISALLOW_COPY_AND_ASSIGN(SelectedMap); 163 DISALLOW_COPY_AND_ASSIGN(SelectedMap);
164 }; 164 };
165 165
166 enum class CollectSelectedMapOption { 166 enum class CollectSelectedMapOption {
167 kCollectBlock, 167 kCollectBlock,
168 kNotCollectBlock, 168 kNotCollectBlock,
169 }; 169 };
170 170
171 static SelectedMap CollectSelectedMap(const SelectionPaintRange& range, 171 static SelectedMap CollectSelectedMap(const SelectionPaintRange& range,
172 CollectSelectedMapOption option) { 172 CollectSelectedMapOption option) {
173 if (range.IsNull())
174 return SelectedMap();
175
176 SelectedMap selected_map; 173 SelectedMap selected_map;
177 174
178 LayoutObject* const stop = 175 LayoutObject* const stop =
179 LayoutObjectAfterPosition(range.EndLayoutObject(), range.EndOffset()); 176 LayoutObjectAfterPosition(range.EndLayoutObject(), range.EndOffset());
180 for (LayoutObject* runner = range.StartLayoutObject(); 177 for (LayoutObject* runner = range.StartLayoutObject();
181 runner && (runner != stop); runner = runner->NextInPreOrder()) { 178 runner && (runner != stop); runner = runner->NextInPreOrder()) {
182 if (!runner->CanBeSelectionLeaf() && runner != range.StartLayoutObject() && 179 if (!runner->CanBeSelectionLeaf() && runner != range.StartLayoutObject() &&
183 runner != range.EndLayoutObject()) 180 runner != range.EndLayoutObject())
184 continue; 181 continue;
185 if (runner->GetSelectionState() == SelectionState::kNone) 182 if (runner->GetSelectionState() == SelectionState::kNone)
(...skipping 11 matching lines...) Expand all
197 break; 194 break;
198 containing_block = containing_block->ContainingBlock(); 195 containing_block = containing_block->ContainingBlock();
199 } 196 }
200 } 197 }
201 } 198 }
202 return selected_map; 199 return selected_map;
203 } 200 }
204 201
205 // Update the selection status of all LayoutObjects between |start| and |end|. 202 // Update the selection status of all LayoutObjects between |start| and |end|.
206 static void SetSelectionState(const SelectionPaintRange& range) { 203 static void SetSelectionState(const SelectionPaintRange& range) {
207 if (range.IsNull())
208 return;
209
210 if (range.StartLayoutObject() == range.EndLayoutObject()) { 204 if (range.StartLayoutObject() == range.EndLayoutObject()) {
211 range.StartLayoutObject()->SetSelectionStateIfNeeded( 205 range.StartLayoutObject()->SetSelectionStateIfNeeded(
212 SelectionState::kStartAndEnd); 206 SelectionState::kStartAndEnd);
213 } else { 207 } else {
214 range.StartLayoutObject()->SetSelectionStateIfNeeded( 208 range.StartLayoutObject()->SetSelectionStateIfNeeded(
215 SelectionState::kStart); 209 SelectionState::kStart);
216 range.EndLayoutObject()->SetSelectionStateIfNeeded(SelectionState::kEnd); 210 range.EndLayoutObject()->SetSelectionStateIfNeeded(SelectionState::kEnd);
217 } 211 }
218 212
219 LayoutObject* const stop = 213 LayoutObject* const stop =
220 LayoutObjectAfterPosition(range.EndLayoutObject(), range.EndOffset()); 214 LayoutObjectAfterPosition(range.EndLayoutObject(), range.EndOffset());
221 for (LayoutObject* runner = range.StartLayoutObject(); 215 for (LayoutObject* runner = range.StartLayoutObject();
222 runner && runner != stop; runner = runner->NextInPreOrder()) { 216 runner && runner != stop; runner = runner->NextInPreOrder()) {
223 if (runner != range.StartLayoutObject() && 217 if (runner != range.StartLayoutObject() &&
224 runner != range.EndLayoutObject() && runner->CanBeSelectionLeaf()) 218 runner != range.EndLayoutObject() && runner->CanBeSelectionLeaf())
225 runner->SetSelectionStateIfNeeded(SelectionState::kInside); 219 runner->SetSelectionStateIfNeeded(SelectionState::kInside);
226 } 220 }
227 } 221 }
228 222
229 // Set SetSelectionState and ShouldInvalidateSelection flag of LayoutObjects 223 // Set SetSelectionState and ShouldInvalidateSelection flag of LayoutObjects
230 // comparing them in |new_range| and |old_range|. 224 // comparing them in |new_range| and |old_range|.
231 static void UpdateLayoutObjectState(const SelectionPaintRange& new_range, 225 static void UpdateLayoutObjectState(const SelectionPaintRange& new_range,
232 const SelectionPaintRange& old_range) { 226 const SelectionPaintRange* old_range) {
233 SelectedMap old_selected_map = 227 SelectedMap old_selected_map =
234 CollectSelectedMap(old_range, CollectSelectedMapOption::kCollectBlock); 228 old_range ? CollectSelectedMap(*old_range,
229 CollectSelectedMapOption::kCollectBlock)
230 : SelectedMap();
235 231
236 // Now clear the selection. 232 // Now clear the selection.
237 for (auto layout_object : old_selected_map.object_map.Keys()) 233 for (auto layout_object : old_selected_map.object_map.Keys())
238 layout_object->SetSelectionStateIfNeeded(SelectionState::kNone); 234 layout_object->SetSelectionStateIfNeeded(SelectionState::kNone);
239 235
240 SetSelectionState(new_range); 236 SetSelectionState(new_range);
241 237
242 // Now that the selection state has been updated for the new objects, walk 238 // Now that the selection state has been updated for the new objects, walk
243 // them again and put them in the new objects list. 239 // them again and put them in the new objects list.
244 // TODO(editing-dev): |new_selected_map| doesn't really need to store the 240 // TODO(editing-dev): |new_selected_map| doesn't really need to store the
245 // SelectionState, it's just more convenient to have it use the same data 241 // SelectionState, it's just more convenient to have it use the same data
246 // structure as |old_selected_map|. 242 // structure as |old_selected_map|.
247 SelectedMap new_selected_map = 243 SelectedMap new_selected_map =
248 CollectSelectedMap(new_range, CollectSelectedMapOption::kCollectBlock); 244 CollectSelectedMap(new_range, CollectSelectedMapOption::kCollectBlock);
249 245
250 // Have any of the old selected objects changed compared to the new selection? 246 // Have any of the old selected objects changed compared to the new selection?
251 for (const auto& pair : old_selected_map.object_map) { 247 for (const auto& pair : old_selected_map.object_map) {
252 LayoutObject* obj = pair.key; 248 LayoutObject* obj = pair.key;
253 SelectionState new_selection_state = obj->GetSelectionState(); 249 SelectionState new_selection_state = obj->GetSelectionState();
254 SelectionState old_selection_state = pair.value; 250 SelectionState old_selection_state = pair.value;
255 if (new_selection_state != old_selection_state || 251 if (new_selection_state != old_selection_state ||
256 (new_range.StartLayoutObject() == obj && 252 (new_range.StartLayoutObject() == obj &&
257 new_range.StartOffset() != old_range.StartOffset()) || 253 new_range.StartOffset() != old_range->StartOffset()) ||
258 (new_range.EndLayoutObject() == obj && 254 (new_range.EndLayoutObject() == obj &&
259 new_range.EndOffset() != old_range.EndOffset())) { 255 new_range.EndOffset() != old_range->EndOffset())) {
260 obj->SetShouldInvalidateSelection(); 256 obj->SetShouldInvalidateSelection();
261 new_selected_map.object_map.erase(obj); 257 new_selected_map.object_map.erase(obj);
262 } 258 }
263 } 259 }
264 260
265 // Any new objects that remain were not found in the old objects dict, and so 261 // Any new objects that remain were not found in the old objects dict, and so
266 // they need to be updated. 262 // they need to be updated.
267 for (auto layout_object : new_selected_map.object_map.Keys()) 263 for (auto layout_object : new_selected_map.object_map.Keys())
268 layout_object->SetShouldInvalidateSelection(); 264 layout_object->SetShouldInvalidateSelection();
269 265
270 // Have any of the old blocks changed? 266 // Have any of the old blocks changed?
271 for (const auto& pair : old_selected_map.block_map) { 267 for (const auto& pair : old_selected_map.block_map) {
272 LayoutBlock* block = pair.key; 268 LayoutBlock* block = pair.key;
273 SelectionState new_selection_state = block->GetSelectionState(); 269 SelectionState new_selection_state = block->GetSelectionState();
274 SelectionState old_selection_state = pair.value; 270 SelectionState old_selection_state = pair.value;
275 if (new_selection_state != old_selection_state) { 271 if (new_selection_state != old_selection_state) {
276 block->SetShouldInvalidateSelection(); 272 block->SetShouldInvalidateSelection();
277 new_selected_map.block_map.erase(block); 273 new_selected_map.block_map.erase(block);
278 } 274 }
279 } 275 }
280 276
281 // Any new blocks that remain were not found in the old blocks dict, and so 277 // Any new blocks that remain were not found in the old blocks dict, and so
282 // they need to be updated. 278 // they need to be updated.
283 for (auto layout_object : new_selected_map.block_map.Keys()) 279 for (auto layout_object : new_selected_map.block_map.Keys())
284 layout_object->SetShouldInvalidateSelection(); 280 layout_object->SetShouldInvalidateSelection();
285 } 281 }
286 282
283 static LayoutBlockFlow* MostRecentLayoutBlockFlow(LayoutObject* layout_object) {
284 for (LayoutObject* runner = layout_object; runner && !runner->IsLayoutView();
285 runner = runner->ContainingBlock()) {
kojii 2017/06/16 11:25:56 why ContainingBlock(), not Parent()?
yoichio 2017/06/21 08:16:43 Perhaps its my misunderstanding. If LayoutBlockFlo
286 if (runner->IsLayoutBlockFlow())
287 return ToLayoutBlockFlow(runner);
288 }
289 return nullptr;
290 }
291
292 static int GetOffsetInMixedTree(Node* node,
293 LayoutObject* layout_object,
294 int offset) {
295 LayoutBlockFlow* start_block_flow = MostRecentLayoutBlockFlow(layout_object);
296 if (!start_block_flow || !start_block_flow->IsLayoutNGBlockFlow())
297 return offset; // Legay. Return DOM offset;
yosin_UTC9 2017/06/16 02:04:20 nit: s/Legay/Legacy/
298
299 // TODO(yoichio): How about caching? Create takes
300 // O(<LayoutNGBlockflow.Data.text_content_>).
301 const NGTextOffsetMap& offset_map =
302 NGTextOffsetMap::Create(*ToLayoutNGBlockFlowOrDie(start_block_flow));
303 const Optional<int> ng_offset = offset_map.Get(node, offset);
304 return ng_offset.value();
305 }
306
287 std::pair<int, int> LayoutSelection::SelectionStartEnd() { 307 std::pair<int, int> LayoutSelection::SelectionStartEnd() {
288 Commit(); 308 Commit();
289 if (paint_range_.IsNull()) 309 if (!paint_range_)
290 return std::make_pair(-1, -1); 310 return std::make_pair(-1, -1);
291 return std::make_pair(paint_range_.StartOffset(), paint_range_.EndOffset()); 311 if (!RuntimeEnabledFeatures::LayoutNGEnabled()) {
312 return std::make_pair(paint_range_->StartOffset(),
313 paint_range_->EndOffset());
314 }
315 // Layout NG mapping
316 const int start_offset_mixed = GetOffsetInMixedTree(
317 paint_range_->StartNode(), paint_range_->StartLayoutObject(),
318 paint_range_->StartOffset());
319 const int end_offset_mixed = GetOffsetInMixedTree(
320 paint_range_->EndNode(), paint_range_->EndLayoutObject(),
321 paint_range_->EndOffset());
322 return std::make_pair(start_offset_mixed, end_offset_mixed);
292 } 323 }
293 324
294 void LayoutSelection::ClearSelection() { 325 void LayoutSelection::ClearSelection() {
295 // For querying Layer::compositingState() 326 // For querying Layer::compositingState()
296 // This is correct, since destroying layout objects needs to cause eager paint 327 // This is correct, since destroying layout objects needs to cause eager paint
297 // invalidations. 328 // invalidations.
298 DisableCompositingQueryAsserts disabler; 329 DisableCompositingQueryAsserts disabler;
299 330
300 // Just return if the selection is already empty. 331 // Just return if the selection is already empty.
301 if (paint_range_.IsNull()) 332 if (!paint_range_)
302 return; 333 return;
303 334
304 const SelectedMap& old_selected_map = CollectSelectedMap( 335 const SelectedMap& old_selected_map = CollectSelectedMap(
305 paint_range_, CollectSelectedMapOption::kNotCollectBlock); 336 *paint_range_, CollectSelectedMapOption::kNotCollectBlock);
306 // Clear SelectionState and invalidation. 337 // Clear SelectionState and invalidation.
307 for (auto layout_object : old_selected_map.object_map.Keys()) { 338 for (auto layout_object : old_selected_map.object_map.Keys()) {
308 const SelectionState old_state = layout_object->GetSelectionState(); 339 const SelectionState old_state = layout_object->GetSelectionState();
309 layout_object->SetSelectionStateIfNeeded(SelectionState::kNone); 340 layout_object->SetSelectionStateIfNeeded(SelectionState::kNone);
310 if (layout_object->GetSelectionState() == old_state) 341 if (layout_object->GetSelectionState() == old_state)
311 continue; 342 continue;
312 layout_object->SetShouldInvalidateSelection(); 343 layout_object->SetShouldInvalidateSelection();
313 } 344 }
314 345
315 // Reset selection. 346 // Reset selection.
316 paint_range_ = SelectionPaintRange(); 347 paint_range_ = nullptr;
317 } 348 }
318 349
319 static SelectionPaintRange CalcSelectionPaintRange( 350 static SelectionPaintRange* CalcSelectionNG(
yosin_UTC9 2017/06/15 09:51:27 If this function traverse flat tree and works on l
yoichio 2017/06/21 08:16:42 I will rewrite w/o most.*CaretPosition() functions
320 const FrameSelection& frame_selection) { 351 const FrameSelection& frame_selection) {
352 const SelectionInDOMTree& selection_in_dom =
353 frame_selection.GetSelectionInDOMTree();
354 if (selection_in_dom.IsNone())
355 return nullptr;
356
357 // yoichio: Tthis should be on FlatTree.
358 const Position& start = selection_in_dom.ComputeStartPosition();
yosin_UTC9 2017/06/15 09:39:02 Why don't you use flat tree version?
359 const Position& end = selection_in_dom.ComputeEndPosition();
360 LayoutObject* const start_layout_object =
yosin_UTC9 2017/06/16 02:04:20 |start_layout_object| can be nullptr. So, we need
361 start.AnchorNode()->GetLayoutObject();
362 LayoutObject* const end_layout_object = end.AnchorNode()->GetLayoutObject();
yosin_UTC9 2017/06/16 02:04:20 |end_layout_object_| can be nullptr. So, we need t
363
364 Node* start_node = nullptr;
365 LayoutObject* paint_range_start = nullptr;
366 int paint_range_start_offset = -1;
367 // Seek the first text node.
368 for (LayoutObject* runner = start_layout_object;
369 runner && runner != end_layout_object->NextInPreOrder();
370 runner = runner->NextInPreOrder()) {
371 if (runner->IsText() && runner->GetNode()->IsTextNode()) {
372 start_node = runner->GetNode();
373 paint_range_start = runner;
374 if (runner == start_layout_object) {
375 paint_range_start_offset = start.ComputeEditingOffset();
376 break;
377 }
378 paint_range_start_offset = 0;
379 break;
380 }
381 }
382 DCHECK(paint_range_start);
383 // Should consider block cursor painting.
384 Node* end_node = nullptr;
385 LayoutObject* paint_range_end = nullptr;
386 int paint_range_end_offset = -1;
387 for (LayoutObject* runner = end_layout_object;
388 runner && runner != start_layout_object->PreviousInPreOrder();
389 runner = runner->PreviousInPreOrder()) {
390 if (runner->IsText() && runner->GetNode()->IsTextNode()) {
391 end_node = runner->GetNode();
392 paint_range_end = runner;
393 if (runner == end_layout_object) {
394 paint_range_end_offset = end.ComputeEditingOffset();
395 break;
396 }
397 LayoutText* text = ToLayoutText(runner);
398 paint_range_end_offset = text->TextLength();
399 break;
400 }
401 }
402 DCHECK(paint_range_end);
403
404 return new SelectionPaintRange(start_node, paint_range_start,
405 paint_range_start_offset, end_node,
406 paint_range_end, paint_range_end_offset);
407 }
408 // if(RuntimeEnabledFeatures::LayoutNGEnabled()) {
409
410 static SelectionPaintRange* CalcSelectionPaintRange(
411 const FrameSelection& frame_selection) {
412 if (RuntimeEnabledFeatures::LayoutNGEnabled())
413 return CalcSelectionNG(frame_selection);
yosin_UTC9 2017/06/15 09:39:02 So, for painting selection, we need to have NG ver
414
415 // NGMemo: ComputeVisibleSelectionInFlatTree depends on offsetmapping from
416 // DOM->NG.
321 const VisibleSelectionInFlatTree& original_selection = 417 const VisibleSelectionInFlatTree& original_selection =
322 frame_selection.ComputeVisibleSelectionInFlatTree(); 418 frame_selection.ComputeVisibleSelectionInFlatTree();
323 // Construct a new VisibleSolution, since visibleSelection() is not 419 // Construct a new VisibleSolution, since visibleSelection() is not
324 // necessarily valid, and the following steps assume a valid selection. See 420 // necessarily valid, and the following steps assume a valid selection. See
325 // <https://bugs.webkit.org/show_bug.cgi?id=69563> and 421 // <https://bugs.webkit.org/show_bug.cgi?id=69563> and
326 // <rdar://problem/10232866>. 422 // <rdar://problem/10232866>.
327 const SelectionInFlatTree& new_selection = CalcSelection( 423 const SelectionInFlatTree& new_selection = CalcSelection(
328 original_selection, frame_selection.ShouldShowBlockCursor()); 424 original_selection, frame_selection.ShouldShowBlockCursor());
329 const VisibleSelectionInFlatTree& selection = 425 const VisibleSelectionInFlatTree& selection =
330 CreateVisibleSelection(new_selection); 426 CreateVisibleSelection(new_selection);
331 427
332 if (!selection.IsRange() || frame_selection.IsHidden()) 428 if (!selection.IsRange() || frame_selection.IsHidden())
333 return SelectionPaintRange(); 429 return nullptr;
334 430
335 DCHECK(!selection.IsNone()); 431 DCHECK(!selection.IsNone());
336 // Use the rightmost candidate for the start of the selection, and the 432 // Use the rightmost candidate for the start of the selection, and the
337 // leftmost candidate for the end of the selection. Example: foo <a>bar</a>. 433 // leftmost candidate for the end of the selection. Example: foo <a>bar</a>.
338 // Imagine that a line wrap occurs after 'foo', and that 'bar' is selected. 434 // Imagine that a line wrap occurs after 'foo', and that 'bar' is selected.
339 // If we pass [foo, 3] as the start of the selection, the selection painting 435 // If we pass [foo, 3] as the start of the selection, the selection painting
340 // code will think that content on the line containing 'foo' is selected 436 // code will think that content on the line containing 'foo' is selected
341 // and will fill the gap before 'bar'. 437 // and will fill the gap before 'bar'.
342 PositionInFlatTree start_pos = selection.Start(); 438 PositionInFlatTree start_pos = selection.Start();
343 const PositionInFlatTree most_forward_start = 439 const PositionInFlatTree most_forward_start =
344 MostForwardCaretPosition(start_pos); 440 MostForwardCaretPosition(start_pos);
345 if (IsVisuallyEquivalentCandidate(most_forward_start)) 441 if (IsVisuallyEquivalentCandidate(most_forward_start))
346 start_pos = most_forward_start; 442 start_pos = most_forward_start;
347 PositionInFlatTree end_pos = selection.End(); 443 PositionInFlatTree end_pos = selection.End();
348 const PositionInFlatTree most_backward = MostBackwardCaretPosition(end_pos); 444 const PositionInFlatTree most_backward = MostBackwardCaretPosition(end_pos);
349 if (IsVisuallyEquivalentCandidate(most_backward)) 445 if (IsVisuallyEquivalentCandidate(most_backward))
350 end_pos = most_backward; 446 end_pos = most_backward;
351 447
352 DCHECK(start_pos.IsNotNull()); 448 DCHECK(start_pos.IsNotNull());
353 DCHECK(end_pos.IsNotNull()); 449 DCHECK(end_pos.IsNotNull());
354 DCHECK_LE(start_pos, end_pos); 450 DCHECK_LE(start_pos, end_pos);
355 LayoutObject* start_layout_object = start_pos.AnchorNode()->GetLayoutObject(); 451 LayoutObject* start_layout_object = start_pos.AnchorNode()->GetLayoutObject();
356 LayoutObject* end_layout_object = end_pos.AnchorNode()->GetLayoutObject(); 452 LayoutObject* end_layout_object = end_pos.AnchorNode()->GetLayoutObject();
357 DCHECK(start_layout_object); 453 DCHECK(start_layout_object);
358 DCHECK(end_layout_object); 454 DCHECK(end_layout_object);
359 DCHECK(start_layout_object->View() == end_layout_object->View()); 455 DCHECK(start_layout_object->View() == end_layout_object->View());
360 456
361 return SelectionPaintRange(start_layout_object, 457 return new SelectionPaintRange(
362 start_pos.ComputeEditingOffset(), 458 start_layout_object, start_pos.ComputeEditingOffset(), end_layout_object,
363 end_layout_object, end_pos.ComputeEditingOffset()); 459 end_pos.ComputeEditingOffset());
364 } 460 }
365 461
366 void LayoutSelection::Commit() { 462 void LayoutSelection::Commit() {
367 if (!HasPendingSelection()) 463 if (!HasPendingSelection())
368 return; 464 return;
369 has_pending_selection_ = false; 465 has_pending_selection_ = false;
370 466
371 const SelectionPaintRange& new_range = 467 SelectionPaintRange* new_range = CalcSelectionPaintRange(*frame_selection_);
372 CalcSelectionPaintRange(*frame_selection_); 468 if (!new_range) {
373 if (new_range.IsNull()) {
374 ClearSelection(); 469 ClearSelection();
375 return; 470 return;
376 } 471 }
377 // Just return if the selection hasn't changed. 472 // Just return if the selection hasn't changed.
378 if (paint_range_ == new_range) 473 if (paint_range_ && *paint_range_ == *new_range)
379 return; 474 return;
380 475
381 DCHECK(frame_selection_->GetDocument().GetLayoutView()->GetFrameView()); 476 DCHECK(frame_selection_->GetDocument().GetLayoutView()->GetFrameView());
382 DCHECK(!frame_selection_->GetDocument().NeedsLayoutTreeUpdate()); 477 DCHECK(!frame_selection_->GetDocument().NeedsLayoutTreeUpdate());
383 UpdateLayoutObjectState(new_range, paint_range_); 478 UpdateLayoutObjectState(*new_range, paint_range_);
384 paint_range_ = new_range; 479 paint_range_ = new_range;
385 } 480 }
386 481
387 void LayoutSelection::OnDocumentShutdown() { 482 void LayoutSelection::OnDocumentShutdown() {
388 has_pending_selection_ = false; 483 has_pending_selection_ = false;
389 paint_range_ = SelectionPaintRange(); 484 paint_range_ = nullptr;
390 } 485 }
391 486
392 static LayoutRect SelectionRectForLayoutObject(const LayoutObject* object) { 487 static LayoutRect SelectionRectForLayoutObject(const LayoutObject* object) {
393 if (!object->IsRooted()) 488 if (!object->IsRooted())
394 return LayoutRect(); 489 return LayoutRect();
395 490
396 if (!object->CanUpdateSelectionOnRootLineBoxes()) 491 if (!object->CanUpdateSelectionOnRootLineBoxes())
397 return LayoutRect(); 492 return LayoutRect();
398 493
399 return object->SelectionRectInViewCoordinates(); 494 return object->SelectionRectInViewCoordinates();
400 } 495 }
401 496
402 IntRect LayoutSelection::SelectionBounds() { 497 IntRect LayoutSelection::SelectionBounds() {
403 // Now create a single bounding box rect that encloses the whole selection. 498 // Now create a single bounding box rect that encloses the whole selection.
404 LayoutRect sel_rect; 499 LayoutRect sel_rect;
405 500
406 typedef HashSet<const LayoutBlock*> VisitedContainingBlockSet; 501 typedef HashSet<const LayoutBlock*> VisitedContainingBlockSet;
407 VisitedContainingBlockSet visited_containing_blocks; 502 VisitedContainingBlockSet visited_containing_blocks;
408 503
409 Commit(); 504 Commit();
410 if (paint_range_.IsNull()) 505 if (!paint_range_)
411 return IntRect(); 506 return IntRect();
412 507
413 LayoutObject* os = paint_range_.StartLayoutObject(); 508 LayoutObject* os = paint_range_->StartLayoutObject();
414 LayoutObject* stop = LayoutObjectAfterPosition(paint_range_.EndLayoutObject(), 509 LayoutObject* stop = LayoutObjectAfterPosition(
415 paint_range_.EndOffset()); 510 paint_range_->EndLayoutObject(), paint_range_->EndOffset());
416 while (os && os != stop) { 511 while (os && os != stop) {
417 if ((os->CanBeSelectionLeaf() || os == paint_range_.StartLayoutObject() || 512 if ((os->CanBeSelectionLeaf() || os == paint_range_->StartLayoutObject() ||
418 os == paint_range_.EndLayoutObject()) && 513 os == paint_range_->EndLayoutObject()) &&
419 os->GetSelectionState() != SelectionState::kNone) { 514 os->GetSelectionState() != SelectionState::kNone) {
420 // Blocks are responsible for painting line gaps and margin gaps. They 515 // Blocks are responsible for painting line gaps and margin gaps. They
421 // must be examined as well. 516 // must be examined as well.
422 sel_rect.Unite(SelectionRectForLayoutObject(os)); 517 sel_rect.Unite(SelectionRectForLayoutObject(os));
423 const LayoutBlock* cb = os->ContainingBlock(); 518 const LayoutBlock* cb = os->ContainingBlock();
424 while (cb && !cb->IsLayoutView()) { 519 while (cb && !cb->IsLayoutView()) {
425 sel_rect.Unite(SelectionRectForLayoutObject(cb)); 520 sel_rect.Unite(SelectionRectForLayoutObject(cb));
426 VisitedContainingBlockSet::AddResult add_result = 521 VisitedContainingBlockSet::AddResult add_result =
427 visited_containing_blocks.insert(cb); 522 visited_containing_blocks.insert(cb);
428 if (!add_result.is_new_entry) 523 if (!add_result.is_new_entry)
429 break; 524 break;
430 cb = cb->ContainingBlock(); 525 cb = cb->ContainingBlock();
431 } 526 }
432 } 527 }
433 528
434 os = os->NextInPreOrder(); 529 os = os->NextInPreOrder();
435 } 530 }
436 531
437 return PixelSnappedIntRect(sel_rect); 532 return PixelSnappedIntRect(sel_rect);
438 } 533 }
439 534
440 void LayoutSelection::InvalidatePaintForSelection() { 535 void LayoutSelection::InvalidatePaintForSelection() {
441 if (paint_range_.IsNull()) 536 if (!paint_range_)
442 return; 537 return;
443 538
444 LayoutObject* end = LayoutObjectAfterPosition(paint_range_.EndLayoutObject(), 539 LayoutObject* end = LayoutObjectAfterPosition(paint_range_->EndLayoutObject(),
445 paint_range_.EndOffset()); 540 paint_range_->EndOffset());
446 for (LayoutObject* o = paint_range_.StartLayoutObject(); o && o != end; 541 for (LayoutObject* o = paint_range_->StartLayoutObject(); o && o != end;
447 o = o->NextInPreOrder()) { 542 o = o->NextInPreOrder()) {
448 if (!o->CanBeSelectionLeaf() && o != paint_range_.StartLayoutObject() && 543 if (!o->CanBeSelectionLeaf() && o != paint_range_->StartLayoutObject() &&
449 o != paint_range_.EndLayoutObject()) 544 o != paint_range_->EndLayoutObject())
450 continue; 545 continue;
451 if (o->GetSelectionState() == SelectionState::kNone) 546 if (o->GetSelectionState() == SelectionState::kNone)
452 continue; 547 continue;
453 548
454 o->SetShouldInvalidateSelection(); 549 o->SetShouldInvalidateSelection();
455 } 550 }
456 } 551 }
457 552
458 DEFINE_TRACE(LayoutSelection) { 553 DEFINE_TRACE(LayoutSelection) {
459 visitor->Trace(frame_selection_); 554 visitor->Trace(frame_selection_);
555 visitor->Trace(paint_range_);
556 }
557
558 NGTextOffsetMap::Builder::Builder() : offset_map_(new NGTextOffsetMap) {}
kojii 2017/06/16 11:25:56 so this part will be removed and not for review, c
559
560 void NGTextOffsetMap::Builder::Add(Node* node,
561 int dom_offset,
562 int layout_offset) {
563 DCHECK(node);
564 offset_map_->node_to_offset_map_.Set(std::make_pair(node, dom_offset),
565 layout_offset);
566 }
567
568 NGTextOffsetMap NGTextOffsetMap::Builder::Build() {
569 return std::move(*offset_map_);
570 }
571
572 Optional<int> NGTextOffsetMap::Get(Node* node, int dom_offset) const {
573 if (!node)
574 return Optional<int>();
575 auto iterator = node_to_offset_map_.find(std::make_pair(node, dom_offset));
576 if (iterator == node_to_offset_map_.end())
577 return Optional<int>();
578 return iterator->value;
579 }
580
581 NGTextOffsetMap NGTextOffsetMap::Create(
582 const LayoutNGBlockFlow& ng_block_flow) {
583 NGTextOffsetMap::Builder builder;
584 Vector<NGInlineItem> pseudo_items;
585 Vector<int> offset_mapping;
586 offset_mapping.push_back(0);
587 NGInlineItemsBuilder items_builder(&pseudo_items, &offset_mapping);
588
589 LayoutObject* last_object = nullptr;
590 for (const auto& item : ng_block_flow.GetNGInlineNodeData().items_) {
591 LayoutObject* layout_object = item.GetLayoutObject();
592 if (!layout_object || !layout_object->IsText() ||
593 layout_object == last_object)
594 continue;
595
596 Text* text = ToText(layout_object->GetNode());
597 size_t begin = offset_mapping.size();
598 items_builder.Append(text->textContent(), layout_object->Style(),
599 layout_object);
600 size_t end = offset_mapping.size();
601 for (size_t i = 0; i < end - begin + 1; i++) {
602 int ng_offset = offset_mapping[begin + i - 1];
603 builder.Add(text, i, ng_offset);
604 }
605
606 last_object = layout_object;
607 }
608 return builder.Build();
460 } 609 }
461 610
462 } // namespace blink 611 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698