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

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

Issue 2680943004: Make FrameSelection to hold non-canonicalized positions (Closed)
Patch Set: 2017-02-10T16:43:07 Rebase and update test expectation for cached Document Range Created 3 years, 10 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) 2004, 2008, 2009, 2010 Apple Inc. All rights reserved. 2 * Copyright (C) 2004, 2008, 2009, 2010 Apple Inc. All rights reserved.
3 * 3 *
4 * Redistribution and use in source and binary forms, with or without 4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions 5 * modification, are permitted provided that the following conditions
6 * are met: 6 * are met:
7 * 1. Redistributions of source code must retain the above copyright 7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer. 8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright 9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the 10 * notice, this list of conditions and the following disclaimer in the
(...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after
103 frame.page()->focusController().focusedFrame() == frame), 103 frame.page()->focusController().focusedFrame() == frame),
104 m_frameCaret(new FrameCaret(frame, *m_selectionEditor)) {} 104 m_frameCaret(new FrameCaret(frame, *m_selectionEditor)) {}
105 105
106 FrameSelection::~FrameSelection() {} 106 FrameSelection::~FrameSelection() {}
107 107
108 const DisplayItemClient& FrameSelection::caretDisplayItemClientForTesting() 108 const DisplayItemClient& FrameSelection::caretDisplayItemClientForTesting()
109 const { 109 const {
110 return m_frameCaret->displayItemClient(); 110 return m_frameCaret->displayItemClient();
111 } 111 }
112 112
113 const Document& FrameSelection::document() const { 113 Document& FrameSelection::document() const {
114 DCHECK(lifecycleContext()); 114 DCHECK(lifecycleContext());
115 return *lifecycleContext(); 115 return *lifecycleContext();
116 } 116 }
117 117
118 Document& FrameSelection::document() { 118 bool FrameSelection::isHandleVisible() const {
119 DCHECK(lifecycleContext()); 119 return selectionInDOMTree().isHandleVisible();
120 return *lifecycleContext();
121 } 120 }
122 121
122 // TODO(yosin): We should replace // |visibleSelection<EditingStrategy>()| to
tkent 2017/02/10 08:47:40 nit: Looks the second "//" is unnecessary.
yosin_UTC9 2017/02/10 10:13:20 Done.
123 // |computeVisibleSelectionInDOMTree()|.
123 // TODO(yosin): To avoid undefined symbols in clang, we explicitly 124 // TODO(yosin): To avoid undefined symbols in clang, we explicitly
124 // have specialized version of |FrameSelection::visibleSelection<Strategy>| 125 // have specialized version of |FrameSelection::visibleSelection<Strategy>|
125 // before |FrameSelection::selection()| which refers this. 126 // before |FrameSelection::selection()| which refers this.
126 template <> 127 template <>
127 const VisibleSelection& FrameSelection::visibleSelection<EditingStrategy>() 128 const VisibleSelection& FrameSelection::visibleSelection<EditingStrategy>()
128 const { 129 const {
129 return m_selectionEditor->visibleSelection<EditingStrategy>(); 130 return m_selectionEditor->visibleSelection<EditingStrategy>();
130 } 131 }
131 132
133 // TODO(yosin): We should replace
134 // |visibleSelection<EditingInFlatTreeStrategy>()| to
tkent 2017/02/10 08:47:41 nit |to| -> |with| or |by|
yosin_UTC9 2017/02/10 10:13:20 Done.
135 // |computeVisibleSelectionInFlatTree()|.
132 template <> 136 template <>
133 const VisibleSelectionInFlatTree& 137 const VisibleSelectionInFlatTree&
134 FrameSelection::visibleSelection<EditingInFlatTreeStrategy>() const { 138 FrameSelection::visibleSelection<EditingInFlatTreeStrategy>() const {
135 return m_selectionEditor->visibleSelection<EditingInFlatTreeStrategy>(); 139 return m_selectionEditor->visibleSelection<EditingInFlatTreeStrategy>();
136 } 140 }
137 141
142 const VisibleSelection& FrameSelection::computeVisibleSelectionInDOMTree()
143 const {
144 return m_selectionEditor->computeVisibleSelectionInDOMTree();
145 }
146
147 const VisibleSelectionInFlatTree&
148 FrameSelection::computeVisibleSelectionInFlatTree() const {
149 return m_selectionEditor->computeVisibleSelectionInFlatTree();
150 }
151
152 const SelectionInDOMTree& FrameSelection::selectionInDOMTree() const {
153 return m_selectionEditor->selectionInDOMTree();
154 }
155
138 Element* FrameSelection::rootEditableElementOrDocumentElement() const { 156 Element* FrameSelection::rootEditableElementOrDocumentElement() const {
139 Element* selectionRoot = selection().rootEditableElement(); 157 Element* selectionRoot = selection().rootEditableElement();
140 return selectionRoot ? selectionRoot : document().documentElement(); 158 return selectionRoot ? selectionRoot : document().documentElement();
141 } 159 }
142 160
143 ContainerNode* FrameSelection::rootEditableElementOrTreeScopeRootNode() const { 161 ContainerNode* FrameSelection::rootEditableElementOrTreeScopeRootNode() const {
144 Element* selectionRoot = selection().rootEditableElement(); 162 Element* selectionRoot = selection().rootEditableElement();
145 if (selectionRoot) 163 if (selectionRoot)
146 return selectionRoot; 164 return selectionRoot;
147 165
148 Node* node = selection().base().computeContainerNode(); 166 Node* node = selection().base().computeContainerNode();
149 return node ? &node->treeScope().rootNode() : 0; 167 return node ? &node->treeScope().rootNode() : 0;
150 } 168 }
151 169
170 // TODO(yosin): We should rename |FrameSelection::selection()| to
171 // |selectionDeprecated()|.
152 const VisibleSelection& FrameSelection::selection() const { 172 const VisibleSelection& FrameSelection::selection() const {
153 return visibleSelection<EditingStrategy>(); 173 // TODO(yosin): We should hoist updateStyleAndLayoutIgnorePendingStylesheets
174 // to caller. See http://crbug.com/590369 for more details.
175 document().updateStyleAndLayoutIgnorePendingStylesheets();
176 return computeVisibleSelectionInDOMTree();
154 } 177 }
155 178
156 const VisibleSelectionInFlatTree& FrameSelection::selectionInFlatTree() const { 179 const VisibleSelectionInFlatTree& FrameSelection::selectionInFlatTree() const {
157 return visibleSelection<EditingInFlatTreeStrategy>(); 180 return visibleSelection<EditingInFlatTreeStrategy>();
158 } 181 }
159 182
160 void FrameSelection::moveCaretSelection(const IntPoint& point) { 183 void FrameSelection::moveCaretSelection(const IntPoint& point) {
161 DCHECK(!document().needsLayoutTreeUpdate()); 184 DCHECK(!document().needsLayoutTreeUpdate());
162 185
163 Element* const editable = rootEditableElement(); 186 Element* const editable = rootEditableElement();
164 if (!editable) 187 if (!editable)
165 return; 188 return;
166 189
167 const VisiblePosition position = 190 const VisiblePosition position =
168 visiblePositionForContentsPoint(point, frame()); 191 visiblePositionForContentsPoint(point, frame());
169 SelectionInDOMTree::Builder builder; 192 SelectionInDOMTree::Builder builder;
170 builder.setIsDirectional(selection().isDirectional()); 193 builder.setIsDirectional(selection().isDirectional());
171 builder.setIsHandleVisible(true); 194 builder.setIsHandleVisible(true);
172 if (position.isNotNull()) 195 if (position.isNotNull())
173 builder.collapse(position.toPositionWithAffinity()); 196 builder.collapse(position.toPositionWithAffinity());
174 setSelection(builder.build(), CloseTyping | ClearTypingStyle | UserTriggered); 197 setSelection(builder.build(), CloseTyping | ClearTypingStyle | UserTriggered);
175 } 198 }
176 199
177 template <typename Strategy> 200 void FrameSelection::setSelection(const SelectionInDOMTree& passedSelection,
178 void FrameSelection::setSelectionAlgorithm( 201 SetSelectionOptions options,
179 const VisibleSelectionTemplate<Strategy>& newSelection, 202 CursorAlignOnScroll align,
180 HandleVisibility handleVisibility, 203 TextGranularity granularity) {
181 SetSelectionOptions options,
182 CursorAlignOnScroll align,
183 TextGranularity granularity) {
184 DCHECK(isAvailable()); 204 DCHECK(isAvailable());
185 DCHECK(newSelection.isValidFor(document())); 205 passedSelection.assertValidFor(document());
186 const Document& currentDocument = document(); 206
207 SelectionInDOMTree::Builder builder(passedSelection);
208 if (shouldAlwaysUseDirectionalSelection(m_frame))
209 builder.setIsDirectional(true);
210 SelectionInDOMTree newSelection = builder.build();
187 if (m_granularityStrategy && 211 if (m_granularityStrategy &&
188 (options & FrameSelection::DoNotClearStrategy) == 0) 212 (options & FrameSelection::DoNotClearStrategy) == 0)
189 m_granularityStrategy->Clear(); 213 m_granularityStrategy->Clear();
190 bool closeTyping = options & CloseTyping; 214 bool closeTyping = options & CloseTyping;
191 bool shouldClearTypingStyle = options & ClearTypingStyle; 215 bool shouldClearTypingStyle = options & ClearTypingStyle;
192 EUserTriggered userTriggered = selectionOptionsToUserTriggered(options);
193
194 // TODO(editing-dev): We should rename variable |s| to another name to avoid
195 // using one letter variable name.
196 VisibleSelectionTemplate<Strategy> s = newSelection;
197 if (shouldAlwaysUseDirectionalSelection(m_frame))
198 s.setIsDirectional(true);
199
200 m_granularity = granularity; 216 m_granularity = granularity;
201 217
202 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to 218 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to
203 // |Editor| class. 219 // |Editor| class.
204 if (closeTyping) 220 if (closeTyping)
205 TypingCommand::closeTyping(m_frame); 221 TypingCommand::closeTyping(m_frame);
206 222
207 if (shouldClearTypingStyle) 223 if (shouldClearTypingStyle)
208 m_frame->editor().clearTypingStyle(); 224 m_frame->editor().clearTypingStyle();
209 225
210 if (m_selectionEditor->visibleSelection<Strategy>() == s && 226 const SelectionInDOMTree oldSelectionInDOMTree =
211 m_handleVisibility == handleVisibility) { 227 m_selectionEditor->selectionInDOMTree();
212 // Even if selection was not changed, selection offsets may have been 228 if (oldSelectionInDOMTree == newSelection)
213 // changed.
214 notifyLayoutObjectOfSelectionChange(userTriggered);
215 return; 229 return;
216 } 230 m_selectionEditor->setSelection(newSelection);
217
218 const VisibleSelectionTemplate<Strategy> oldSelection =
219 visibleSelection<Strategy>();
220 const Position& oldSelectionStart = selection().start();
221
222 m_handleVisibility = handleVisibility;
223 m_selectionEditor->setVisibleSelection(s, options);
224 scheduleVisualUpdateForPaintInvalidationIfNeeded(); 231 scheduleVisualUpdateForPaintInvalidationIfNeeded();
225 232
226 if (!s.isNone() && !(options & DoNotSetFocus)) { 233 // TODO(yosin): The use of updateStyleAndLayoutIgnorePendingStylesheets
234 // needs to be audited. see http://crbug.com/590369 for more details.
235 document().updateStyleAndLayoutIgnorePendingStylesheets();
236
237 const Document& currentDocument = document();
238 // TODO(yosin): We should get rid of unsued |options| for
239 // |Editor::respondToChangedSelection()|.
240 // Note: Since, setting focus can modify DOM tree, we should use
241 // |oldSelection| before setting focus
242 m_frame->editor().respondToChangedSelection(
243 createVisibleSelection(oldSelectionInDOMTree).start(), options);
244 DCHECK_EQ(currentDocument, document());
245
246 if (!selection().isNone() && !(options & DoNotSetFocus)) {
227 setFocusedNodeIfNeeded(); 247 setFocusedNodeIfNeeded();
228 // |setFocusedNodeIfNeeded()| dispatches sync events "FocusOut" and 248 // |setFocusedNodeIfNeeded()| dispatches sync events "FocusOut" and
229 // "FocusIn", |m_frame| may associate to another document. 249 // "FocusIn", |m_frame| may associate to another document.
230 if (!isAvailable() || document() != currentDocument) { 250 if (!isAvailable() || document() != currentDocument) {
231 // Once we get test case to reach here, we should change this 251 // Once we get test case to reach here, we should change this
232 // if-statement to |DCHECK()|. 252 // if-statement to |DCHECK()|.
233 NOTREACHED(); 253 NOTREACHED();
234 return; 254 return;
235 } 255 }
236 } 256 }
237 257
238 if (!(options & DoNotUpdateAppearance)) { 258 if (!(options & DoNotUpdateAppearance)) {
239 m_frameCaret->stopCaretBlinkTimer(); 259 m_frameCaret->stopCaretBlinkTimer();
240 updateAppearance(); 260 updateAppearance();
241 } 261 }
242 262
243 // Always clear the x position used for vertical arrow navigation. 263 // Always clear the x position used for vertical arrow navigation.
244 // It will be restored by the vertical arrow navigation code if necessary. 264 // It will be restored by the vertical arrow navigation code if necessary.
245 m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation(); 265 m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation();
266 // TODO(yosin): Can we move this to at end of this function?
246 // This may dispatch a synchronous focus-related events. 267 // This may dispatch a synchronous focus-related events.
247 selectFrameElementInParentIfFullySelected(); 268 selectFrameElementInParentIfFullySelected();
248 if (!isAvailable() || document() != currentDocument) { 269 if (!isAvailable() || document() != currentDocument) {
249 // editing/selection/selectallchildren-crash.html and 270 // editing/selection/selectallchildren-crash.html and
250 // editing/selection/longpress-selection-in-iframe-removed-crash.html 271 // editing/selection/longpress-selection-in-iframe-removed-crash.html
251 // reach here. 272 // reach here.
252 return; 273 return;
253 } 274 }
275 EUserTriggered userTriggered = selectionOptionsToUserTriggered(options);
254 notifyLayoutObjectOfSelectionChange(userTriggered); 276 notifyLayoutObjectOfSelectionChange(userTriggered);
255 // If the selections are same in the DOM tree but not in the flat tree,
256 // don't fire events. For example, if the selection crosses shadow tree
257 // boundary, selection for the DOM tree is shrunk while that for the
258 // flat tree is not. Additionally, this case occurs in some edge cases.
259 // See also: editing/pasteboard/4076267-3.html
260 if (oldSelection == m_selectionEditor->visibleSelection<Strategy>())
261 return;
262
263 m_frame->editor().respondToChangedSelection(oldSelectionStart, options);
264 if (userTriggered == UserTriggered) { 277 if (userTriggered == UserTriggered) {
265 ScrollAlignment alignment; 278 ScrollAlignment alignment;
266 279
267 if (m_frame->editor().behavior().shouldCenterAlignWhenSelectionIsRevealed()) 280 if (m_frame->editor().behavior().shouldCenterAlignWhenSelectionIsRevealed())
268 alignment = (align == CursorAlignOnScroll::Always) 281 alignment = (align == CursorAlignOnScroll::Always)
269 ? ScrollAlignment::alignCenterAlways 282 ? ScrollAlignment::alignCenterAlways
270 : ScrollAlignment::alignCenterIfNeeded; 283 : ScrollAlignment::alignCenterIfNeeded;
271 else 284 else
272 alignment = (align == CursorAlignOnScroll::Always) 285 alignment = (align == CursorAlignOnScroll::Always)
273 ? ScrollAlignment::alignTopAlways 286 ? ScrollAlignment::alignTopAlways
274 : ScrollAlignment::alignToEdgeIfNeeded; 287 : ScrollAlignment::alignToEdgeIfNeeded;
275 288
289 // TODO(editing-dev): The use of
290 // updateStyleAndLayoutIgnorePendingStylesheets
291 // needs to be audited. See http://crbug.com/590369 for more details.
292 document().updateStyleAndLayoutIgnorePendingStylesheets();
293
276 revealSelection(alignment, RevealExtent); 294 revealSelection(alignment, RevealExtent);
277 } 295 }
278 296
279 notifyAccessibilityForSelectionChange(); 297 notifyAccessibilityForSelectionChange();
280 notifyCompositorForSelectionChange(); 298 notifyCompositorForSelectionChange();
281 notifyEventHandlerForSelectionChange(); 299 notifyEventHandlerForSelectionChange();
282 m_frame->domWindow()->enqueueDocumentEvent( 300 m_frame->domWindow()->enqueueDocumentEvent(
283 Event::create(EventTypeNames::selectionchange)); 301 Event::create(EventTypeNames::selectionchange));
284 } 302 }
285 303
286 // TODO(yosin): We will make |selectionInDOMTree| version of |SetSelection()|
287 // as primary function instead of wrapper.
288 void FrameSelection::setSelection(const SelectionInDOMTree& newSelection,
289 SetSelectionOptions options,
290 CursorAlignOnScroll align,
291 TextGranularity granularity) {
292 if (!newSelection.isNone()) {
293 // TODO(editing-dev): The use of
294 // updateStyleAndLayoutIgnorePendingStylesheets
295 // needs to be audited. See http://crbug.com/590369 for more details.
296 newSelection.base()
297 .document()
298 ->updateStyleAndLayoutIgnorePendingStylesheets();
299 }
300 setSelection(createVisibleSelection(newSelection),
301 newSelection.isHandleVisible() ? HandleVisibility::Visible
302 : HandleVisibility::NotVisible,
303 options, align, granularity);
304 }
305
306 // TODO(yosin): We will make |selectionInFlatTree| version of |SetSelection()|
307 // as primary function instead of wrapper.
308 void FrameSelection::setSelection(const SelectionInFlatTree& newSelection, 304 void FrameSelection::setSelection(const SelectionInFlatTree& newSelection,
309 SetSelectionOptions options, 305 SetSelectionOptions options,
310 CursorAlignOnScroll align, 306 CursorAlignOnScroll align,
311 TextGranularity granularity) { 307 TextGranularity granularity) {
312 if (!newSelection.isNone()) { 308 newSelection.assertValidFor(document());
313 // TODO(editing-dev): The use of 309 SelectionInDOMTree::Builder builder;
314 // updateStyleAndLayoutIgnorePendingStylesheets 310 builder.setAffinity(newSelection.affinity())
315 // needs to be audited. See http://crbug.com/590369 for more details. 311 .setBaseAndExtent(toPositionInDOMTree(newSelection.base()),
316 newSelection.base() 312 toPositionInDOMTree(newSelection.extent()))
317 .document() 313 .setGranularity(newSelection.granularity())
318 ->updateStyleAndLayoutIgnorePendingStylesheets(); 314 .setIsDirectional(newSelection.isDirectional())
319 } 315 .setIsHandleVisible(newSelection.isHandleVisible())
320 setSelection(createVisibleSelection(newSelection), 316 .setHasTrailingWhitespace(newSelection.hasTrailingWhitespace());
321 newSelection.isHandleVisible() ? HandleVisibility::Visible 317 return setSelection(builder.build(), options, align, granularity);
322 : HandleVisibility::NotVisible,
323 options, align, granularity);
324 } 318 }
325 319
326 void FrameSelection::setSelection(const VisibleSelection& newSelection, 320 void FrameSelection::setSelection(const VisibleSelection& newSelection,
327 HandleVisibility handleVisibility, 321 HandleVisibility handleVisibility,
328 SetSelectionOptions options, 322 SetSelectionOptions options,
329 CursorAlignOnScroll align, 323 CursorAlignOnScroll align,
330 TextGranularity granularity) { 324 TextGranularity granularity) {
331 setSelectionAlgorithm<EditingStrategy>(newSelection, handleVisibility, 325 setSelection(
332 options, align, granularity); 326 SelectionInDOMTree::Builder(newSelection.asSelection())
327 .setIsHandleVisible(handleVisibility == HandleVisibility::Visible)
328 .build(),
329 options, align, granularity);
333 } 330 }
334 331
335 void FrameSelection::setSelection(const VisibleSelection& newSelection, 332 void FrameSelection::setSelection(const VisibleSelection& newSelection,
336 SetSelectionOptions options) { 333 SetSelectionOptions options) {
337 setSelection(newSelection, HandleVisibility::NotVisible, options); 334 setSelection(newSelection.asSelection(), options);
338 } 335 }
339 336
340 void FrameSelection::setSelection( 337 void FrameSelection::setSelection(
341 const VisibleSelectionInFlatTree& newSelection, 338 const VisibleSelectionInFlatTree& newSelection,
342 HandleVisibility handleVisibility, 339 HandleVisibility handleVisibility,
343 SetSelectionOptions options, 340 SetSelectionOptions options,
344 CursorAlignOnScroll align, 341 CursorAlignOnScroll align,
345 TextGranularity granularity) { 342 TextGranularity granularity) {
346 setSelectionAlgorithm<EditingInFlatTreeStrategy>( 343 setSelection(
347 newSelection, handleVisibility, options, align, granularity); 344 SelectionInFlatTree::Builder(newSelection.asSelection())
345 .setIsHandleVisible(handleVisibility == HandleVisibility::Visible)
346 .build(),
347 options, align, granularity);
348 } 348 }
349 349
350 void FrameSelection::setSelection( 350 void FrameSelection::setSelection(
351 const VisibleSelectionInFlatTree& newSelection, 351 const VisibleSelectionInFlatTree& newSelection,
352 SetSelectionOptions options) { 352 SetSelectionOptions options) {
353 setSelection(newSelection, HandleVisibility::NotVisible, options); 353 setSelection(newSelection.asSelection(), options);
354 } 354 }
355 355
356 static bool removingNodeRemovesPosition(Node& node, const Position& position) { 356 // TODO(yosin): We should remove |computePositionForChildrenRemoval()| to
tkent 2017/02/10 08:47:40 nit: remove -> move
yosin_UTC9 2017/02/10 10:13:20 Done.
357 if (!position.anchorNode()) 357 // "SelectionEditor.cpp" since it used only in
358 return false; 358 // |SelectionEditor::nodeChildrenWillBeRemoved()|.
359
360 if (position.anchorNode() == node)
361 return true;
362
363 if (!node.isElementNode())
364 return false;
365
366 Element& element = toElement(node);
367 return element.isShadowIncludingInclusiveAncestorOf(position.anchorNode());
368 }
369
370 static Position computePositionForChildrenRemoval(const Position& position, 359 static Position computePositionForChildrenRemoval(const Position& position,
371 ContainerNode& container) { 360 ContainerNode& container) {
372 Node* node = position.computeContainerNode(); 361 Node* node = position.computeContainerNode();
373 if (container.containsIncludingHostElements(*node)) 362 if (container.containsIncludingHostElements(*node))
374 return Position::firstPositionInNode(&container); 363 return Position::firstPositionInNode(&container);
375 return position; 364 return position;
376 } 365 }
377 366
378 void FrameSelection::nodeChildrenWillBeRemoved(ContainerNode& container) { 367 void FrameSelection::nodeChildrenWillBeRemoved(ContainerNode& container) {
379 if (isNone() || !container.inActiveDocument()) 368 if (!container.inActiveDocument())
380 return; 369 return;
381 const Position& oldStart = selection().start();
382 const Position& newStart =
383 computePositionForChildrenRemoval(oldStart, container);
384 const Position& oldEnd = selection().end();
385 const Position& newEnd = computePositionForChildrenRemoval(oldEnd, container);
386 const Position& oldBase = selection().base();
387 const Position& newBase =
388 computePositionForChildrenRemoval(oldBase, container);
389 const Position& oldExtent = selection().extent();
390 const Position& newExtent =
391 computePositionForChildrenRemoval(oldExtent, container);
392 if (newStart == oldStart && newEnd == oldEnd && newBase == oldBase &&
393 newExtent == oldExtent)
394 return;
395 if (selection().isBaseFirst())
396 m_selectionEditor->setWithoutValidation(newStart, newEnd);
397 else
398 m_selectionEditor->setWithoutValidation(newEnd, newStart);
399 if (document().isRunningExecCommand())
400 return;
401 TypingCommand::closeTyping(m_frame);
402 }
403
404 void FrameSelection::nodeWillBeRemoved(Node& node) {
405 // There can't be a selection inside a fragment, so if a fragment's node is
406 // being removed, the selection in the document that created the fragment
407 // needs no adjustment.
408 if (isNone() || !node.inActiveDocument())
409 return;
410
411 respondToNodeModification(
412 node, removingNodeRemovesPosition(node, selection().base()),
413 removingNodeRemovesPosition(node, selection().extent()),
414 removingNodeRemovesPosition(node, selection().start()),
415 removingNodeRemovesPosition(node, selection().end()));
416 }
417
418 static SelectionState selectionStateOf(const Node& node) {
419 const LayoutObject* layoutObject = node.layoutObject();
420 if (!layoutObject)
421 return SelectionNone;
422 return layoutObject->getSelectionState();
423 }
424
425 void FrameSelection::respondToNodeModification(Node& node,
426 bool baseRemoved,
427 bool extentRemoved,
428 bool startRemoved,
429 bool endRemoved) {
430 DCHECK(node.document().isActive()) << node;
431
432 bool clearLayoutTreeSelection = false;
433 bool clearDOMTreeSelection = false;
434
435 if (startRemoved || endRemoved) {
436 Position start = selection().start();
437 Position end = selection().end();
438 if (startRemoved)
439 updatePositionForNodeRemoval(start, node);
440 if (endRemoved)
441 updatePositionForNodeRemoval(end, node);
442
443 if (Position::commonAncestorTreeScope(start, end) && start.isNotNull() &&
444 end.isNotNull()) {
445 if (selection().isBaseFirst())
446 m_selectionEditor->setWithoutValidation(start, end);
447 else
448 m_selectionEditor->setWithoutValidation(end, start);
449 } else {
450 clearDOMTreeSelection = true;
451 }
452
453 clearLayoutTreeSelection = true;
454 } else if (baseRemoved || extentRemoved) {
455 // The base and/or extent are about to be removed, but the start and end
456 // aren't. Change the base and extent to the start and end, but don't
457 // re-validate the selection, since doing so could move the start and end
458 // into the node that is about to be removed.
459 if (selection().isBaseFirst())
460 m_selectionEditor->setWithoutValidation(selection().start(),
461 selection().end());
462 else
463 m_selectionEditor->setWithoutValidation(selection().end(),
464 selection().start());
465 } else if (selectionStateOf(node) != SelectionNone) {
466 // When node to be removed is part of selection, we invalidate
467 // selection to paint again.
468 // TODO(yosin): We should paint changed area only rather than whole
469 // selected range.
470 clearLayoutTreeSelection = true;
471 }
472
473 if (clearLayoutTreeSelection)
474 selection().start().document()->layoutViewItem().clearSelection();
475
476 if (clearDOMTreeSelection)
477 setSelection(SelectionInDOMTree(), DoNotSetFocus);
478
479 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to 370 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to
480 // |Editor| class. 371 // |Editor| class.
481 if (!document().isRunningExecCommand()) 372 if (!document().isRunningExecCommand())
482 TypingCommand::closeTyping(m_frame); 373 TypingCommand::closeTyping(m_frame);
483 } 374 }
484 375
376 // TODO(yosin): We should move |SelectionEditor::nodeChildrenWillBeRemoved()|
377 // to "SelectionEditor.cpp".
378 void SelectionEditor::nodeChildrenWillBeRemoved(ContainerNode& container) {
379 if (m_selection.isNone())
380 return;
381 const Position oldBase = m_selection.m_base;
382 const Position oldExtent = m_selection.m_extent;
383 const Position& newBase =
384 computePositionForChildrenRemoval(oldBase, container);
385 const Position& newExtent =
386 computePositionForChildrenRemoval(oldExtent, container);
387 if (newBase == oldBase && newExtent == oldExtent)
388 return;
389 m_selection = SelectionInDOMTree::Builder()
390 .setBaseAndExtent(newBase, newExtent)
391 .build();
392 markCacheDirty();
393 }
394
395 void FrameSelection::nodeWillBeRemoved(Node& node) {
396 // There can't be a selection inside a fragment, so if a fragment's node is
397 // being removed,
tkent 2017/02/10 08:47:40 nit: Text wrapping looks weird.
yosin_UTC9 2017/02/10 10:13:20 Done.
398 // the selection in the document that created the fragment needs no
399 // adjustment.
400 if (!node.inActiveDocument())
401 return;
402 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to
403 // |Editor| class.
404 if (!document().isRunningExecCommand())
405 TypingCommand::closeTyping(m_frame);
406 }
407
408 // TODO(yosin): We should remove |updatePositionAfterAdoptingTextReplacement()|
tkent 2017/02/10 08:47:41 nit: remove -> move
yosin_UTC9 2017/02/10 10:13:20 Done.
409 // to // "SelectionEditor.cpp" since it used only in
tkent 2017/02/10 08:47:40 nit: the second '//' looks unnecessary.
yosin_UTC9 2017/02/10 10:13:20 Done.
410 // |SelectionEditor::didUpdateCharacterData()|.
485 static Position updatePositionAfterAdoptingTextReplacement( 411 static Position updatePositionAfterAdoptingTextReplacement(
486 const Position& position, 412 const Position& position,
487 CharacterData* node, 413 CharacterData* node,
488 unsigned offset, 414 unsigned offset,
489 unsigned oldLength, 415 unsigned oldLength,
490 unsigned newLength) { 416 unsigned newLength) {
491 if (!position.anchorNode() || position.anchorNode() != node || 417 if (position.anchorNode() != node)
492 !position.isOffsetInAnchor())
493 return position; 418 return position;
494 419
420 if (position.isBeforeAnchor()) {
421 return updatePositionAfterAdoptingTextReplacement(
422 Position(node, 0), node, offset, oldLength, newLength);
423 }
424 if (position.isAfterAnchor()) {
425 return updatePositionAfterAdoptingTextReplacement(
426 Position(node, oldLength), node, offset, oldLength, newLength);
427 }
428
495 // See: 429 // See:
496 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range- Mutation 430 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range- Mutation
497 DCHECK_GE(position.offsetInContainerNode(), 0); 431 DCHECK_GE(position.offsetInContainerNode(), 0);
498 unsigned positionOffset = 432 unsigned positionOffset =
499 static_cast<unsigned>(position.offsetInContainerNode()); 433 static_cast<unsigned>(position.offsetInContainerNode());
500 // Replacing text can be viewed as a deletion followed by insertion. 434 // Replacing text can be viewed as a deletion followed by insertion.
501 if (positionOffset >= offset && positionOffset <= offset + oldLength) 435 if (positionOffset >= offset && positionOffset <= offset + oldLength)
502 positionOffset = offset; 436 positionOffset = offset;
503 437
504 // Adjust the offset if the position is after the end of the deleted contents 438 // Adjust the offset if the position is after the end of the deleted contents
505 // (positionOffset > offset + oldLength) to avoid having a stale offset. 439 // (positionOffset > offset + oldLength) to avoid having a stale offset.
506 if (positionOffset > offset + oldLength) 440 if (positionOffset > offset + oldLength)
507 positionOffset = positionOffset - oldLength + newLength; 441 positionOffset = positionOffset - oldLength + newLength;
508 442
509 // Due to case folding 443 // Due to case folding
510 // (http://unicode.org/Public/UCD/latest/ucd/CaseFolding.txt), LayoutText 444 // (http://unicode.org/Public/UCD/latest/ucd/CaseFolding.txt), LayoutText
511 // length may be different from Text length. A correct implementation would 445 // length may be different from Text length. A correct implementation would
512 // translate the LayoutText offset to a Text offset; this is just a safety 446 // translate the LayoutText offset to a Text offset; this is just a safety
513 // precaution to avoid offset values that run off the end of the Text. 447 // precaution to avoid offset values that run off the end of the Text.
514 if (positionOffset > node->length()) 448 if (positionOffset > node->length())
515 positionOffset = node->length(); 449 positionOffset = node->length();
516 450
517 // CharacterNode in VisibleSelection must be Text node, because Comment 451 return Position(node, positionOffset);
518 // and ProcessingInstruction node aren't visible.
519 return Position(toText(node), positionOffset);
520 } 452 }
521 453
522 void FrameSelection::didUpdateCharacterData(CharacterData* node, 454 void SelectionEditor::didUpdateCharacterData(CharacterData* node,
tkent 2017/02/10 08:47:40 nit: Add TODO comment about moving it to Selection
yosin_UTC9 2017/02/10 10:13:20 Done.
523 unsigned offset, 455 unsigned offset,
524 unsigned oldLength, 456 unsigned oldLength,
525 unsigned newLength) { 457 unsigned newLength) {
526 // The fragment check is a performance optimization. See 458 // The fragment check is a performance optimization. See
527 // http://trac.webkit.org/changeset/30062. 459 // http://trac.webkit.org/changeset/30062.
528 if (isNone() || !node || !node->isConnected()) 460 if (m_selection.isNone() || !node || !node->isConnected()) {
461 didFinishDOMMutation();
529 return; 462 return;
530 463 }
531 Position base = updatePositionAfterAdoptingTextReplacement( 464 const Position& newBase = updatePositionAfterAdoptingTextReplacement(
532 selection().base(), node, offset, oldLength, newLength); 465 m_selection.m_base, node, offset, oldLength, newLength);
533 Position extent = updatePositionAfterAdoptingTextReplacement( 466 const Position& newExtent = updatePositionAfterAdoptingTextReplacement(
534 selection().extent(), node, offset, oldLength, newLength); 467 m_selection.m_extent, node, offset, oldLength, newLength);
535 Position start = updatePositionAfterAdoptingTextReplacement( 468 didFinishTextChange(newBase, newExtent);
536 selection().start(), node, offset, oldLength, newLength);
537 Position end = updatePositionAfterAdoptingTextReplacement(
538 selection().end(), node, offset, oldLength, newLength);
539 updateSelectionIfNeeded(base, extent, start, end);
540 } 469 }
541 470
471 // TODO(yosin): We should remove |updatePostionAfterAdoptingTextNodesMerged()|
tkent 2017/02/10 08:47:41 nit: remove -> move
yosin_UTC9 2017/02/10 10:13:20 Done.
472 // to // "SelectionEditor.cpp" since it used only in
tkent 2017/02/10 08:47:40 nit: the second '//' looks unnecessary.
yosin_UTC9 2017/02/10 10:13:20 Done.
473 // |SelectionEditor::didMergeTextNodes()|.
542 static Position updatePostionAfterAdoptingTextNodesMerged( 474 static Position updatePostionAfterAdoptingTextNodesMerged(
543 const Position& position, 475 const Position& position,
544 const Text& oldNode, 476 const Text& mergedNode,
545 unsigned offset) { 477 const NodeWithIndex& nodeToBeRemovedWithIndex,
546 if (!position.anchorNode() || !position.isOffsetInAnchor()) 478 unsigned oldLength) {
547 return position; 479 Node* const anchorNode = position.anchorNode();
548 480 const Node& nodeToBeRemoved = nodeToBeRemovedWithIndex.node();
549 DCHECK_GE(position.offsetInContainerNode(), 0); 481 switch (position.anchorType()) {
550 unsigned positionOffset = 482 case PositionAnchorType::BeforeChildren:
551 static_cast<unsigned>(position.offsetInContainerNode()); 483 case PositionAnchorType::AfterChildren:
552 484 return position;
553 if (position.anchorNode() == &oldNode) 485 case PositionAnchorType::BeforeAnchor:
554 return Position(toText(oldNode.previousSibling()), positionOffset + offset); 486 if (anchorNode == nodeToBeRemoved)
555 487 return Position(const_cast<Text*>(&mergedNode), mergedNode.length());
556 if (position.anchorNode() == oldNode.parentNode() && positionOffset == offset) 488 return position;
557 return Position(toText(oldNode.previousSibling()), offset); 489 case PositionAnchorType::AfterAnchor:
558 490 if (anchorNode == nodeToBeRemoved)
491 return Position(const_cast<Text*>(&mergedNode), mergedNode.length());
492 if (anchorNode == mergedNode)
493 return Position(const_cast<Text*>(&mergedNode), oldLength);
494 return position;
495 case PositionAnchorType::OffsetInAnchor: {
496 const int offset = position.offsetInContainerNode();
497 if (anchorNode == nodeToBeRemoved)
498 return Position(const_cast<Text*>(&mergedNode), oldLength + offset);
499 if (anchorNode == nodeToBeRemoved.parentNode() &&
500 offset == nodeToBeRemovedWithIndex.index()) {
501 return Position(const_cast<Text*>(&mergedNode), oldLength);
502 }
503 return position;
504 }
505 }
506 NOTREACHED() << position;
559 return position; 507 return position;
560 } 508 }
561 509
562 void FrameSelection::didMergeTextNodes( 510 // TODO(yosin): We should move |SelectionEditor::didMergeTextNodes()| to
511 // "SelectionEditor.cpp".
512 void SelectionEditor::didMergeTextNodes(
563 const Text& mergedNode, 513 const Text& mergedNode,
564 const NodeWithIndex& nodeToBeRemovedWithIndex, 514 const NodeWithIndex& nodeToBeRemovedWithIndex,
565 unsigned offset) { 515 unsigned oldLength) {
566 const Text& oldNode = toText(nodeToBeRemovedWithIndex.node()); 516 if (m_selection.isNone()) {
567 if (isNone() || !oldNode.isConnected()) 517 didFinishDOMMutation();
568 return; 518 return;
569 Position base = updatePostionAfterAdoptingTextNodesMerged(selection().base(), 519 }
570 oldNode, offset); 520 const Position& newBase = updatePostionAfterAdoptingTextNodesMerged(
571 Position extent = updatePostionAfterAdoptingTextNodesMerged( 521 m_selection.m_base, mergedNode, nodeToBeRemovedWithIndex, oldLength);
572 selection().extent(), oldNode, offset); 522 const Position& newExtent = updatePostionAfterAdoptingTextNodesMerged(
573 Position start = updatePostionAfterAdoptingTextNodesMerged( 523 m_selection.m_extent, mergedNode, nodeToBeRemovedWithIndex, oldLength);
574 selection().start(), oldNode, offset); 524 didFinishTextChange(newBase, newExtent);
575 Position end = updatePostionAfterAdoptingTextNodesMerged(selection().end(),
576 oldNode, offset);
577 updateSelectionIfNeeded(base, extent, start, end);
578 } 525 }
579 526
527 // TODO(yosin): We should remove |updatePostionAfterAdoptingTextNodeSplit()|
tkent 2017/02/10 08:47:40 nit: remove -> move
yosin_UTC9 2017/02/10 10:13:20 Done.
528 // to // "SelectionEditor.cpp" since it used only in
tkent 2017/02/10 08:47:41 nit: the second '//' looks unnecessary.
yosin_UTC9 2017/02/10 10:13:20 Done.
529 // |SelectionEditor::didSplitTextNode()|.
580 static Position updatePostionAfterAdoptingTextNodeSplit( 530 static Position updatePostionAfterAdoptingTextNodeSplit(
581 const Position& position, 531 const Position& position,
582 const Text& oldNode) { 532 const Text& oldNode) {
583 if (!position.anchorNode() || position.anchorNode() != &oldNode || 533 if (!position.anchorNode() || position.anchorNode() != &oldNode ||
584 !position.isOffsetInAnchor()) 534 !position.isOffsetInAnchor())
585 return position; 535 return position;
586 // See: 536 // See:
587 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range- Mutation 537 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range- Mutation
588 DCHECK_GE(position.offsetInContainerNode(), 0); 538 DCHECK_GE(position.offsetInContainerNode(), 0);
589 unsigned positionOffset = 539 unsigned positionOffset =
590 static_cast<unsigned>(position.offsetInContainerNode()); 540 static_cast<unsigned>(position.offsetInContainerNode());
591 unsigned oldLength = oldNode.length(); 541 unsigned oldLength = oldNode.length();
592 if (positionOffset <= oldLength) 542 if (positionOffset <= oldLength)
593 return position; 543 return position;
594 return Position(toText(oldNode.nextSibling()), positionOffset - oldLength); 544 return Position(toText(oldNode.nextSibling()), positionOffset - oldLength);
595 } 545 }
596 546
597 void FrameSelection::didSplitTextNode(const Text& oldNode) { 547 // TODO(yosin): We should move |SelectionEditor::didSplitTextNode()| to
598 if (isNone() || !oldNode.isConnected()) 548 // "SelectionEditor.cpp".
549 void SelectionEditor::didSplitTextNode(const Text& oldNode) {
550 if (m_selection.isNone() || !oldNode.isConnected()) {
551 didFinishDOMMutation();
599 return; 552 return;
600 Position base = 553 }
601 updatePostionAfterAdoptingTextNodeSplit(selection().base(), oldNode); 554 const Position& newBase =
602 Position extent = 555 updatePostionAfterAdoptingTextNodeSplit(m_selection.m_base, oldNode);
603 updatePostionAfterAdoptingTextNodeSplit(selection().extent(), oldNode); 556 const Position& newExtent =
604 Position start = 557 updatePostionAfterAdoptingTextNodeSplit(m_selection.m_extent, oldNode);
605 updatePostionAfterAdoptingTextNodeSplit(selection().start(), oldNode); 558 didFinishTextChange(newBase, newExtent);
606 Position end =
607 updatePostionAfterAdoptingTextNodeSplit(selection().end(), oldNode);
608 updateSelectionIfNeeded(base, extent, start, end);
609 }
610
611 void FrameSelection::updateSelectionIfNeeded(const Position& base,
612 const Position& extent,
613 const Position& start,
614 const Position& end) {
615 if (base == selection().base() && extent == selection().extent() &&
616 start == selection().start() && end == selection().end())
617 return;
618 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to
619 // |Editor| class.
620 if (!document().isRunningExecCommand())
621 TypingCommand::closeTyping(m_frame);
622 VisibleSelection newSelection;
623 if (selection().isBaseFirst())
624 newSelection.setWithoutValidation(start, end);
625 else
626 newSelection.setWithoutValidation(end, start);
627 setSelection(newSelection, DoNotSetFocus);
628 } 559 }
629 560
630 void FrameSelection::didChangeFocus() { 561 void FrameSelection::didChangeFocus() {
631 // Hits in 562 // Hits in
632 // virtual/gpu/compositedscrolling/scrollbars/scrollbar-miss-mousemove-disable d.html 563 // virtual/gpu/compositedscrolling/scrollbars/scrollbar-miss-mousemove-disable d.html
633 DisableCompositingQueryAsserts disabler; 564 DisableCompositingQueryAsserts disabler;
634 updateAppearance(); 565 updateAppearance();
635 } 566 }
636 567
637 static DispatchEventResult dispatchSelectStart( 568 static DispatchEventResult dispatchSelectStart(
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after
724 } 655 }
725 656
726 void FrameSelection::contextDestroyed(Document* document) { 657 void FrameSelection::contextDestroyed(Document* document) {
727 m_granularity = CharacterGranularity; 658 m_granularity = CharacterGranularity;
728 659
729 LayoutViewItem view = m_frame->contentLayoutItem(); 660 LayoutViewItem view = m_frame->contentLayoutItem();
730 if (!view.isNull()) 661 if (!view.isNull())
731 view.clearSelection(); 662 view.clearSelection();
732 663
733 m_frame->editor().clearTypingStyle(); 664 m_frame->editor().clearTypingStyle();
734 m_selectionEditor->documentDetached(*document);
735 } 665 }
736 666
737 void FrameSelection::clearPreviousCaretVisualRect(const LayoutBlock& block) { 667 void FrameSelection::clearPreviousCaretVisualRect(const LayoutBlock& block) {
738 m_frameCaret->clearPreviousVisualRect(block); 668 m_frameCaret->clearPreviousVisualRect(block);
739 } 669 }
740 670
741 void FrameSelection::layoutBlockWillBeDestroyed(const LayoutBlock& block) { 671 void FrameSelection::layoutBlockWillBeDestroyed(const LayoutBlock& block) {
742 m_frameCaret->layoutBlockWillBeDestroyed(block); 672 m_frameCaret->layoutBlockWillBeDestroyed(block);
743 } 673 }
744 674
745 void FrameSelection::updateStyleAndLayoutIfNeeded() { 675 void FrameSelection::updateStyleAndLayoutIfNeeded() {
746 m_frameCaret->updateStyleAndLayoutIfNeeded(); 676 m_frameCaret->updateStyleAndLayoutIfNeeded();
747 } 677 }
748 678
749 void FrameSelection::invalidatePaintIfNeeded( 679 void FrameSelection::invalidatePaintIfNeeded(
750 const LayoutBlock& block, 680 const LayoutBlock& block,
751 const PaintInvalidatorContext& context, 681 const PaintInvalidatorContext& context,
752 PaintInvalidationReason reason) { 682 PaintInvalidationReason reason) {
753 m_frameCaret->invalidatePaintIfNeeded(block, context, reason); 683 m_frameCaret->invalidatePaintIfNeeded(block, context, reason);
754 } 684 }
755 685
756 bool FrameSelection::shouldPaintCaret(const LayoutBlock& block) const { 686 bool FrameSelection::shouldPaintCaret(const LayoutBlock& block) const {
757 DCHECK(selection().isValidFor(document())); 687 DCHECK_GE(document().lifecycle().state(), DocumentLifecycle::LayoutClean);
758
759 bool result = m_frameCaret->shouldPaintCaret(block); 688 bool result = m_frameCaret->shouldPaintCaret(block);
760 DCHECK(!result || (isCaret() && hasEditableStyle())); 689 DCHECK(!result || (isCaret() && hasEditableStyle()));
761 return result; 690 return result;
762 } 691 }
763 692
764 IntRect FrameSelection::absoluteCaretBounds() { 693 IntRect FrameSelection::absoluteCaretBounds() {
765 DCHECK(selection().isValidFor(*m_frame->document())); 694 DCHECK(selection().isValidFor(*m_frame->document()));
766 return m_frameCaret->absoluteCaretBounds(); 695 return m_frameCaret->absoluteCaretBounds();
767 } 696 }
768 697
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after
1068 997
1069 void FrameSelection::commitAppearanceIfNeeded(LayoutView& layoutView) { 998 void FrameSelection::commitAppearanceIfNeeded(LayoutView& layoutView) {
1070 return m_pendingSelection->commit(layoutView); 999 return m_pendingSelection->commit(layoutView);
1071 } 1000 }
1072 1001
1073 void FrameSelection::didLayout() { 1002 void FrameSelection::didLayout() {
1074 updateAppearance(); 1003 updateAppearance();
1075 } 1004 }
1076 1005
1077 void FrameSelection::updateAppearance() { 1006 void FrameSelection::updateAppearance() {
1078 m_frameCaret->updateAppearance(); 1007 DCHECK(!m_frame->contentLayoutItem().isNull());
1079 1008 m_frameCaret->scheduleVisualUpdateForPaintInvalidationIfNeeded();
1080 if (m_frame->contentLayoutItem().isNull())
1081 return;
1082 m_pendingSelection->setHasPendingSelection(); 1009 m_pendingSelection->setHasPendingSelection();
1083 } 1010 }
1084 1011
1085 void FrameSelection::notifyLayoutObjectOfSelectionChange( 1012 void FrameSelection::notifyLayoutObjectOfSelectionChange(
1086 EUserTriggered userTriggered) { 1013 EUserTriggered userTriggered) {
1087 if (TextControlElement* textControl = enclosingTextControl(start())) 1014 if (TextControlElement* textControl = enclosingTextControl(start()))
1088 textControl->selectionChanged(userTriggered == UserTriggered); 1015 textControl->selectionChanged(userTriggered == UserTriggered);
1089 } 1016 }
1090 1017
1091 // Helper function that tells whether a particular node is an element that has 1018 // Helper function that tells whether a particular node is an element that has
(...skipping 182 matching lines...) Expand 10 before | Expand all | Expand 10 after
1274 1201
1275 Document* document = m_frame->document(); 1202 Document* document = m_frame->document();
1276 if (!isNone() || !(blink::hasEditableStyle(*document))) 1203 if (!isNone() || !(blink::hasEditableStyle(*document)))
1277 return; 1204 return;
1278 1205
1279 Element* documentElement = document->documentElement(); 1206 Element* documentElement = document->documentElement();
1280 if (!documentElement) 1207 if (!documentElement)
1281 return; 1208 return;
1282 if (HTMLBodyElement* body = 1209 if (HTMLBodyElement* body =
1283 Traversal<HTMLBodyElement>::firstChild(*documentElement)) { 1210 Traversal<HTMLBodyElement>::firstChild(*documentElement)) {
1284 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
1285 // needs to be audited. See http://crbug.com/590369 for more details.
1286 document->updateStyleAndLayoutIgnorePendingStylesheets();
1287
1288 setSelection(SelectionInDOMTree::Builder() 1211 setSelection(SelectionInDOMTree::Builder()
1289 .collapse(firstPositionInOrBeforeNode(body)) 1212 .collapse(firstPositionInOrBeforeNode(body))
1290 .build()); 1213 .build());
1291 } 1214 }
1292 } 1215 }
1293 1216
1294 // TODO(yoichio): We should have LocalFrame having FrameCaret, 1217 // TODO(yoichio): We should have LocalFrame having FrameCaret,
1295 // Editor and PendingSelection using FrameCaret directly 1218 // Editor and PendingSelection using FrameCaret directly
1296 // and get rid of this. 1219 // and get rid of this.
1297 bool FrameSelection::shouldShowBlockCursor() const { 1220 bool FrameSelection::shouldShowBlockCursor() const {
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after
1388 FrameSelection::DoNotClearStrategy | UserTriggered, 1311 FrameSelection::DoNotClearStrategy | UserTriggered,
1389 CursorAlignOnScroll::IfNeeded, CharacterGranularity); 1312 CursorAlignOnScroll::IfNeeded, CharacterGranularity);
1390 } 1313 }
1391 1314
1392 // TODO(yosin): We should make |FrameSelection::moveRangeSelection()| to take 1315 // TODO(yosin): We should make |FrameSelection::moveRangeSelection()| to take
1393 // two |IntPoint| instead of two |VisiblePosition| like 1316 // two |IntPoint| instead of two |VisiblePosition| like
1394 // |moveRangeSelectionExtent()|. 1317 // |moveRangeSelectionExtent()|.
1395 void FrameSelection::moveRangeSelection(const VisiblePosition& basePosition, 1318 void FrameSelection::moveRangeSelection(const VisiblePosition& basePosition,
1396 const VisiblePosition& extentPosition, 1319 const VisiblePosition& extentPosition,
1397 TextGranularity granularity) { 1320 TextGranularity granularity) {
1398 VisibleSelection newSelection = createVisibleSelection( 1321 SelectionInDOMTree newSelection =
1399 SelectionInDOMTree::Builder() 1322 SelectionInDOMTree::Builder()
1400 .setBaseAndExtentDeprecated(basePosition.deepEquivalent(), 1323 .setBaseAndExtentDeprecated(basePosition.deepEquivalent(),
1401 extentPosition.deepEquivalent()) 1324 extentPosition.deepEquivalent())
1402 .setAffinity(basePosition.affinity()) 1325 .setAffinity(basePosition.affinity())
1403 .setGranularity(granularity) 1326 .setGranularity(granularity)
1404 .build()); 1327 .setIsHandleVisible(isHandleVisible())
1328 .build();
1405 1329
1406 if (newSelection.isNone()) 1330 if (newSelection.isNone())
1407 return; 1331 return;
1408 1332
1409 setSelection(newSelection, m_handleVisibility, CloseTyping | ClearTypingStyle, 1333 setSelection(newSelection, CloseTyping | ClearTypingStyle,
1410 CursorAlignOnScroll::IfNeeded, granularity); 1334 CursorAlignOnScroll::IfNeeded, granularity);
1411 } 1335 }
1412 1336
1413 void FrameSelection::updateIfNeeded() { 1337 void FrameSelection::updateIfNeeded() {
1414 DCHECK(!m_frame->document()->needsLayoutTreeUpdate()); 1338 DCHECK(!m_frame->document()->needsLayoutTreeUpdate());
1415 m_selectionEditor->updateIfNeeded(); 1339 m_selectionEditor->updateIfNeeded();
1416 } 1340 }
1417 1341
1418 void FrameSelection::setCaretVisible(bool caretIsVisible) { 1342 void FrameSelection::setCaretVisible(bool caretIsVisible) {
1419 m_frameCaret->setCaretVisibility(caretIsVisible ? CaretVisibility::Visible 1343 m_frameCaret->setCaretVisibility(caretIsVisible ? CaretVisibility::Visible
(...skipping 29 matching lines...) Expand all
1449 } 1373 }
1450 1374
1451 void showTree(const blink::FrameSelection* sel) { 1375 void showTree(const blink::FrameSelection* sel) {
1452 if (sel) 1376 if (sel)
1453 sel->showTreeForThis(); 1377 sel->showTreeForThis();
1454 else 1378 else
1455 LOG(INFO) << "Cannot showTree for <null> FrameSelection."; 1379 LOG(INFO) << "Cannot showTree for <null> FrameSelection.";
1456 } 1380 }
1457 1381
1458 #endif 1382 #endif
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698