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

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

Issue 2813403002: Move LayouetSelection function definition from layout/LayoutView.cpp to editing/LayoutSelection.cpp (Closed)
Patch Set: update Created 3 years, 8 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 | « no previous file | third_party/WebKit/Source/core/layout/LayoutView.cpp » ('j') | 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 *
(...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/paint/PaintLayer.h"
31 32
32 namespace blink { 33 namespace blink {
33 34
34 LayoutSelection::LayoutSelection(FrameSelection& frame_selection) 35 LayoutSelection::LayoutSelection(FrameSelection& frame_selection)
35 : frame_selection_(&frame_selection), 36 : frame_selection_(&frame_selection),
36 has_pending_selection_(false), 37 has_pending_selection_(false),
37 selection_start_(nullptr), 38 selection_start_(nullptr),
38 selection_end_(nullptr), 39 selection_end_(nullptr),
39 selection_start_pos_(-1), 40 selection_start_pos_(-1),
40 selection_end_pos_(-1) {} 41 selection_end_pos_(-1) {}
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after
104 ? TextAffinity::kUpstream 105 ? TextAffinity::kUpstream
105 : affinity); 106 : affinity);
106 if (visible_end.IsNull()) 107 if (visible_end.IsNull())
107 return SelectionInFlatTree(); 108 return SelectionInFlatTree();
108 SelectionInFlatTree::Builder builder; 109 SelectionInFlatTree::Builder builder;
109 builder.Collapse(visible_start.ToPositionWithAffinity()); 110 builder.Collapse(visible_start.ToPositionWithAffinity());
110 builder.Extend(visible_end.DeepEquivalent()); 111 builder.Extend(visible_end.DeepEquivalent());
111 return builder.Build(); 112 return builder.Build();
112 } 113 }
113 114
115 static LayoutObject* LayoutObjectAfterPosition(LayoutObject* object,
116 unsigned offset) {
117 if (!object)
118 return nullptr;
119
120 LayoutObject* child = object->ChildAt(offset);
121 return child ? child : object->NextInPreOrderAfterChildren();
122 }
123
124 // When exploring the LayoutTree looking for the nodes involved in the
125 // Selection, sometimes it's required to change the traversing direction because
126 // the "start" position is below the "end" one.
127 static inline LayoutObject* GetNextOrPrevLayoutObjectBasedOnDirection(
128 const LayoutObject* o,
129 const LayoutObject* stop,
130 bool& continue_exploring,
131 bool& exploring_backwards) {
132 LayoutObject* next;
133 if (exploring_backwards) {
134 next = o->PreviousInPreOrder();
135 continue_exploring = next && !(next)->IsLayoutView();
136 } else {
137 next = o->NextInPreOrder();
138 continue_exploring = next && next != stop;
139 exploring_backwards = !next && (next != stop);
140 if (exploring_backwards) {
141 next = stop->PreviousInPreOrder();
142 continue_exploring = next && !next->IsLayoutView();
143 }
144 }
145
146 return next;
147 }
148
149 void LayoutSelection::SetSelection(
150 LayoutObject* start,
151 int start_pos,
152 LayoutObject* end,
153 int end_pos,
154 SelectionPaintInvalidationMode block_paint_invalidation_mode) {
155 // This code makes no assumptions as to if the layout tree is up to date or
156 // not and will not try to update it. Currently clearSelection calls this
157 // (intentionally) without updating the layout tree as it doesn't care.
158 // Other callers may want to force recalc style before calling this.
159
160 // Make sure both our start and end objects are defined.
161 // Check www.msnbc.com and try clicking around to find the case where this
162 // happened.
163 if ((start && !end) || (end && !start))
164 return;
165
166 // Just return if the selection hasn't changed.
167 if (selection_start_ == start && selection_start_pos_ == start_pos &&
168 selection_end_ == end && selection_end_pos_ == end_pos)
169 return;
170
171 // Record the old selected objects. These will be used later when we compare
172 // against the new selected objects.
173 int old_start_pos = selection_start_pos_;
174 int old_end_pos = selection_end_pos_;
175
176 // Objects each have a single selection rect to examine.
177 typedef HashMap<LayoutObject*, SelectionState> SelectedObjectMap;
178 SelectedObjectMap old_selected_objects;
179 // FIXME: |newSelectedObjects| doesn't really need to store the
180 // SelectionState, it's just more convenient to have it use the same data
181 // structure as |oldSelectedObjects|.
182 SelectedObjectMap new_selected_objects;
183
184 // Blocks contain selected objects and fill gaps between them, either on the
185 // left, right, or in between lines and blocks.
186 // In order to get the visual rect right, we have to examine left, middle, and
187 // right rects individually, since otherwise the union of those rects might
188 // remain the same even when changes have occurred.
189 typedef HashMap<LayoutBlock*, SelectionState> SelectedBlockMap;
190 SelectedBlockMap old_selected_blocks;
191 // FIXME: |newSelectedBlocks| doesn't really need to store the SelectionState,
192 // it's just more convenient to have it use the same data structure as
193 // |oldSelectedBlocks|.
194 SelectedBlockMap new_selected_blocks;
195
196 LayoutObject* os = selection_start_;
197 LayoutObject* stop =
198 LayoutObjectAfterPosition(selection_end_, selection_end_pos_);
199 bool exploring_backwards = false;
200 bool continue_exploring = os && (os != stop);
201 while (continue_exploring) {
202 if ((os->CanBeSelectionLeaf() || os == selection_start_ ||
203 os == selection_end_) &&
204 os->GetSelectionState() != SelectionNone) {
205 // Blocks are responsible for painting line gaps and margin gaps. They
206 // must be examined as well.
207 old_selected_objects.Set(os, os->GetSelectionState());
208 if (block_paint_invalidation_mode == kPaintInvalidationNewXOROld) {
209 LayoutBlock* cb = os->ContainingBlock();
210 while (cb && !cb->IsLayoutView()) {
211 SelectedBlockMap::AddResult result =
212 old_selected_blocks.insert(cb, cb->GetSelectionState());
213 if (!result.is_new_entry)
214 break;
215 cb = cb->ContainingBlock();
216 }
217 }
218 }
219
220 os = GetNextOrPrevLayoutObjectBasedOnDirection(os, stop, continue_exploring,
221 exploring_backwards);
222 }
223
224 // Now clear the selection.
225 SelectedObjectMap::iterator old_objects_end = old_selected_objects.end();
226 for (SelectedObjectMap::iterator i = old_selected_objects.begin();
227 i != old_objects_end; ++i)
228 i->key->SetSelectionStateIfNeeded(SelectionNone);
229
230 // set selection start and end
231 selection_start_ = start;
232 selection_start_pos_ = start_pos;
233 selection_end_ = end;
234 selection_end_pos_ = end_pos;
235
236 // Update the selection status of all objects between m_selectionStart and
237 // m_selectionEnd
238 if (start && start == end) {
239 start->SetSelectionStateIfNeeded(SelectionBoth);
240 } else {
241 if (start)
242 start->SetSelectionStateIfNeeded(SelectionStart);
243 if (end)
244 end->SetSelectionStateIfNeeded(SelectionEnd);
245 }
246
247 LayoutObject* o = start;
248 stop = LayoutObjectAfterPosition(end, end_pos);
249
250 while (o && o != stop) {
251 if (o != start && o != end && o->CanBeSelectionLeaf())
252 o->SetSelectionStateIfNeeded(SelectionInside);
253 o = o->NextInPreOrder();
254 }
255
256 // Now that the selection state has been updated for the new objects, walk
257 // them again and put them in the new objects list.
258 o = start;
259 exploring_backwards = false;
260 continue_exploring = o && (o != stop);
261 while (continue_exploring) {
262 if ((o->CanBeSelectionLeaf() || o == start || o == end) &&
263 o->GetSelectionState() != SelectionNone) {
264 new_selected_objects.Set(o, o->GetSelectionState());
265 LayoutBlock* cb = o->ContainingBlock();
266 while (cb && !cb->IsLayoutView()) {
267 SelectedBlockMap::AddResult result =
268 new_selected_blocks.insert(cb, cb->GetSelectionState());
269 if (!result.is_new_entry)
270 break;
271 cb = cb->ContainingBlock();
272 }
273 }
274
275 o = GetNextOrPrevLayoutObjectBasedOnDirection(o, stop, continue_exploring,
276 exploring_backwards);
277 }
278
279 // TODO(yoichio): DCHECK(frame_selection_->,,,->GetFrameView());
280 if (!frame_selection_->GetDocument().GetLayoutView()->GetFrameView())
281 return;
282
283 // Have any of the old selected objects changed compared to the new selection?
284 for (SelectedObjectMap::iterator i = old_selected_objects.begin();
285 i != old_objects_end; ++i) {
286 LayoutObject* obj = i->key;
287 SelectionState new_selection_state = obj->GetSelectionState();
288 SelectionState old_selection_state = i->value;
289 if (new_selection_state != old_selection_state ||
290 (selection_start_ == obj && old_start_pos != selection_start_pos_) ||
291 (selection_end_ == obj && old_end_pos != selection_end_pos_)) {
292 obj->SetShouldInvalidateSelection();
293 new_selected_objects.erase(obj);
294 }
295 }
296
297 // Any new objects that remain were not found in the old objects dict, and so
298 // they need to be updated.
299 SelectedObjectMap::iterator new_objects_end = new_selected_objects.end();
300 for (SelectedObjectMap::iterator i = new_selected_objects.begin();
301 i != new_objects_end; ++i)
302 i->key->SetShouldInvalidateSelection();
303
304 // Have any of the old blocks changed?
305 SelectedBlockMap::iterator old_blocks_end = old_selected_blocks.end();
306 for (SelectedBlockMap::iterator i = old_selected_blocks.begin();
307 i != old_blocks_end; ++i) {
308 LayoutBlock* block = i->key;
309 SelectionState new_selection_state = block->GetSelectionState();
310 SelectionState old_selection_state = i->value;
311 if (new_selection_state != old_selection_state) {
312 block->SetShouldInvalidateSelection();
313 new_selected_blocks.erase(block);
314 }
315 }
316
317 // Any new blocks that remain were not found in the old blocks dict, and so
318 // they need to be updated.
319 SelectedBlockMap::iterator new_blocks_end = new_selected_blocks.end();
320 for (SelectedBlockMap::iterator i = new_selected_blocks.begin();
321 i != new_blocks_end; ++i)
322 i->key->SetShouldInvalidateSelection();
323 }
324
325 void LayoutSelection::SelectionStartEnd(int& start_pos, int& end_pos) {
326 Commit(*frame_selection_->GetDocument().GetLayoutView());
327 start_pos = selection_start_pos_;
328 end_pos = selection_end_pos_;
329 }
330
331 void LayoutSelection::ClearSelection() {
332 // For querying Layer::compositingState()
333 // This is correct, since destroying layout objects needs to cause eager paint
334 // invalidations.
335 DisableCompositingQueryAsserts disabler;
336
337 SetSelection(0, -1, 0, -1, kPaintInvalidationNewMinusOld);
338 }
339
114 void LayoutSelection::Commit(LayoutView& layout_view) { 340 void LayoutSelection::Commit(LayoutView& layout_view) {
115 if (!HasPendingSelection()) 341 if (!HasPendingSelection())
116 return; 342 return;
117 DCHECK(!layout_view.NeedsLayout()); 343 DCHECK(!layout_view.NeedsLayout());
118 has_pending_selection_ = false; 344 has_pending_selection_ = false;
119 345
120 const VisibleSelectionInFlatTree& original_selection = 346 const VisibleSelectionInFlatTree& original_selection =
121 frame_selection_->ComputeVisibleSelectionInFlatTree(); 347 frame_selection_->ComputeVisibleSelectionInFlatTree();
122 348
123 // Skip if pending VisibilePositions became invalid before we reach here. 349 // Skip if pending VisibilePositions became invalid before we reach here.
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after
169 } 395 }
170 396
171 void LayoutSelection::OnDocumentShutdown() { 397 void LayoutSelection::OnDocumentShutdown() {
172 has_pending_selection_ = false; 398 has_pending_selection_ = false;
173 selection_start_ = nullptr; 399 selection_start_ = nullptr;
174 selection_end_ = nullptr; 400 selection_end_ = nullptr;
175 selection_start_pos_ = -1; 401 selection_start_pos_ = -1;
176 selection_end_pos_ = -1; 402 selection_end_pos_ = -1;
177 } 403 }
178 404
405 static LayoutRect SelectionRectForLayoutObject(const LayoutObject* object) {
406 if (!object->IsRooted())
407 return LayoutRect();
408
409 if (!object->CanUpdateSelectionOnRootLineBoxes())
410 return LayoutRect();
411
412 return object->SelectionRectInViewCoordinates();
413 }
414
415 IntRect LayoutSelection::SelectionBounds() {
416 // Now create a single bounding box rect that encloses the whole selection.
417 LayoutRect sel_rect;
418
419 typedef HashSet<const LayoutBlock*> VisitedContainingBlockSet;
420 VisitedContainingBlockSet visited_containing_blocks;
421
422 Commit(*frame_selection_->GetDocument().GetLayoutView());
423 LayoutObject* os = selection_start_;
424 LayoutObject* stop =
425 LayoutObjectAfterPosition(selection_end_, selection_end_pos_);
426 while (os && os != stop) {
427 if ((os->CanBeSelectionLeaf() || os == selection_start_ ||
428 os == selection_end_) &&
429 os->GetSelectionState() != SelectionNone) {
430 // Blocks are responsible for painting line gaps and margin gaps. They
431 // must be examined as well.
432 sel_rect.Unite(SelectionRectForLayoutObject(os));
433 const LayoutBlock* cb = os->ContainingBlock();
434 while (cb && !cb->IsLayoutView()) {
435 sel_rect.Unite(SelectionRectForLayoutObject(cb));
436 VisitedContainingBlockSet::AddResult add_result =
437 visited_containing_blocks.insert(cb);
438 if (!add_result.is_new_entry)
439 break;
440 cb = cb->ContainingBlock();
441 }
442 }
443
444 os = os->NextInPreOrder();
445 }
446
447 return PixelSnappedIntRect(sel_rect);
448 }
449
450 void LayoutSelection::InvalidatePaintForSelection() {
451 LayoutObject* end =
452 LayoutObjectAfterPosition(selection_end_, selection_end_pos_);
453 for (LayoutObject* o = selection_start_; o && o != end;
454 o = o->NextInPreOrder()) {
455 if (!o->CanBeSelectionLeaf() && o != selection_start_ &&
456 o != selection_end_)
457 continue;
458 if (o->GetSelectionState() == SelectionNone)
459 continue;
460
461 o->SetShouldInvalidateSelection();
462 }
463 }
464
179 DEFINE_TRACE(LayoutSelection) { 465 DEFINE_TRACE(LayoutSelection) {
180 visitor->Trace(frame_selection_); 466 visitor->Trace(frame_selection_);
181 } 467 }
182 468
183 } // namespace blink 469 } // namespace blink
OLDNEW
« no previous file with comments | « no previous file | third_party/WebKit/Source/core/layout/LayoutView.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698