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

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

Issue 1958093002: CONTINUED Make FrameSelection to hold non-canonicalized positions Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: 2017-01-16T20:04:35 Created 3 years, 11 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 74 matching lines...) Expand 10 before | Expand all | Expand 10 after
85 #define EDIT_DEBUG 0 85 #define EDIT_DEBUG 0
86 86
87 namespace blink { 87 namespace blink {
88 88
89 using namespace HTMLNames; 89 using namespace HTMLNames;
90 90
91 static inline bool shouldAlwaysUseDirectionalSelection(LocalFrame* frame) { 91 static inline bool shouldAlwaysUseDirectionalSelection(LocalFrame* frame) {
92 return frame->editor().behavior().shouldConsiderSelectionAsDirectional(); 92 return frame->editor().behavior().shouldConsiderSelectionAsDirectional();
93 } 93 }
94 94
95 FrameSelection* FrameSelection::create(LocalFrame& frame) {
96 return new FrameSelection(frame);
97 }
98
95 FrameSelection::FrameSelection(LocalFrame& frame) 99 FrameSelection::FrameSelection(LocalFrame& frame)
96 : m_frame(frame), 100 : m_frame(frame),
97 m_pendingSelection(PendingSelection::create(*this)), 101 m_pendingSelection(PendingSelection::create(*this)),
98 m_selectionEditor(SelectionEditor::create(frame)), 102 m_selectionEditor(SelectionEditor::create(frame)),
99 m_granularity(CharacterGranularity), 103 m_granularity(CharacterGranularity),
100 m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation()), 104 m_xPosForVerticalArrowNavigation(NoXPosForVerticalArrowNavigation()),
101 m_focused(frame.page() && 105 m_focused(frame.page() &&
102 frame.page()->focusController().focusedFrame() == frame), 106 frame.page()->focusController().focusedFrame() == frame),
103 m_frameCaret(new FrameCaret(frame, *m_selectionEditor)) {} 107 m_frameCaret(new FrameCaret(frame, *m_selectionEditor)) {}
104 108
105 FrameSelection::~FrameSelection() {} 109 FrameSelection::~FrameSelection() {}
106 110
107 const DisplayItemClient& FrameSelection::caretDisplayItemClientForTesting() 111 const DisplayItemClient& FrameSelection::caretDisplayItemClientForTesting()
108 const { 112 const {
109 return *m_frameCaret; 113 return m_frameCaret->displayItemClient();
110 } 114 }
111 115
112 const Document& FrameSelection::document() const { 116 Document& FrameSelection::document() const {
113 DCHECK(m_document); 117 DCHECK(lifecycleContext());
114 return *m_document; 118 return *lifecycleContext();
115 } 119 }
116 120
117 Document& FrameSelection::document() { 121 const VisibleSelection& FrameSelection::computeVisibleSelectionInDOMTree()
118 DCHECK(m_document); 122 const {
119 return *m_document; 123 return m_selectionEditor->computeVisibleSelectionInDOMTree();
120 } 124 }
121 125
122 // TODO(yosin): To avoid undefined symbols in clang, we explicitly 126 const VisibleSelectionInFlatTree&
123 // have specialized version of |FrameSelection::visibleSelection<Strategy>| 127 FrameSelection::computeVisibleSelectionInFlatTree() const {
124 // before |FrameSelection::selection()| which refers this. 128 return m_selectionEditor->computeVisibleSelectionInFlatTree();
125 template <>
126 const VisibleSelection& FrameSelection::visibleSelection<EditingStrategy>()
127 const {
128 return m_selectionEditor->visibleSelection<EditingStrategy>();
129 } 129 }
130 130
131 template <> 131 const SelectionInDOMTree& FrameSelection::selectionInDOMTree() const {
132 const VisibleSelectionInFlatTree& 132 return m_selectionEditor->selectionInDOMTree();
133 FrameSelection::visibleSelection<EditingInFlatTreeStrategy>() const {
134 return m_selectionEditor->visibleSelection<EditingInFlatTreeStrategy>();
135 } 133 }
136 134
137 Element* FrameSelection::rootEditableElementOrDocumentElement() const { 135 Element* FrameSelection::rootEditableElementOrDocumentElement() const {
138 Element* selectionRoot = selection().rootEditableElement(); 136 Element* selectionRoot = selection().rootEditableElement();
139 return selectionRoot ? selectionRoot : document().documentElement(); 137 return selectionRoot ? selectionRoot : document().documentElement();
140 } 138 }
141 139
142 ContainerNode* FrameSelection::rootEditableElementOrTreeScopeRootNode() const { 140 ContainerNode* FrameSelection::rootEditableElementOrTreeScopeRootNode() const {
143 Element* selectionRoot = selection().rootEditableElement(); 141 Element* selectionRoot = selection().rootEditableElement();
144 if (selectionRoot) 142 if (selectionRoot)
145 return selectionRoot; 143 return selectionRoot;
146 144
147 Node* node = selection().base().computeContainerNode(); 145 Node* node = selection().base().computeContainerNode();
148 return node ? &node->treeScope().rootNode() : 0; 146 return node ? &node->treeScope().rootNode() : 0;
149 } 147 }
150 148
149 // TODO(yosin): We should rename |FrameSelection::selection()| to
150 // |selectionDeprecated()|.
151 const VisibleSelection& FrameSelection::selection() const { 151 const VisibleSelection& FrameSelection::selection() const {
152 return visibleSelection<EditingStrategy>(); 152 // TODO(yosin): We should hoist updateStyleAndLayoutIgnorePendingStylesheets
153 } 153 // to caller. See http://crbug.com/590369 for more details.
154 154 document().updateStyleAndLayoutIgnorePendingStylesheets();
155 const VisibleSelectionInFlatTree& FrameSelection::selectionInFlatTree() const { 155 return computeVisibleSelectionInDOMTree();
156 return visibleSelection<EditingInFlatTreeStrategy>();
157 } 156 }
158 157
159 void FrameSelection::moveCaretSelection(const IntPoint& point) { 158 void FrameSelection::moveCaretSelection(const IntPoint& point) {
160 DCHECK(!document().needsLayoutTreeUpdate()); 159 DCHECK(!document().needsLayoutTreeUpdate());
161 160
162 Element* const editable = rootEditableElement(); 161 Element* const editable = rootEditableElement();
163 if (!editable) 162 if (!editable)
164 return; 163 return;
165 164
166 const VisiblePosition position = 165 const VisiblePosition position =
167 visiblePositionForContentsPoint(point, frame()); 166 visiblePositionForContentsPoint(point, frame());
168 SelectionInDOMTree::Builder builder; 167 SelectionInDOMTree::Builder builder;
169 builder.setIsDirectional(selection().isDirectional()); 168 builder.setIsDirectional(selection().isDirectional());
170 if (position.isNotNull()) 169 if (position.isNotNull())
171 builder.collapse(position.toPositionWithAffinity()); 170 builder.collapse(position.toPositionWithAffinity());
172 setSelection(builder.build(), CloseTyping | ClearTypingStyle | UserTriggered); 171 setSelection(builder.build(), CloseTyping | ClearTypingStyle | UserTriggered);
173 } 172 }
174 173
175 template <typename Strategy> 174 void FrameSelection::setSelection(const SelectionInDOMTree& passedSelection,
176 void FrameSelection::setSelectionAlgorithm( 175 SetSelectionOptions options,
177 const VisibleSelectionTemplate<Strategy>& newSelection, 176 CursorAlignOnScroll align,
178 SetSelectionOptions options, 177 TextGranularity granularity) {
179 CursorAlignOnScroll align,
180 TextGranularity granularity) {
181 DCHECK(isAvailable()); 178 DCHECK(isAvailable());
182 DCHECK(newSelection.isValidFor(document())); 179 passedSelection.assertValidFor(document());
183 const Document& currentDocument = document(); 180
181 SelectionInDOMTree::Builder builder(passedSelection);
182 if (shouldAlwaysUseDirectionalSelection(m_frame))
183 builder.setIsDirectional(true);
184 SelectionInDOMTree newSelection = builder.build();
184 if (m_granularityStrategy && 185 if (m_granularityStrategy &&
185 (options & FrameSelection::DoNotClearStrategy) == 0) 186 (options & FrameSelection::DoNotClearStrategy) == 0)
186 m_granularityStrategy->Clear(); 187 m_granularityStrategy->Clear();
187 bool closeTyping = options & CloseTyping; 188 bool closeTyping = options & CloseTyping;
188 bool shouldClearTypingStyle = options & ClearTypingStyle; 189 bool shouldClearTypingStyle = options & ClearTypingStyle;
189 EUserTriggered userTriggered = selectionOptionsToUserTriggered(options);
190
191 // TODO(editing-dev): We should rename variable |s| to another name to avoid
192 // using one letter variable name.
193 VisibleSelectionTemplate<Strategy> s = newSelection;
194 if (shouldAlwaysUseDirectionalSelection(m_frame))
195 s.setIsDirectional(true);
196 190
197 m_granularity = granularity; 191 m_granularity = granularity;
198 192
199 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to 193 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to
200 // |Editor| class. 194 // |Editor| class.
201 if (closeTyping) 195 if (closeTyping)
202 TypingCommand::closeTyping(m_frame); 196 TypingCommand::closeTyping(m_frame);
203 197
204 if (shouldClearTypingStyle) 198 if (shouldClearTypingStyle)
205 clearTypingStyle(); 199 clearTypingStyle();
206 200
207 if (m_selectionEditor->visibleSelection<Strategy>() == s) { 201 const SelectionInDOMTree oldSelectionInDOMTree =
208 // Even if selection was not changed, selection offsets may have been 202 m_selectionEditor->selectionInDOMTree();
209 // changed. 203 if (oldSelectionInDOMTree == newSelection)
210 m_frame->inputMethodController().cancelCompositionIfSelectionIsInvalid();
211 notifyLayoutObjectOfSelectionChange(userTriggered);
212 return; 204 return;
213 } 205 m_selectionEditor->setSelection(newSelection);
214 206
215 const VisibleSelectionTemplate<Strategy> oldSelection = 207 // TODO(yosin): The use of updateStyleAndLayoutIgnorePendingStylesheets
216 visibleSelection<Strategy>(); 208 // needs to be audited. see http://crbug.com/590369 for more details.
217 const Position& oldSelectionStart = selection().start(); 209 document().updateStyleAndLayoutIgnorePendingStylesheets();
218 210
219 m_selectionEditor->setVisibleSelection(s, options); 211 const Document& currentDocument = document();
220 m_frameCaret->setCaretRectNeedsUpdate(); 212 // TODO(yosin): We should get rid of unsued |options| for
213 // |Editor::respondToChangedSelection()|.
214 // Note: Since, setting focus can modify DOM tree, we should use
215 // |oldSelection| before setting focus
216 m_frame->editor().respondToChangedSelection(
217 createVisibleSelection(oldSelectionInDOMTree).start(), options);
218 DCHECK_EQ(currentDocument, document());
221 219
222 if (!s.isNone() && !(options & DoNotSetFocus)) { 220 if (!selection().isNone() && !(options & DoNotSetFocus)) {
223 setFocusedNodeIfNeeded(); 221 setFocusedNodeIfNeeded();
224 // |setFocusedNodeIfNeeded()| dispatches sync events "FocusOut" and 222 // |setFocusedNodeIfNeeded()| dispatches sync events "FocusOut" and
225 // "FocusIn", |m_frame| may associate to another document. 223 // "FocusIn", |m_frame| may associate to another document.
226 if (!isAvailable() || document() != currentDocument) { 224 if (!isAvailable() || document() != currentDocument) {
227 // Once we get test case to reach here, we should change this 225 // Once we get test case to reach here, we should change this
228 // if-statement to |DCHECK()|. 226 // if-statement to |DCHECK()|.
229 NOTREACHED(); 227 NOTREACHED();
230 return; 228 return;
231 } 229 }
232 } 230 }
233 231 updateAppearance();
234 if (!(options & DoNotUpdateAppearance)) {
235 // Hits in
236 // compositing/overflow/do-not-paint-outline-into-composited-scrolling-conte nts.html
237 DisableCompositingQueryAsserts disabler;
238 m_frameCaret->stopCaretBlinkTimer();
239 updateAppearance();
240 }
241 232
242 // Always clear the x position used for vertical arrow navigation. 233 // Always clear the x position used for vertical arrow navigation.
243 // It will be restored by the vertical arrow navigation code if necessary. 234 // It will be restored by the vertical arrow navigation code if necessary.
244 m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation(); 235 m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation();
236 // TODO(yosin): Can we move this to at end of this function?
245 // This may dispatch a synchronous focus-related events. 237 // This may dispatch a synchronous focus-related events.
246 selectFrameElementInParentIfFullySelected(); 238 selectFrameElementInParentIfFullySelected();
247 if (!isAvailable() || document() != currentDocument) { 239 if (!isAvailable() || document() != currentDocument) {
248 // editing/selection/selectallchildren-crash.html and 240 // editing/selection/selectallchildren-crash.html and
249 // editing/selection/longpress-selection-in-iframe-removed-crash.html 241 // editing/selection/longpress-selection-in-iframe-removed-crash.html
250 // reach here. 242 // reach here.
251 return; 243 return;
252 } 244 }
245 EUserTriggered userTriggered = selectionOptionsToUserTriggered(options);
253 notifyLayoutObjectOfSelectionChange(userTriggered); 246 notifyLayoutObjectOfSelectionChange(userTriggered);
254 // If the selections are same in the DOM tree but not in the flat tree,
255 // don't fire events. For example, if the selection crosses shadow tree
256 // boundary, selection for the DOM tree is shrunk while that for the
257 // flat tree is not. Additionally, this case occurs in some edge cases.
258 // See also: editing/pasteboard/4076267-3.html
259 if (oldSelection == m_selectionEditor->visibleSelection<Strategy>()) {
260 m_frame->inputMethodController().cancelCompositionIfSelectionIsInvalid();
261 return;
262 }
263 m_frame->editor().respondToChangedSelection(oldSelectionStart, options);
264 if (userTriggered == UserTriggered) { 247 if (userTriggered == UserTriggered) {
265 ScrollAlignment alignment; 248 ScrollAlignment alignment;
266 249
267 if (m_frame->editor().behavior().shouldCenterAlignWhenSelectionIsRevealed()) 250 if (m_frame->editor().behavior().shouldCenterAlignWhenSelectionIsRevealed())
268 alignment = (align == CursorAlignOnScroll::Always) 251 alignment = (align == CursorAlignOnScroll::Always)
269 ? ScrollAlignment::alignCenterAlways 252 ? ScrollAlignment::alignCenterAlways
270 : ScrollAlignment::alignCenterIfNeeded; 253 : ScrollAlignment::alignCenterIfNeeded;
271 else 254 else
272 alignment = (align == CursorAlignOnScroll::Always) 255 alignment = (align == CursorAlignOnScroll::Always)
273 ? ScrollAlignment::alignTopAlways 256 ? ScrollAlignment::alignTopAlways
274 : ScrollAlignment::alignToEdgeIfNeeded; 257 : ScrollAlignment::alignToEdgeIfNeeded;
275 258
259 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
260 // needs to be audited. See http://crbug.com/590369 for more details.
261 document().updateStyleAndLayoutIgnorePendingStylesheets();
262
276 revealSelection(alignment, RevealExtent); 263 revealSelection(alignment, RevealExtent);
277 } 264 }
278 265
279 notifyAccessibilityForSelectionChange(); 266 notifyAccessibilityForSelectionChange();
280 notifyCompositorForSelectionChange(); 267 notifyCompositorForSelectionChange();
281 notifyEventHandlerForSelectionChange(); 268 notifyEventHandlerForSelectionChange();
282 m_frame->domWindow()->enqueueDocumentEvent( 269 m_frame->domWindow()->enqueueDocumentEvent(
283 Event::create(EventTypeNames::selectionchange)); 270 Event::create(EventTypeNames::selectionchange));
284 } 271 }
285 272
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), options, align,
301 granularity);
302 }
303
304 // TODO(yosin): We will make |selectionInFlatTree| version of |SetSelection()|
305 // as primary function instead of wrapper.
306 void FrameSelection::setSelection(const SelectionInFlatTree& newSelection, 273 void FrameSelection::setSelection(const SelectionInFlatTree& newSelection,
307 SetSelectionOptions options, 274 SetSelectionOptions options,
308 CursorAlignOnScroll align, 275 CursorAlignOnScroll align,
309 TextGranularity granularity) { 276 TextGranularity granularity) {
310 if (!newSelection.isNone()) { 277 newSelection.assertValidFor(document());
311 // TODO(editing-dev): The use of 278 SelectionInDOMTree::Builder builder;
312 // updateStyleAndLayoutIgnorePendingStylesheets 279 builder.setAffinity(newSelection.affinity())
313 // needs to be audited. See http://crbug.com/590369 for more details. 280 .setBaseAndExtent(toPositionInDOMTree(newSelection.base()),
314 newSelection.base() 281 toPositionInDOMTree(newSelection.extent()))
315 .document() 282 .setGranularity(newSelection.granularity())
316 ->updateStyleAndLayoutIgnorePendingStylesheets(); 283 .setIsDirectional(newSelection.isDirectional())
317 } 284 .setHasTrailingWhitespace(newSelection.hasTrailingWhitespace());
318 setSelection(createVisibleSelection(newSelection), options, align, 285 return setSelection(builder.build(), options, align, granularity);
319 granularity);
320 } 286 }
321 287
322 void FrameSelection::setSelection(const VisibleSelection& newSelection, 288 void FrameSelection::setSelection(const VisibleSelection& newSelection,
323 SetSelectionOptions options, 289 SetSelectionOptions options,
324 CursorAlignOnScroll align, 290 CursorAlignOnScroll align,
325 TextGranularity granularity) { 291 TextGranularity granularity) {
326 setSelectionAlgorithm<EditingStrategy>(newSelection, options, align, 292 setSelection(newSelection.asSelection(), options, align, granularity);
327 granularity);
328 } 293 }
329 294
330 void FrameSelection::setSelection( 295 void FrameSelection::setSelection(
331 const VisibleSelectionInFlatTree& newSelection, 296 const VisibleSelectionInFlatTree& newSelection,
332 SetSelectionOptions options, 297 SetSelectionOptions options,
333 CursorAlignOnScroll align, 298 CursorAlignOnScroll align,
334 TextGranularity granularity) { 299 TextGranularity granularity) {
335 setSelectionAlgorithm<EditingInFlatTreeStrategy>(newSelection, options, align, 300 setSelection(newSelection.asSelection(), options, align, granularity);
336 granularity);
337 }
338
339 static bool removingNodeRemovesPosition(Node& node, const Position& position) {
340 if (!position.anchorNode())
341 return false;
342
343 if (position.anchorNode() == node)
344 return true;
345
346 if (!node.isElementNode())
347 return false;
348
349 Element& element = toElement(node);
350 return element.isShadowIncludingInclusiveAncestorOf(position.anchorNode());
351 }
352
353 static Position computePositionForChildrenRemoval(const Position& position,
354 ContainerNode& container) {
355 Node* node = position.computeContainerNode();
356 if (container.containsIncludingHostElements(*node))
357 return Position::firstPositionInNode(&container);
358 return position;
359 } 301 }
360 302
361 void FrameSelection::nodeChildrenWillBeRemoved(ContainerNode& container) { 303 void FrameSelection::nodeChildrenWillBeRemoved(ContainerNode& container) {
362 if (isNone() || !container.inActiveDocument()) 304 if (!container.inActiveDocument())
363 return; 305 return;
364 const Position& oldStart = selection().start();
365 const Position& newStart =
366 computePositionForChildrenRemoval(oldStart, container);
367 const Position& oldEnd = selection().end();
368 const Position& newEnd = computePositionForChildrenRemoval(oldEnd, container);
369 const Position& oldBase = selection().base();
370 const Position& newBase =
371 computePositionForChildrenRemoval(oldBase, container);
372 const Position& oldExtent = selection().extent();
373 const Position& newExtent =
374 computePositionForChildrenRemoval(oldExtent, container);
375 if (newStart == oldStart && newEnd == oldEnd && newBase == oldBase &&
376 newExtent == oldExtent)
377 return;
378 if (selection().isBaseFirst())
379 m_selectionEditor->setWithoutValidation(newStart, newEnd);
380 else
381 m_selectionEditor->setWithoutValidation(newEnd, newStart);
382 m_frameCaret->setCaretRectNeedsUpdate();
383 if (document().isRunningExecCommand())
384 return;
385 TypingCommand::closeTyping(m_frame);
386 }
387
388 void FrameSelection::nodeWillBeRemoved(Node& node) {
389 // There can't be a selection inside a fragment, so if a fragment's node is
390 // being removed, the selection in the document that created the fragment
391 // needs no adjustment.
392 if (isNone() || !node.inActiveDocument())
393 return;
394
395 respondToNodeModification(
396 node, removingNodeRemovesPosition(node, selection().base()),
397 removingNodeRemovesPosition(node, selection().extent()),
398 removingNodeRemovesPosition(node, selection().start()),
399 removingNodeRemovesPosition(node, selection().end()));
400
401 m_frameCaret->nodeWillBeRemoved(node);
402 }
403
404 static SelectionState selectionStateOf(const Node& node) {
405 const LayoutObject* layoutObject = node.layoutObject();
406 if (!layoutObject)
407 return SelectionNone;
408 return layoutObject->getSelectionState();
409 }
410
411 void FrameSelection::respondToNodeModification(Node& node,
412 bool baseRemoved,
413 bool extentRemoved,
414 bool startRemoved,
415 bool endRemoved) {
416 DCHECK(node.document().isActive()) << node;
417
418 bool clearLayoutTreeSelection = false;
419 bool clearDOMTreeSelection = false;
420
421 if (startRemoved || endRemoved) {
422 Position start = selection().start();
423 Position end = selection().end();
424 if (startRemoved)
425 updatePositionForNodeRemoval(start, node);
426 if (endRemoved)
427 updatePositionForNodeRemoval(end, node);
428
429 if (Position::commonAncestorTreeScope(start, end) && start.isNotNull() &&
430 end.isNotNull()) {
431 if (selection().isBaseFirst())
432 m_selectionEditor->setWithoutValidation(start, end);
433 else
434 m_selectionEditor->setWithoutValidation(end, start);
435 } else {
436 clearDOMTreeSelection = true;
437 }
438
439 clearLayoutTreeSelection = true;
440 } else if (baseRemoved || extentRemoved) {
441 // The base and/or extent are about to be removed, but the start and end
442 // aren't. Change the base and extent to the start and end, but don't
443 // re-validate the selection, since doing so could move the start and end
444 // into the node that is about to be removed.
445 if (selection().isBaseFirst())
446 m_selectionEditor->setWithoutValidation(selection().start(),
447 selection().end());
448 else
449 m_selectionEditor->setWithoutValidation(selection().end(),
450 selection().start());
451 } else if (selectionStateOf(node) != SelectionNone) {
452 // When node to be removed is part of selection, we invalidate
453 // selection to paint again.
454 // TODO(yosin): We should paint changed area only rather than whole
455 // selected range.
456 clearLayoutTreeSelection = true;
457 }
458
459 if (clearLayoutTreeSelection)
460 selection().start().document()->layoutViewItem().clearSelection();
461
462 if (clearDOMTreeSelection)
463 setSelection(SelectionInDOMTree(), DoNotSetFocus);
464 m_frameCaret->setCaretRectNeedsUpdate();
465
466 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to 306 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to
467 // |Editor| class. 307 // |Editor| class.
468 if (!document().isRunningExecCommand()) 308 if (!document().isRunningExecCommand())
469 TypingCommand::closeTyping(m_frame); 309 TypingCommand::closeTyping(m_frame);
470 } 310 }
471 311
472 static Position updatePositionAfterAdoptingTextReplacement( 312 void FrameSelection::nodeWillBeRemoved(Node& node) {
473 const Position& position, 313 // There can't be a selection inside a fragment, so if a fragment's node is
474 CharacterData* node, 314 // being removed,
475 unsigned offset, 315 // the selection in the document that created the fragment needs no
476 unsigned oldLength, 316 // adjustment.
477 unsigned newLength) { 317 if (!node.inActiveDocument())
478 if (!position.anchorNode() || position.anchorNode() != node ||
479 !position.isOffsetInAnchor())
480 return position;
481
482 // See:
483 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range- Mutation
484 DCHECK_GE(position.offsetInContainerNode(), 0);
485 unsigned positionOffset =
486 static_cast<unsigned>(position.offsetInContainerNode());
487 // Replacing text can be viewed as a deletion followed by insertion.
488 if (positionOffset >= offset && positionOffset <= offset + oldLength)
489 positionOffset = offset;
490
491 // Adjust the offset if the position is after the end of the deleted contents
492 // (positionOffset > offset + oldLength) to avoid having a stale offset.
493 if (positionOffset > offset + oldLength)
494 positionOffset = positionOffset - oldLength + newLength;
495
496 // Due to case folding
497 // (http://unicode.org/Public/UCD/latest/ucd/CaseFolding.txt), LayoutText
498 // length may be different from Text length. A correct implementation would
499 // translate the LayoutText offset to a Text offset; this is just a safety
500 // precaution to avoid offset values that run off the end of the Text.
501 if (positionOffset > node->length())
502 positionOffset = node->length();
503
504 // CharacterNode in VisibleSelection must be Text node, because Comment
505 // and ProcessingInstruction node aren't visible.
506 return Position(toText(node), positionOffset);
507 }
508
509 void FrameSelection::didUpdateCharacterData(CharacterData* node,
510 unsigned offset,
511 unsigned oldLength,
512 unsigned newLength) {
513 // The fragment check is a performance optimization. See
514 // http://trac.webkit.org/changeset/30062.
515 if (isNone() || !node || !node->isConnected())
516 return;
517
518 Position base = updatePositionAfterAdoptingTextReplacement(
519 selection().base(), node, offset, oldLength, newLength);
520 Position extent = updatePositionAfterAdoptingTextReplacement(
521 selection().extent(), node, offset, oldLength, newLength);
522 Position start = updatePositionAfterAdoptingTextReplacement(
523 selection().start(), node, offset, oldLength, newLength);
524 Position end = updatePositionAfterAdoptingTextReplacement(
525 selection().end(), node, offset, oldLength, newLength);
526 updateSelectionIfNeeded(base, extent, start, end);
527 }
528
529 static Position updatePostionAfterAdoptingTextNodesMerged(
530 const Position& position,
531 const Text& oldNode,
532 unsigned offset) {
533 if (!position.anchorNode() || !position.isOffsetInAnchor())
534 return position;
535
536 DCHECK_GE(position.offsetInContainerNode(), 0);
537 unsigned positionOffset =
538 static_cast<unsigned>(position.offsetInContainerNode());
539
540 if (position.anchorNode() == &oldNode)
541 return Position(toText(oldNode.previousSibling()), positionOffset + offset);
542
543 if (position.anchorNode() == oldNode.parentNode() && positionOffset == offset)
544 return Position(toText(oldNode.previousSibling()), offset);
545
546 return position;
547 }
548
549 void FrameSelection::didMergeTextNodes(const Text& oldNode, unsigned offset) {
550 if (isNone() || !oldNode.isConnected())
551 return;
552 Position base = updatePostionAfterAdoptingTextNodesMerged(selection().base(),
553 oldNode, offset);
554 Position extent = updatePostionAfterAdoptingTextNodesMerged(
555 selection().extent(), oldNode, offset);
556 Position start = updatePostionAfterAdoptingTextNodesMerged(
557 selection().start(), oldNode, offset);
558 Position end = updatePostionAfterAdoptingTextNodesMerged(selection().end(),
559 oldNode, offset);
560 updateSelectionIfNeeded(base, extent, start, end);
561 }
562
563 static Position updatePostionAfterAdoptingTextNodeSplit(
564 const Position& position,
565 const Text& oldNode) {
566 if (!position.anchorNode() || position.anchorNode() != &oldNode ||
567 !position.isOffsetInAnchor())
568 return position;
569 // See:
570 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range- Mutation
571 DCHECK_GE(position.offsetInContainerNode(), 0);
572 unsigned positionOffset =
573 static_cast<unsigned>(position.offsetInContainerNode());
574 unsigned oldLength = oldNode.length();
575 if (positionOffset <= oldLength)
576 return position;
577 return Position(toText(oldNode.nextSibling()), positionOffset - oldLength);
578 }
579
580 void FrameSelection::didSplitTextNode(const Text& oldNode) {
581 if (isNone() || !oldNode.isConnected())
582 return;
583 Position base =
584 updatePostionAfterAdoptingTextNodeSplit(selection().base(), oldNode);
585 Position extent =
586 updatePostionAfterAdoptingTextNodeSplit(selection().extent(), oldNode);
587 Position start =
588 updatePostionAfterAdoptingTextNodeSplit(selection().start(), oldNode);
589 Position end =
590 updatePostionAfterAdoptingTextNodeSplit(selection().end(), oldNode);
591 updateSelectionIfNeeded(base, extent, start, end);
592 }
593
594 void FrameSelection::updateSelectionIfNeeded(const Position& base,
595 const Position& extent,
596 const Position& start,
597 const Position& end) {
598 if (base == selection().base() && extent == selection().extent() &&
599 start == selection().start() && end == selection().end())
600 return; 318 return;
601 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to 319 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to
602 // |Editor| class. 320 // |Editor| class.
603 if (!document().isRunningExecCommand()) 321 if (!document().isRunningExecCommand())
604 TypingCommand::closeTyping(m_frame); 322 TypingCommand::closeTyping(m_frame);
605 VisibleSelection newSelection;
606 if (selection().isBaseFirst())
607 newSelection.setWithoutValidation(start, end);
608 else
609 newSelection.setWithoutValidation(end, start);
610 setSelection(newSelection, DoNotSetFocus);
611 } 323 }
612 324
613 void FrameSelection::didChangeFocus() { 325 void FrameSelection::didChangeFocus() {
614 // Hits in 326 // Hits in
615 // virtual/gpu/compositedscrolling/scrollbars/scrollbar-miss-mousemove-disable d.html 327 // virtual/gpu/compositedscrolling/scrollbars/scrollbar-miss-mousemove-disable d.html
616 DisableCompositingQueryAsserts disabler; 328 DisableCompositingQueryAsserts disabler;
617 updateAppearance(); 329 updateAppearance();
618 } 330 }
619 331
620 static DispatchEventResult dispatchSelectStart( 332 static DispatchEventResult dispatchSelectStart(
(...skipping 68 matching lines...) Expand 10 before | Expand all | Expand 10 after
689 401
690 m_granularity = CharacterGranularity; 402 m_granularity = CharacterGranularity;
691 403
692 return true; 404 return true;
693 } 405 }
694 406
695 void FrameSelection::clear() { 407 void FrameSelection::clear() {
696 m_granularity = CharacterGranularity; 408 m_granularity = CharacterGranularity;
697 if (m_granularityStrategy) 409 if (m_granularityStrategy)
698 m_granularityStrategy->Clear(); 410 m_granularityStrategy->Clear();
699 setSelection(SelectionInDOMTree()); 411 setSelection(VisibleSelection());
700 } 412 }
701 413
702 void FrameSelection::documentAttached(Document* document) { 414 void FrameSelection::documentAttached(Document* document) {
703 DCHECK(document); 415 DCHECK(document);
704 DCHECK(!m_document) << "FrameSelection is already attached to " << m_document; 416 m_frameCaret->documentAttached(document);
705 m_document = document;
706 m_useSecureKeyboardEntryWhenActive = false;
707 m_selectionEditor->documentAttached(document); 417 m_selectionEditor->documentAttached(document);
418 setContext(document);
708 } 419 }
709 420
710 void FrameSelection::documentDetached(const Document& document) { 421 void FrameSelection::contextDestroyed(Document*) {
711 DCHECK_EQ(m_document, document);
712 m_document = nullptr;
713 m_granularity = CharacterGranularity; 422 m_granularity = CharacterGranularity;
714 423
715 LayoutViewItem view = m_frame->contentLayoutItem(); 424 LayoutViewItem view = m_frame->contentLayoutItem();
716 if (!view.isNull()) 425 if (!view.isNull())
717 view.clearSelection(); 426 view.clearSelection();
718 427
719 clearTypingStyle(); 428 clearTypingStyle();
720 m_selectionEditor->documentDetached(document);
721 m_frameCaret->documentDetached();
722 } 429 }
723 430
724 LayoutBlock* FrameSelection::caretLayoutObject() const { 431 LayoutBlock* FrameSelection::caretLayoutObject() const {
725 DCHECK(selection().isValidFor(document())); 432 DCHECK(isAvailable());
726 if (!isCaret()) 433 const VisibleSelection& selection = computeVisibleSelectionInDOMTree();
434 if (!selection.isCaret())
727 return nullptr; 435 return nullptr;
728 return CaretBase::caretLayoutObject(selection().start().anchorNode()); 436 return CaretBase::caretLayoutObject(selection.start().anchorNode());
729 } 437 }
730 438
731 IntRect FrameSelection::absoluteCaretBounds() { 439 IntRect FrameSelection::absoluteCaretBounds() {
732 DCHECK(selection().isValidFor(*m_frame->document())); 440 DCHECK(isAvailable());
733 return m_frameCaret->absoluteCaretBounds(); 441 return m_frameCaret->absoluteCaretBounds();
734 } 442 }
735 443
736 void FrameSelection::invalidateCaretRect(bool forceInvalidation) { 444 void FrameSelection::invalidateCaretRect(bool forceInvalidation) {
737 m_frameCaret->invalidateCaretRect(forceInvalidation); 445 m_frameCaret->invalidateCaretRect(forceInvalidation);
738 } 446 }
739 447
740 void FrameSelection::dataWillChange(const CharacterData& node) {
741 m_frameCaret->dataWillChange(node);
742 }
743
744 void FrameSelection::paintCaret(GraphicsContext& context, 448 void FrameSelection::paintCaret(GraphicsContext& context,
745 const LayoutPoint& paintOffset) { 449 const LayoutPoint& paintOffset) {
746 m_frameCaret->paintCaret(context, paintOffset); 450 m_frameCaret->paintCaret(context, paintOffset);
747 } 451 }
748 452
749 bool FrameSelection::contains(const LayoutPoint& point) { 453 bool FrameSelection::contains(const LayoutPoint& point) {
750 if (document().layoutViewItem().isNull()) 454 if (!isAvailable())
751 return false; 455 return false;
752 456
753 // Treat a collapsed selection like no selection. 457 // Treat a collapsed selection like no selection.
754 const VisibleSelectionInFlatTree& visibleSelection = 458 const VisibleSelectionInFlatTree& visibleSelection =
755 this->visibleSelection<EditingInFlatTreeStrategy>(); 459 computeVisibleSelectionInFlatTree();
756 if (!visibleSelection.isRange()) 460 if (!visibleSelection.isRange())
757 return false; 461 return false;
758 462
759 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active); 463 HitTestRequest request(HitTestRequest::ReadOnly | HitTestRequest::Active);
760 HitTestResult result(request, point); 464 HitTestResult result(request, point);
761 document().layoutViewItem().hitTest(result); 465 document().layoutViewItem().hitTest(result);
762 Node* innerNode = result.innerNode(); 466 Node* innerNode = result.innerNode();
763 if (!innerNode || !innerNode->layoutObject()) 467 if (!innerNode || !innerNode->layoutObject())
764 return false; 468 return false;
765 469
(...skipping 10 matching lines...) Expand all
776 return false; 480 return false;
777 481
778 const PositionInFlatTree& start = visibleStart.deepEquivalent(); 482 const PositionInFlatTree& start = visibleStart.deepEquivalent();
779 const PositionInFlatTree& end = visibleEnd.deepEquivalent(); 483 const PositionInFlatTree& end = visibleEnd.deepEquivalent();
780 const PositionInFlatTree& pos = visiblePos.deepEquivalent(); 484 const PositionInFlatTree& pos = visiblePos.deepEquivalent();
781 return start.compareTo(pos) <= 0 && pos.compareTo(end) <= 0; 485 return start.compareTo(pos) <= 0 && pos.compareTo(end) <= 0;
782 } 486 }
783 487
784 // Workaround for the fact that it's hard to delete a frame. 488 // Workaround for the fact that it's hard to delete a frame.
785 // Call this after doing user-triggered selections to make it easy to delete the 489 // Call this after doing user-triggered selections to make it easy to delete the
786 // frame you entirely selected. Can't do this implicitly as part of every 490 // frame you entirely selected.
787 // setSelection call because in some contexts it might not be good for the focus 491 // Can't do this implicitly as part of every setSelection call because in some
788 // to move to another frame. So instead we call it from places where we are 492 // contexts it might not be good
789 // selecting with the mouse or the keyboard after setting the selection. 493 // for the focus to move to another frame. So instead we call it from places
494 // where we are selecting with the
495 // mouse or the keyboard after setting the selection.
790 void FrameSelection::selectFrameElementInParentIfFullySelected() { 496 void FrameSelection::selectFrameElementInParentIfFullySelected() {
791 // Find the parent frame; if there is none, then we have nothing to do. 497 // Find the parent frame; if there is none, then we have nothing to do.
792 Frame* parent = m_frame->tree().parent(); 498 Frame* parent = m_frame->tree().parent();
793 if (!parent) 499 if (!parent)
794 return; 500 return;
795 Page* page = m_frame->page(); 501 Page* page = m_frame->page();
796 if (!page) 502 if (!page)
797 return; 503 return;
798 504
799 // Check if the selection contains the entire frame contents; if not, then 505 // Check if the selection contains the entire frame contents; if not, then
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
905 // |root| may be detached due to selectstart event. 611 // |root| may be detached due to selectstart event.
906 if (!root->isConnected() || expectedDocument != root->document()) 612 if (!root->isConnected() || expectedDocument != root->document())
907 return; 613 return;
908 } 614 }
909 615
910 setSelection(SelectionInDOMTree::Builder().selectAllChildren(*root).build()); 616 setSelection(SelectionInDOMTree::Builder().selectAllChildren(*root).build());
911 selectFrameElementInParentIfFullySelected(); 617 selectFrameElementInParentIfFullySelected();
912 notifyLayoutObjectOfSelectionChange(UserTriggered); 618 notifyLayoutObjectOfSelectionChange(UserTriggered);
913 } 619 }
914 620
621 bool FrameSelection::setSelectedRange(Range* range,
622 TextAffinity affinity,
623 SelectionDirectionalMode directional,
624 SetSelectionOptions options) {
625 if (!range || !range->isConnected())
626 return false;
627 DCHECK_EQ(range->startContainer()->document(),
628 range->endContainer()->document());
629 return setSelectedRange(EphemeralRange(range), affinity, directional,
630 options);
631 }
632
915 bool FrameSelection::setSelectedRange(const EphemeralRange& range, 633 bool FrameSelection::setSelectedRange(const EphemeralRange& range,
916 TextAffinity affinity, 634 TextAffinity affinity,
917 SelectionDirectionalMode directional, 635 SelectionDirectionalMode directional,
918 SetSelectionOptions options) { 636 SetSelectionOptions options) {
919 if (range.isNull()) 637 if (range.isNull())
920 return false; 638 return false;
921 m_selectionEditor->resetLogicalRange(); 639 m_selectionEditor->resetLogicalRange();
922 // Since |FrameSeleciton::setSelection()| dispatches events and DOM tree 640 // Since |FrameSeleciton::setSelection()| dispatches events and DOM tree
923 // can be modified by event handlers, we should create |Range| object before 641 // can be modified by event handlers, we should create |Range| object before
924 // calling it. 642 // calling it.
(...skipping 69 matching lines...) Expand 10 before | Expand all | Expand 10 after
994 // Secure keyboard entry is set by the active frame. 712 // Secure keyboard entry is set by the active frame.
995 if (m_useSecureKeyboardEntryWhenActive) 713 if (m_useSecureKeyboardEntryWhenActive)
996 setUseSecureKeyboardEntry(activeAndFocused); 714 setUseSecureKeyboardEntry(activeAndFocused);
997 } 715 }
998 716
999 void FrameSelection::pageActivationChanged() { 717 void FrameSelection::pageActivationChanged() {
1000 focusedOrActiveStateChanged(); 718 focusedOrActiveStateChanged();
1001 } 719 }
1002 720
1003 void FrameSelection::updateSecureKeyboardEntryIfActive() { 721 void FrameSelection::updateSecureKeyboardEntryIfActive() {
1004 if (!isFocusedAndActive()) 722 if (isFocusedAndActive())
1005 return; 723 setUseSecureKeyboardEntry(m_useSecureKeyboardEntryWhenActive);
1006 setUseSecureKeyboardEntry(m_useSecureKeyboardEntryWhenActive);
1007 } 724 }
1008 725
1009 void FrameSelection::setUseSecureKeyboardEntryWhenActive( 726 void FrameSelection::setUseSecureKeyboardEntryWhenActive(
1010 bool usesSecureKeyboard) { 727 bool usesSecureKeyboard) {
1011 if (m_useSecureKeyboardEntryWhenActive == usesSecureKeyboard) 728 if (m_useSecureKeyboardEntryWhenActive == usesSecureKeyboard)
1012 return; 729 return;
1013 m_useSecureKeyboardEntryWhenActive = usesSecureKeyboard; 730 m_useSecureKeyboardEntryWhenActive = usesSecureKeyboard;
1014 updateSecureKeyboardEntryIfActive(); 731 updateSecureKeyboardEntryIfActive();
1015 } 732 }
1016 733
(...skipping 18 matching lines...) Expand all
1035 } 752 }
1036 753
1037 bool FrameSelection::isAppearanceDirty() const { 754 bool FrameSelection::isAppearanceDirty() const {
1038 return m_pendingSelection->hasPendingSelection(); 755 return m_pendingSelection->hasPendingSelection();
1039 } 756 }
1040 757
1041 void FrameSelection::commitAppearanceIfNeeded(LayoutView& layoutView) { 758 void FrameSelection::commitAppearanceIfNeeded(LayoutView& layoutView) {
1042 return m_pendingSelection->commit(layoutView); 759 return m_pendingSelection->commit(layoutView);
1043 } 760 }
1044 761
762 void FrameSelection::didLayout() {
763 DCHECK_GE(document().lifecycle().state(),
764 DocumentLifecycle::AfterPerformLayout);
765 updateAppearance();
766 }
767
1045 void FrameSelection::updateAppearance() { 768 void FrameSelection::updateAppearance() {
1046 m_frameCaret->updateAppearance(); 769 DCHECK(!m_frame->contentLayoutItem().isNull());
1047 770 m_frameCaret->setCaretRectNeedsUpdate();
1048 if (m_frame->contentLayoutItem().isNull())
1049 return;
1050 m_pendingSelection->setHasPendingSelection(); 771 m_pendingSelection->setHasPendingSelection();
1051 } 772 }
1052 773
1053 void FrameSelection::notifyLayoutObjectOfSelectionChange( 774 void FrameSelection::notifyLayoutObjectOfSelectionChange(
1054 EUserTriggered userTriggered) { 775 EUserTriggered userTriggered) {
1055 if (TextControlElement* textControl = enclosingTextControl(start())) 776 if (TextControlElement* textControl = enclosingTextControl(start()))
1056 textControl->selectionChanged(userTriggered == UserTriggered); 777 textControl->selectionChanged(userTriggered == UserTriggered);
1057 } 778 }
1058 779
1059 // Helper function that tells whether a particular node is an element that has 780 // Helper function that tells whether a particular node is an element that has
(...skipping 26 matching lines...) Expand all
1086 } 807 }
1087 target = target->parentOrShadowHostElement(); 808 target = target->parentOrShadowHostElement();
1088 } 809 }
1089 document().clearFocusedElement(); 810 document().clearFocusedElement();
1090 } 811 }
1091 } 812 }
1092 813
1093 static String extractSelectedText(const FrameSelection& selection, 814 static String extractSelectedText(const FrameSelection& selection,
1094 TextIteratorBehavior behavior) { 815 TextIteratorBehavior behavior) {
1095 const VisibleSelectionInFlatTree& visibleSelection = 816 const VisibleSelectionInFlatTree& visibleSelection =
1096 selection.visibleSelection<EditingInFlatTreeStrategy>(); 817 selection.computeVisibleSelectionInFlatTree();
1097 const EphemeralRangeInFlatTree& range = 818 const EphemeralRangeInFlatTree& range =
1098 visibleSelection.toNormalizedEphemeralRange(); 819 visibleSelection.toNormalizedEphemeralRange();
1099 // We remove '\0' characters because they are not visibly rendered to the 820 // We remove '\0' characters because they are not visibly rendered to the
1100 // user. 821 // user.
1101 return plainText(range, behavior).replace(0, ""); 822 return plainText(range, behavior).replace(0, "");
1102 } 823 }
1103 824
1104 String FrameSelection::selectedHTMLForClipboard() const { 825 String FrameSelection::selectedHTMLForClipboard() const {
1105 const VisibleSelectionInFlatTree& visibleSelection = 826 const VisibleSelectionInFlatTree& visibleSelection =
1106 this->visibleSelection<EditingInFlatTreeStrategy>(); 827 computeVisibleSelectionInFlatTree();
1107 const EphemeralRangeInFlatTree& range = 828 const EphemeralRangeInFlatTree& range =
1108 visibleSelection.toNormalizedEphemeralRange(); 829 visibleSelection.toNormalizedEphemeralRange();
1109 return createMarkup(range.startPosition(), range.endPosition(), 830 return createMarkup(range.startPosition(), range.endPosition(),
1110 AnnotateForInterchange, 831 AnnotateForInterchange,
1111 ConvertBlocksToInlines::NotConvert, ResolveNonLocalURLs); 832 ConvertBlocksToInlines::NotConvert, ResolveNonLocalURLs);
1112 } 833 }
1113 834
1114 String FrameSelection::selectedText(TextIteratorBehavior behavior) const { 835 String FrameSelection::selectedText(TextIteratorBehavior behavior) const {
1115 return extractSelectedText(*this, behavior); 836 return extractSelectedText(*this, behavior);
1116 } 837 }
(...skipping 118 matching lines...) Expand 10 before | Expand all | Expand 10 after
1235 956
1236 Document* document = m_frame->document(); 957 Document* document = m_frame->document();
1237 if (!isNone() || !(blink::hasEditableStyle(*document))) 958 if (!isNone() || !(blink::hasEditableStyle(*document)))
1238 return; 959 return;
1239 960
1240 Element* documentElement = document->documentElement(); 961 Element* documentElement = document->documentElement();
1241 if (!documentElement) 962 if (!documentElement)
1242 return; 963 return;
1243 if (HTMLBodyElement* body = 964 if (HTMLBodyElement* body =
1244 Traversal<HTMLBodyElement>::firstChild(*documentElement)) { 965 Traversal<HTMLBodyElement>::firstChild(*documentElement)) {
1245 // TODO(xiaochengh): The use of updateStyleAndLayoutIgnorePendingStylesheets
1246 // needs to be audited. See http://crbug.com/590369 for more details.
1247 document->updateStyleAndLayoutIgnorePendingStylesheets();
1248
1249 setSelection(SelectionInDOMTree::Builder() 966 setSelection(SelectionInDOMTree::Builder()
1250 .collapse(firstPositionInOrBeforeNode(body)) 967 .collapse(firstPositionInOrBeforeNode(body))
1251 .build()); 968 .build());
1252 } 969 }
1253 } 970 }
1254 971
1255 // TODO(yoichio): We should have LocalFrame having FrameCaret, 972 // TODO(yoichio): We should have LocalFrame having FrameCaret,
1256 // Editor and PendingSelection using FrameCaret directly 973 // Editor and PendingSelection using FrameCaret directly
1257 // and get rid of this. 974 // and get rid of this.
1258 bool FrameSelection::shouldShowBlockCursor() const { 975 bool FrameSelection::shouldShowBlockCursor() const {
1259 return m_frameCaret->shouldShowBlockCursor(); 976 return m_frameCaret->shouldShowBlockCursor();
1260 } 977 }
1261 978
1262 // TODO(yoichio): We should have LocalFrame having FrameCaret, 979 // TODO(yoichio): We should have LocalFrame having FrameCaret,
1263 // Editor and PendingSelection using FrameCaret directly 980 // Editor and PendingSelection using FrameCaret directly
1264 // and get rid of this. 981 // and get rid of this.
1265 // TODO(yoichio): We should use "caret-shape" in "CSS Basic User Interface 982 // TODO(yoichio): We should use "caret-shape" in "CSS Basic User Interface
1266 // Module Level 4" https://drafts.csswg.org/css-ui-4/ 983 // Module Level 4" https://drafts.csswg.org/css-ui-4/
1267 // To use "caret-shape", we need to expose inserting mode information to CSS; 984 // To use "caret-shape", we need to expose inserting mode information to CSS;
1268 // https://github.com/w3c/csswg-drafts/issues/133 985 // https://github.com/w3c/csswg-drafts/issues/133
1269 void FrameSelection::setShouldShowBlockCursor(bool shouldShowBlockCursor) { 986 void FrameSelection::setShouldShowBlockCursor(bool shouldShowBlockCursor) {
1270 m_frameCaret->setShouldShowBlockCursor(shouldShowBlockCursor); 987 m_frameCaret->setShouldShowBlockCursor(shouldShowBlockCursor);
1271 } 988 }
1272 989
990 template <typename Strategy>
991 VisibleSelectionTemplate<Strategy> FrameSelection::validateSelection(
992 const VisibleSelectionTemplate<Strategy>& selection) {
993 if (selection.isNone())
994 return selection;
995
996 const PositionTemplate<Strategy> base = selection.base();
997 const PositionTemplate<Strategy> extent = selection.extent();
998 bool isBaseValid = base.document() == document();
999 bool isExtentValid = extent.document() == document();
1000
1001 if (isBaseValid && isExtentValid)
1002 return selection;
1003
1004 VisibleSelectionTemplate<Strategy> newSelection;
1005 if (isBaseValid) {
1006 newSelection.setWithoutValidation(base, base);
1007 } else if (isExtentValid) {
1008 newSelection.setWithoutValidation(extent, extent);
1009 }
1010 return newSelection;
1011 }
1012
1273 #ifndef NDEBUG 1013 #ifndef NDEBUG
1274 1014
1275 void FrameSelection::showTreeForThis() const { 1015 void FrameSelection::showTreeForThis() const {
1276 selection().showTreeForThis(); 1016 selection().showTreeForThis();
1277 } 1017 }
1278 1018
1279 #endif 1019 #endif
1280 1020
1281 DEFINE_TRACE(FrameSelection) { 1021 DEFINE_TRACE(FrameSelection) {
1282 visitor->trace(m_document);
1283 visitor->trace(m_frame); 1022 visitor->trace(m_frame);
1284 visitor->trace(m_pendingSelection); 1023 visitor->trace(m_pendingSelection);
1285 visitor->trace(m_selectionEditor); 1024 visitor->trace(m_selectionEditor);
1286 visitor->trace(m_typingStyle); 1025 visitor->trace(m_typingStyle);
1287 visitor->trace(m_frameCaret); 1026 visitor->trace(m_frameCaret);
1027 SynchronousMutationObserver::trace(visitor);
1288 } 1028 }
1289 1029
1290 void FrameSelection::scheduleVisualUpdate() const { 1030 void FrameSelection::scheduleVisualUpdate() const {
1291 if (Page* page = m_frame->page()) 1031 if (Page* page = m_frame->page())
1292 page->animator().scheduleVisualUpdate(m_frame->localFrameRoot()); 1032 page->animator().scheduleVisualUpdate(m_frame->localFrameRoot());
1293 } 1033 }
1294 1034
1295 bool FrameSelection::selectWordAroundPosition(const VisiblePosition& position) { 1035 bool FrameSelection::selectWordAroundPosition(const VisiblePosition& position) {
1296 static const EWordSide wordSideList[2] = {RightWordIfOnBoundary, 1036 static const EWordSide wordSideList[2] = {RightWordIfOnBoundary,
1297 LeftWordIfOnBoundary}; 1037 LeftWordIfOnBoundary};
1298 for (EWordSide wordSide : wordSideList) { 1038 for (EWordSide wordSide : wordSideList) {
1299 VisiblePosition start = startOfWord(position, wordSide); 1039 VisiblePosition start = startOfWord(position, wordSide);
1300 VisiblePosition end = endOfWord(position, wordSide); 1040 VisiblePosition end = endOfWord(position, wordSide);
1301 String text = 1041 String text =
1302 plainText(EphemeralRange(start.deepEquivalent(), end.deepEquivalent())); 1042 plainText(EphemeralRange(start.deepEquivalent(), end.deepEquivalent()));
1303 if (!text.isEmpty() && !isSeparator(text.characterStartingAt(0))) { 1043 if (!text.isEmpty() && !isSeparator(text.characterStartingAt(0))) {
1304 setSelection(SelectionInDOMTree::Builder() 1044 setSelection(SelectionInDOMTree::Builder()
1305 .collapse(start.toPositionWithAffinity()) 1045 .collapse(start.toPositionWithAffinity())
1306 .extend(end.deepEquivalent()) 1046 .extend(end.deepEquivalent())
1307 .build(), 1047 .build(),
1308 CloseTyping | ClearTypingStyle, 1048 WordGranularity);
1309 CursorAlignOnScroll::IfNeeded, WordGranularity);
1310 return true; 1049 return true;
1311 } 1050 }
1312 } 1051 }
1313 1052
1314 return false; 1053 return false;
1315 } 1054 }
1316 1055
1317 GranularityStrategy* FrameSelection::granularityStrategy() { 1056 GranularityStrategy* FrameSelection::granularityStrategy() {
1318 // We do lazy initalization for m_granularityStrategy, because if we 1057 // We do lazy initalization for m_granularityStrategy, because if we
1319 // initialize it right in the constructor - the correct settings may not be 1058 // initialize it right in the constructor - the correct settings may not be
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
1356 SelectionInDOMTree::Builder() 1095 SelectionInDOMTree::Builder()
1357 .setBaseAndExtentDeprecated(basePosition.deepEquivalent(), 1096 .setBaseAndExtentDeprecated(basePosition.deepEquivalent(),
1358 extentPosition.deepEquivalent()) 1097 extentPosition.deepEquivalent())
1359 .setAffinity(basePosition.affinity()) 1098 .setAffinity(basePosition.affinity())
1360 .setGranularity(granularity) 1099 .setGranularity(granularity)
1361 .build()); 1100 .build());
1362 1101
1363 if (newSelection.isNone()) 1102 if (newSelection.isNone())
1364 return; 1103 return;
1365 1104
1366 setSelection(newSelection, CloseTyping | ClearTypingStyle, 1105 setSelection(newSelection, granularity);
1367 CursorAlignOnScroll::IfNeeded, granularity);
1368 } 1106 }
1369 1107
1370 void FrameSelection::updateIfNeeded() { 1108 void FrameSelection::updateIfNeeded() {
1371 DCHECK(!m_frame->document()->needsLayoutTreeUpdate()); 1109 DCHECK(!m_frame->document()->needsLayoutTreeUpdate());
1372 m_selectionEditor->updateIfNeeded(); 1110 m_selectionEditor->updateIfNeeded();
1373 } 1111 }
1374 1112
1375 void FrameSelection::setCaretVisible(bool caretIsVisible) { 1113 void FrameSelection::setCaretVisible(bool caretIsVisible) {
1376 m_frameCaret->setCaretVisibility(caretIsVisible ? CaretVisibility::Visible 1114 m_frameCaret->setCaretVisibility(caretIsVisible ? CaretVisibility::Visible
1377 : CaretVisibility::Hidden); 1115 : CaretVisibility::Hidden);
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after
1410 } 1148 }
1411 1149
1412 void showTree(const blink::FrameSelection* sel) { 1150 void showTree(const blink::FrameSelection* sel) {
1413 if (sel) 1151 if (sel)
1414 sel->showTreeForThis(); 1152 sel->showTreeForThis();
1415 else 1153 else
1416 LOG(INFO) << "Cannot showTree for <null> FrameSelection."; 1154 LOG(INFO) << "Cannot showTree for <null> FrameSelection.";
1417 } 1155 }
1418 1156
1419 #endif 1157 #endif
OLDNEW
« no previous file with comments | « third_party/WebKit/Source/core/editing/FrameSelection.h ('k') | third_party/WebKit/Source/core/editing/FrameSelectionTest.cpp » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698