OLD | NEW |
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 Loading... |
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 |
| 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>()| with |
| 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 (!computeVisibleSelectionInDOMTree().isNone() && |
| 247 !(options & DoNotSetFocus)) { |
227 setFocusedNodeIfNeeded(); | 248 setFocusedNodeIfNeeded(); |
228 // |setFocusedNodeIfNeeded()| dispatches sync events "FocusOut" and | 249 // |setFocusedNodeIfNeeded()| dispatches sync events "FocusOut" and |
229 // "FocusIn", |m_frame| may associate to another document. | 250 // "FocusIn", |m_frame| may associate to another document. |
230 if (!isAvailable() || document() != currentDocument) { | 251 if (!isAvailable() || document() != currentDocument) { |
231 // Once we get test case to reach here, we should change this | 252 // Once we get test case to reach here, we should change this |
232 // if-statement to |DCHECK()|. | 253 // if-statement to |DCHECK()|. |
233 NOTREACHED(); | 254 NOTREACHED(); |
234 return; | 255 return; |
235 } | 256 } |
236 } | 257 } |
237 | 258 |
238 if (!(options & DoNotUpdateAppearance)) { | 259 if (!(options & DoNotUpdateAppearance)) { |
239 m_frameCaret->stopCaretBlinkTimer(); | 260 m_frameCaret->stopCaretBlinkTimer(); |
240 updateAppearance(); | 261 updateAppearance(); |
241 } | 262 } |
242 | 263 |
243 // Always clear the x position used for vertical arrow navigation. | 264 // Always clear the x position used for vertical arrow navigation. |
244 // It will be restored by the vertical arrow navigation code if necessary. | 265 // It will be restored by the vertical arrow navigation code if necessary. |
245 m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation(); | 266 m_xPosForVerticalArrowNavigation = NoXPosForVerticalArrowNavigation(); |
| 267 // TODO(yosin): Can we move this to at end of this function? |
246 // This may dispatch a synchronous focus-related events. | 268 // This may dispatch a synchronous focus-related events. |
247 selectFrameElementInParentIfFullySelected(); | 269 selectFrameElementInParentIfFullySelected(); |
248 if (!isAvailable() || document() != currentDocument) { | 270 if (!isAvailable() || document() != currentDocument) { |
249 // editing/selection/selectallchildren-crash.html and | 271 // editing/selection/selectallchildren-crash.html and |
250 // editing/selection/longpress-selection-in-iframe-removed-crash.html | 272 // editing/selection/longpress-selection-in-iframe-removed-crash.html |
251 // reach here. | 273 // reach here. |
252 return; | 274 return; |
253 } | 275 } |
| 276 EUserTriggered userTriggered = selectionOptionsToUserTriggered(options); |
254 notifyLayoutObjectOfSelectionChange(userTriggered); | 277 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) { | 278 if (userTriggered == UserTriggered) { |
265 ScrollAlignment alignment; | 279 ScrollAlignment alignment; |
266 | 280 |
267 if (m_frame->editor().behavior().shouldCenterAlignWhenSelectionIsRevealed()) | 281 if (m_frame->editor().behavior().shouldCenterAlignWhenSelectionIsRevealed()) |
268 alignment = (align == CursorAlignOnScroll::Always) | 282 alignment = (align == CursorAlignOnScroll::Always) |
269 ? ScrollAlignment::alignCenterAlways | 283 ? ScrollAlignment::alignCenterAlways |
270 : ScrollAlignment::alignCenterIfNeeded; | 284 : ScrollAlignment::alignCenterIfNeeded; |
271 else | 285 else |
272 alignment = (align == CursorAlignOnScroll::Always) | 286 alignment = (align == CursorAlignOnScroll::Always) |
273 ? ScrollAlignment::alignTopAlways | 287 ? ScrollAlignment::alignTopAlways |
274 : ScrollAlignment::alignToEdgeIfNeeded; | 288 : ScrollAlignment::alignToEdgeIfNeeded; |
275 | 289 |
| 290 // TODO(editing-dev): The use of |
| 291 // updateStyleAndLayoutIgnorePendingStylesheets |
| 292 // needs to be audited. See http://crbug.com/590369 for more details. |
| 293 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
| 294 |
276 revealSelection(alignment, RevealExtent); | 295 revealSelection(alignment, RevealExtent); |
277 } | 296 } |
278 | 297 |
279 notifyAccessibilityForSelectionChange(); | 298 notifyAccessibilityForSelectionChange(); |
280 notifyCompositorForSelectionChange(); | 299 notifyCompositorForSelectionChange(); |
281 notifyEventHandlerForSelectionChange(); | 300 notifyEventHandlerForSelectionChange(); |
282 m_frame->domWindow()->enqueueDocumentEvent( | 301 m_frame->domWindow()->enqueueDocumentEvent( |
283 Event::create(EventTypeNames::selectionchange)); | 302 Event::create(EventTypeNames::selectionchange)); |
284 } | 303 } |
285 | 304 |
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, | 305 void FrameSelection::setSelection(const SelectionInFlatTree& newSelection, |
309 SetSelectionOptions options, | 306 SetSelectionOptions options, |
310 CursorAlignOnScroll align, | 307 CursorAlignOnScroll align, |
311 TextGranularity granularity) { | 308 TextGranularity granularity) { |
312 if (!newSelection.isNone()) { | 309 newSelection.assertValidFor(document()); |
313 // TODO(editing-dev): The use of | 310 SelectionInDOMTree::Builder builder; |
314 // updateStyleAndLayoutIgnorePendingStylesheets | 311 builder.setAffinity(newSelection.affinity()) |
315 // needs to be audited. See http://crbug.com/590369 for more details. | 312 .setBaseAndExtent(toPositionInDOMTree(newSelection.base()), |
316 newSelection.base() | 313 toPositionInDOMTree(newSelection.extent())) |
317 .document() | 314 .setGranularity(newSelection.granularity()) |
318 ->updateStyleAndLayoutIgnorePendingStylesheets(); | 315 .setIsDirectional(newSelection.isDirectional()) |
319 } | 316 .setIsHandleVisible(newSelection.isHandleVisible()) |
320 setSelection(createVisibleSelection(newSelection), | 317 .setHasTrailingWhitespace(newSelection.hasTrailingWhitespace()); |
321 newSelection.isHandleVisible() ? HandleVisibility::Visible | 318 return setSelection(builder.build(), options, align, granularity); |
322 : HandleVisibility::NotVisible, | |
323 options, align, granularity); | |
324 } | 319 } |
325 | 320 |
326 void FrameSelection::setSelection(const VisibleSelection& newSelection, | 321 void FrameSelection::setSelection(const VisibleSelection& newSelection, |
327 HandleVisibility handleVisibility, | 322 HandleVisibility handleVisibility, |
328 SetSelectionOptions options, | 323 SetSelectionOptions options, |
329 CursorAlignOnScroll align, | 324 CursorAlignOnScroll align, |
330 TextGranularity granularity) { | 325 TextGranularity granularity) { |
331 setSelectionAlgorithm<EditingStrategy>(newSelection, handleVisibility, | 326 setSelection( |
332 options, align, granularity); | 327 SelectionInDOMTree::Builder(newSelection.asSelection()) |
| 328 .setIsHandleVisible(handleVisibility == HandleVisibility::Visible) |
| 329 .build(), |
| 330 options, align, granularity); |
333 } | 331 } |
334 | 332 |
335 void FrameSelection::setSelection(const VisibleSelection& newSelection, | 333 void FrameSelection::setSelection(const VisibleSelection& newSelection, |
336 SetSelectionOptions options) { | 334 SetSelectionOptions options) { |
337 setSelection(newSelection, HandleVisibility::NotVisible, options); | 335 setSelection(newSelection.asSelection(), options); |
338 } | 336 } |
339 | 337 |
340 void FrameSelection::setSelection( | 338 void FrameSelection::setSelection( |
341 const VisibleSelectionInFlatTree& newSelection, | 339 const VisibleSelectionInFlatTree& newSelection, |
342 HandleVisibility handleVisibility, | 340 HandleVisibility handleVisibility, |
343 SetSelectionOptions options, | 341 SetSelectionOptions options, |
344 CursorAlignOnScroll align, | 342 CursorAlignOnScroll align, |
345 TextGranularity granularity) { | 343 TextGranularity granularity) { |
346 setSelectionAlgorithm<EditingInFlatTreeStrategy>( | 344 setSelection( |
347 newSelection, handleVisibility, options, align, granularity); | 345 SelectionInFlatTree::Builder(newSelection.asSelection()) |
| 346 .setIsHandleVisible(handleVisibility == HandleVisibility::Visible) |
| 347 .build(), |
| 348 options, align, granularity); |
348 } | 349 } |
349 | 350 |
350 void FrameSelection::setSelection( | 351 void FrameSelection::setSelection( |
351 const VisibleSelectionInFlatTree& newSelection, | 352 const VisibleSelectionInFlatTree& newSelection, |
352 SetSelectionOptions options) { | 353 SetSelectionOptions options) { |
353 setSelection(newSelection, HandleVisibility::NotVisible, options); | 354 setSelection(newSelection.asSelection(), options); |
354 } | 355 } |
355 | 356 |
356 static bool removingNodeRemovesPosition(Node& node, const Position& position) { | 357 // TODO(yosin): We should move |computePositionForChildrenRemoval()| to |
357 if (!position.anchorNode()) | 358 // "SelectionEditor.cpp" since it used only in |
358 return false; | 359 // |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, | 360 static Position computePositionForChildrenRemoval(const Position& position, |
371 ContainerNode& container) { | 361 ContainerNode& container) { |
372 Node* node = position.computeContainerNode(); | 362 Node* node = position.computeContainerNode(); |
373 if (container.containsIncludingHostElements(*node)) | 363 if (container.containsIncludingHostElements(*node)) |
374 return Position::firstPositionInNode(&container); | 364 return Position::firstPositionInNode(&container); |
375 return position; | 365 return position; |
376 } | 366 } |
377 | 367 |
378 void FrameSelection::nodeChildrenWillBeRemoved(ContainerNode& container) { | 368 void FrameSelection::nodeChildrenWillBeRemoved(ContainerNode& container) { |
379 if (isNone() || !container.inActiveDocument()) | 369 if (!container.inActiveDocument()) |
380 return; | 370 return; |
381 const Position& oldStart = selection().start(); | 371 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to |
382 const Position& newStart = | 372 // |Editor| class. |
383 computePositionForChildrenRemoval(oldStart, container); | 373 if (!document().isRunningExecCommand()) |
384 const Position& oldEnd = selection().end(); | 374 TypingCommand::closeTyping(m_frame); |
385 const Position& newEnd = computePositionForChildrenRemoval(oldEnd, container); | 375 } |
386 const Position& oldBase = selection().base(); | 376 |
| 377 // TODO(yosin): We should move |SelectionEditor::nodeChildrenWillBeRemoved()| |
| 378 // to "SelectionEditor.cpp". |
| 379 void SelectionEditor::nodeChildrenWillBeRemoved(ContainerNode& container) { |
| 380 if (m_selection.isNone()) |
| 381 return; |
| 382 const Position oldBase = m_selection.m_base; |
| 383 const Position oldExtent = m_selection.m_extent; |
387 const Position& newBase = | 384 const Position& newBase = |
388 computePositionForChildrenRemoval(oldBase, container); | 385 computePositionForChildrenRemoval(oldBase, container); |
389 const Position& oldExtent = selection().extent(); | |
390 const Position& newExtent = | 386 const Position& newExtent = |
391 computePositionForChildrenRemoval(oldExtent, container); | 387 computePositionForChildrenRemoval(oldExtent, container); |
392 if (newStart == oldStart && newEnd == oldEnd && newBase == oldBase && | 388 if (newBase == oldBase && newExtent == oldExtent) |
393 newExtent == oldExtent) | |
394 return; | 389 return; |
395 if (selection().isBaseFirst()) | 390 m_selection = SelectionInDOMTree::Builder() |
396 m_selectionEditor->setWithoutValidation(newStart, newEnd); | 391 .setBaseAndExtent(newBase, newExtent) |
397 else | 392 .build(); |
398 m_selectionEditor->setWithoutValidation(newEnd, newStart); | 393 markCacheDirty(); |
399 if (document().isRunningExecCommand()) | 394 } |
| 395 |
| 396 // TODO(yosin): We should move |computePositionForChildrenRemoval()| with |
| 397 // |nodeWillBeRemoved()| to "SelectionEditor.cpp". |
| 398 static Position computePositionForNodeRemoval(const Position& position, |
| 399 Node& nodeToBeRemoved) { |
| 400 Position result = position; |
| 401 // TODO(yosin): We should rename |updatePositionForNodeRemoval()| |
| 402 // to |computePositionForNodeRemoval()| to avoid using output parameter. |
| 403 updatePositionForNodeRemoval(result, nodeToBeRemoved); |
| 404 return result; |
| 405 } |
| 406 |
| 407 // TODO(yosin): We should move |nodeWillBeRemoved()| to |
| 408 // "SelectionEditor.cpp". |
| 409 void SelectionEditor::nodeWillBeRemoved(Node& nodeToBeRemoved) { |
| 410 if (m_selection.isNone()) |
400 return; | 411 return; |
401 TypingCommand::closeTyping(m_frame); | 412 const Position oldBase = m_selection.m_base; |
| 413 const Position oldExtent = m_selection.m_extent; |
| 414 const Position& newBase = |
| 415 computePositionForNodeRemoval(oldBase, nodeToBeRemoved); |
| 416 const Position& newExtent = |
| 417 computePositionForNodeRemoval(oldExtent, nodeToBeRemoved); |
| 418 if (newBase == oldBase && newExtent == oldExtent) |
| 419 return; |
| 420 m_selection = SelectionInDOMTree::Builder() |
| 421 .setBaseAndExtent(newBase, newExtent) |
| 422 .build(); |
| 423 markCacheDirty(); |
402 } | 424 } |
403 | 425 |
404 void FrameSelection::nodeWillBeRemoved(Node& node) { | 426 void FrameSelection::nodeWillBeRemoved(Node& node) { |
405 // There can't be a selection inside a fragment, so if a fragment's node is | 427 // 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 | 428 // being removed, the selection in the document that created the fragment |
407 // needs no adjustment. | 429 // needs no adjustment. |
408 if (isNone() || !node.inActiveDocument()) | 430 if (!node.inActiveDocument()) |
409 return; | 431 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 | 432 // TODO(yosin): We should move to call |TypingCommand::closeTyping()| to |
480 // |Editor| class. | 433 // |Editor| class. |
481 if (!document().isRunningExecCommand()) | 434 if (!document().isRunningExecCommand()) |
482 TypingCommand::closeTyping(m_frame); | 435 TypingCommand::closeTyping(m_frame); |
483 } | 436 } |
484 | 437 |
| 438 // TODO(yosin): We should move |updatePositionAfterAdoptingTextReplacement()| |
| 439 // to "SelectionEditor.cpp" since it used only in |
| 440 // |SelectionEditor::didUpdateCharacterData()|. |
485 static Position updatePositionAfterAdoptingTextReplacement( | 441 static Position updatePositionAfterAdoptingTextReplacement( |
486 const Position& position, | 442 const Position& position, |
487 CharacterData* node, | 443 CharacterData* node, |
488 unsigned offset, | 444 unsigned offset, |
489 unsigned oldLength, | 445 unsigned oldLength, |
490 unsigned newLength) { | 446 unsigned newLength) { |
491 if (!position.anchorNode() || position.anchorNode() != node || | 447 if (position.anchorNode() != node) |
492 !position.isOffsetInAnchor()) | |
493 return position; | 448 return position; |
494 | 449 |
| 450 if (position.isBeforeAnchor()) { |
| 451 return updatePositionAfterAdoptingTextReplacement( |
| 452 Position(node, 0), node, offset, oldLength, newLength); |
| 453 } |
| 454 if (position.isAfterAnchor()) { |
| 455 return updatePositionAfterAdoptingTextReplacement( |
| 456 Position(node, oldLength), node, offset, oldLength, newLength); |
| 457 } |
| 458 |
495 // See: | 459 // See: |
496 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-
Mutation | 460 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-
Mutation |
497 DCHECK_GE(position.offsetInContainerNode(), 0); | 461 DCHECK_GE(position.offsetInContainerNode(), 0); |
498 unsigned positionOffset = | 462 unsigned positionOffset = |
499 static_cast<unsigned>(position.offsetInContainerNode()); | 463 static_cast<unsigned>(position.offsetInContainerNode()); |
500 // Replacing text can be viewed as a deletion followed by insertion. | 464 // Replacing text can be viewed as a deletion followed by insertion. |
501 if (positionOffset >= offset && positionOffset <= offset + oldLength) | 465 if (positionOffset >= offset && positionOffset <= offset + oldLength) |
502 positionOffset = offset; | 466 positionOffset = offset; |
503 | 467 |
504 // Adjust the offset if the position is after the end of the deleted contents | 468 // Adjust the offset if the position is after the end of the deleted contents |
505 // (positionOffset > offset + oldLength) to avoid having a stale offset. | 469 // (positionOffset > offset + oldLength) to avoid having a stale offset. |
506 if (positionOffset > offset + oldLength) | 470 if (positionOffset > offset + oldLength) |
507 positionOffset = positionOffset - oldLength + newLength; | 471 positionOffset = positionOffset - oldLength + newLength; |
508 | 472 |
509 // Due to case folding | 473 // Due to case folding |
510 // (http://unicode.org/Public/UCD/latest/ucd/CaseFolding.txt), LayoutText | 474 // (http://unicode.org/Public/UCD/latest/ucd/CaseFolding.txt), LayoutText |
511 // length may be different from Text length. A correct implementation would | 475 // 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 | 476 // 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. | 477 // precaution to avoid offset values that run off the end of the Text. |
514 if (positionOffset > node->length()) | 478 if (positionOffset > node->length()) |
515 positionOffset = node->length(); | 479 positionOffset = node->length(); |
516 | 480 |
517 // CharacterNode in VisibleSelection must be Text node, because Comment | 481 return Position(node, positionOffset); |
518 // and ProcessingInstruction node aren't visible. | |
519 return Position(toText(node), positionOffset); | |
520 } | 482 } |
521 | 483 |
522 void FrameSelection::didUpdateCharacterData(CharacterData* node, | 484 // TODO(yosin): We should move |didUpdateCharacterData()| to |
523 unsigned offset, | 485 // "SelectionEditor.cpp". |
524 unsigned oldLength, | 486 void SelectionEditor::didUpdateCharacterData(CharacterData* node, |
525 unsigned newLength) { | 487 unsigned offset, |
| 488 unsigned oldLength, |
| 489 unsigned newLength) { |
526 // The fragment check is a performance optimization. See | 490 // The fragment check is a performance optimization. See |
527 // http://trac.webkit.org/changeset/30062. | 491 // http://trac.webkit.org/changeset/30062. |
528 if (isNone() || !node || !node->isConnected()) | 492 if (m_selection.isNone() || !node || !node->isConnected()) { |
| 493 didFinishDOMMutation(); |
529 return; | 494 return; |
530 | 495 } |
531 Position base = updatePositionAfterAdoptingTextReplacement( | 496 const Position& newBase = updatePositionAfterAdoptingTextReplacement( |
532 selection().base(), node, offset, oldLength, newLength); | 497 m_selection.m_base, node, offset, oldLength, newLength); |
533 Position extent = updatePositionAfterAdoptingTextReplacement( | 498 const Position& newExtent = updatePositionAfterAdoptingTextReplacement( |
534 selection().extent(), node, offset, oldLength, newLength); | 499 m_selection.m_extent, node, offset, oldLength, newLength); |
535 Position start = updatePositionAfterAdoptingTextReplacement( | 500 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 } | 501 } |
541 | 502 |
| 503 // TODO(yosin): We should move |updatePostionAfterAdoptingTextNodesMerged()| |
| 504 // to "SelectionEditor.cpp" since it used only in |
| 505 // |SelectionEditor::didMergeTextNodes()|. |
| 506 // TODO(yosin): We should introduce |Position(const Text&, int)| to avoid |
| 507 // |const_cast<Text*>|. |
542 static Position updatePostionAfterAdoptingTextNodesMerged( | 508 static Position updatePostionAfterAdoptingTextNodesMerged( |
543 const Position& position, | 509 const Position& position, |
544 const Text& oldNode, | 510 const Text& mergedNode, |
545 unsigned offset) { | 511 const NodeWithIndex& nodeToBeRemovedWithIndex, |
546 if (!position.anchorNode() || !position.isOffsetInAnchor()) | 512 unsigned oldLength) { |
547 return position; | 513 Node* const anchorNode = position.anchorNode(); |
548 | 514 const Node& nodeToBeRemoved = nodeToBeRemovedWithIndex.node(); |
549 DCHECK_GE(position.offsetInContainerNode(), 0); | 515 switch (position.anchorType()) { |
550 unsigned positionOffset = | 516 case PositionAnchorType::BeforeChildren: |
551 static_cast<unsigned>(position.offsetInContainerNode()); | 517 case PositionAnchorType::AfterChildren: |
552 | 518 return position; |
553 if (position.anchorNode() == &oldNode) | 519 case PositionAnchorType::BeforeAnchor: |
554 return Position(toText(oldNode.previousSibling()), positionOffset + offset); | 520 if (anchorNode == nodeToBeRemoved) |
555 | 521 return Position(const_cast<Text*>(&mergedNode), mergedNode.length()); |
556 if (position.anchorNode() == oldNode.parentNode() && positionOffset == offset) | 522 return position; |
557 return Position(toText(oldNode.previousSibling()), offset); | 523 case PositionAnchorType::AfterAnchor: |
558 | 524 if (anchorNode == nodeToBeRemoved) |
| 525 return Position(const_cast<Text*>(&mergedNode), mergedNode.length()); |
| 526 if (anchorNode == mergedNode) |
| 527 return Position(const_cast<Text*>(&mergedNode), oldLength); |
| 528 return position; |
| 529 case PositionAnchorType::OffsetInAnchor: { |
| 530 const int offset = position.offsetInContainerNode(); |
| 531 if (anchorNode == nodeToBeRemoved) |
| 532 return Position(const_cast<Text*>(&mergedNode), oldLength + offset); |
| 533 if (anchorNode == nodeToBeRemoved.parentNode() && |
| 534 offset == nodeToBeRemovedWithIndex.index()) { |
| 535 return Position(const_cast<Text*>(&mergedNode), oldLength); |
| 536 } |
| 537 return position; |
| 538 } |
| 539 } |
| 540 NOTREACHED() << position; |
559 return position; | 541 return position; |
560 } | 542 } |
561 | 543 |
562 void FrameSelection::didMergeTextNodes( | 544 // TODO(yosin): We should move |SelectionEditor::didMergeTextNodes()| to |
| 545 // "SelectionEditor.cpp". |
| 546 void SelectionEditor::didMergeTextNodes( |
563 const Text& mergedNode, | 547 const Text& mergedNode, |
564 const NodeWithIndex& nodeToBeRemovedWithIndex, | 548 const NodeWithIndex& nodeToBeRemovedWithIndex, |
565 unsigned offset) { | 549 unsigned oldLength) { |
566 const Text& oldNode = toText(nodeToBeRemovedWithIndex.node()); | 550 if (m_selection.isNone()) { |
567 if (isNone() || !oldNode.isConnected()) | 551 didFinishDOMMutation(); |
568 return; | 552 return; |
569 Position base = updatePostionAfterAdoptingTextNodesMerged(selection().base(), | 553 } |
570 oldNode, offset); | 554 const Position& newBase = updatePostionAfterAdoptingTextNodesMerged( |
571 Position extent = updatePostionAfterAdoptingTextNodesMerged( | 555 m_selection.m_base, mergedNode, nodeToBeRemovedWithIndex, oldLength); |
572 selection().extent(), oldNode, offset); | 556 const Position& newExtent = updatePostionAfterAdoptingTextNodesMerged( |
573 Position start = updatePostionAfterAdoptingTextNodesMerged( | 557 m_selection.m_extent, mergedNode, nodeToBeRemovedWithIndex, oldLength); |
574 selection().start(), oldNode, offset); | 558 didFinishTextChange(newBase, newExtent); |
575 Position end = updatePostionAfterAdoptingTextNodesMerged(selection().end(), | |
576 oldNode, offset); | |
577 updateSelectionIfNeeded(base, extent, start, end); | |
578 } | 559 } |
579 | 560 |
| 561 // TODO(yosin): We should move |updatePostionAfterAdoptingTextNodeSplit()| |
| 562 // to "SelectionEditor.cpp" since it used only in |
| 563 // |SelectionEditor::didSplitTextNode()|. |
580 static Position updatePostionAfterAdoptingTextNodeSplit( | 564 static Position updatePostionAfterAdoptingTextNodeSplit( |
581 const Position& position, | 565 const Position& position, |
582 const Text& oldNode) { | 566 const Text& oldNode) { |
583 if (!position.anchorNode() || position.anchorNode() != &oldNode || | 567 if (!position.anchorNode() || position.anchorNode() != &oldNode || |
584 !position.isOffsetInAnchor()) | 568 !position.isOffsetInAnchor()) |
585 return position; | 569 return position; |
586 // See: | 570 // See: |
587 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-
Mutation | 571 // http://www.w3.org/TR/DOM-Level-2-Traversal-Range/ranges.html#Level-2-Range-
Mutation |
588 DCHECK_GE(position.offsetInContainerNode(), 0); | 572 DCHECK_GE(position.offsetInContainerNode(), 0); |
589 unsigned positionOffset = | 573 unsigned positionOffset = |
590 static_cast<unsigned>(position.offsetInContainerNode()); | 574 static_cast<unsigned>(position.offsetInContainerNode()); |
591 unsigned oldLength = oldNode.length(); | 575 unsigned oldLength = oldNode.length(); |
592 if (positionOffset <= oldLength) | 576 if (positionOffset <= oldLength) |
593 return position; | 577 return position; |
594 return Position(toText(oldNode.nextSibling()), positionOffset - oldLength); | 578 return Position(toText(oldNode.nextSibling()), positionOffset - oldLength); |
595 } | 579 } |
596 | 580 |
597 void FrameSelection::didSplitTextNode(const Text& oldNode) { | 581 // TODO(yosin): We should move |SelectionEditor::didSplitTextNode()| to |
598 if (isNone() || !oldNode.isConnected()) | 582 // "SelectionEditor.cpp". |
| 583 void SelectionEditor::didSplitTextNode(const Text& oldNode) { |
| 584 if (m_selection.isNone() || !oldNode.isConnected()) { |
| 585 didFinishDOMMutation(); |
599 return; | 586 return; |
600 Position base = | 587 } |
601 updatePostionAfterAdoptingTextNodeSplit(selection().base(), oldNode); | 588 const Position& newBase = |
602 Position extent = | 589 updatePostionAfterAdoptingTextNodeSplit(m_selection.m_base, oldNode); |
603 updatePostionAfterAdoptingTextNodeSplit(selection().extent(), oldNode); | 590 const Position& newExtent = |
604 Position start = | 591 updatePostionAfterAdoptingTextNodeSplit(m_selection.m_extent, oldNode); |
605 updatePostionAfterAdoptingTextNodeSplit(selection().start(), oldNode); | 592 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 } | 593 } |
629 | 594 |
630 void FrameSelection::didChangeFocus() { | 595 void FrameSelection::didChangeFocus() { |
631 // Hits in | 596 // Hits in |
632 // virtual/gpu/compositedscrolling/scrollbars/scrollbar-miss-mousemove-disable
d.html | 597 // virtual/gpu/compositedscrolling/scrollbars/scrollbar-miss-mousemove-disable
d.html |
633 DisableCompositingQueryAsserts disabler; | 598 DisableCompositingQueryAsserts disabler; |
634 updateAppearance(); | 599 updateAppearance(); |
635 } | 600 } |
636 | 601 |
637 static DispatchEventResult dispatchSelectStart( | 602 static DispatchEventResult dispatchSelectStart( |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
724 } | 689 } |
725 | 690 |
726 void FrameSelection::contextDestroyed(Document* document) { | 691 void FrameSelection::contextDestroyed(Document* document) { |
727 m_granularity = CharacterGranularity; | 692 m_granularity = CharacterGranularity; |
728 | 693 |
729 LayoutViewItem view = m_frame->contentLayoutItem(); | 694 LayoutViewItem view = m_frame->contentLayoutItem(); |
730 if (!view.isNull()) | 695 if (!view.isNull()) |
731 view.clearSelection(); | 696 view.clearSelection(); |
732 | 697 |
733 m_frame->editor().clearTypingStyle(); | 698 m_frame->editor().clearTypingStyle(); |
734 m_selectionEditor->documentDetached(*document); | |
735 } | 699 } |
736 | 700 |
737 void FrameSelection::clearPreviousCaretVisualRect(const LayoutBlock& block) { | 701 void FrameSelection::clearPreviousCaretVisualRect(const LayoutBlock& block) { |
738 m_frameCaret->clearPreviousVisualRect(block); | 702 m_frameCaret->clearPreviousVisualRect(block); |
739 } | 703 } |
740 | 704 |
741 void FrameSelection::layoutBlockWillBeDestroyed(const LayoutBlock& block) { | 705 void FrameSelection::layoutBlockWillBeDestroyed(const LayoutBlock& block) { |
742 m_frameCaret->layoutBlockWillBeDestroyed(block); | 706 m_frameCaret->layoutBlockWillBeDestroyed(block); |
743 } | 707 } |
744 | 708 |
745 void FrameSelection::updateStyleAndLayoutIfNeeded() { | 709 void FrameSelection::updateStyleAndLayoutIfNeeded() { |
746 m_frameCaret->updateStyleAndLayoutIfNeeded(); | 710 m_frameCaret->updateStyleAndLayoutIfNeeded(); |
747 } | 711 } |
748 | 712 |
749 void FrameSelection::invalidatePaintIfNeeded( | 713 void FrameSelection::invalidatePaintIfNeeded( |
750 const LayoutBlock& block, | 714 const LayoutBlock& block, |
751 const PaintInvalidatorContext& context, | 715 const PaintInvalidatorContext& context, |
752 PaintInvalidationReason reason) { | 716 PaintInvalidationReason reason) { |
753 m_frameCaret->invalidatePaintIfNeeded(block, context, reason); | 717 m_frameCaret->invalidatePaintIfNeeded(block, context, reason); |
754 } | 718 } |
755 | 719 |
756 bool FrameSelection::shouldPaintCaret(const LayoutBlock& block) const { | 720 bool FrameSelection::shouldPaintCaret(const LayoutBlock& block) const { |
757 DCHECK(selection().isValidFor(document())); | 721 DCHECK_GE(document().lifecycle().state(), DocumentLifecycle::LayoutClean); |
758 | |
759 bool result = m_frameCaret->shouldPaintCaret(block); | 722 bool result = m_frameCaret->shouldPaintCaret(block); |
760 DCHECK(!result || (isCaret() && hasEditableStyle())); | 723 DCHECK(!result || (isCaret() && hasEditableStyle())); |
761 return result; | 724 return result; |
762 } | 725 } |
763 | 726 |
764 IntRect FrameSelection::absoluteCaretBounds() { | 727 IntRect FrameSelection::absoluteCaretBounds() { |
765 DCHECK(selection().isValidFor(*m_frame->document())); | 728 DCHECK(selection().isValidFor(*m_frame->document())); |
766 return m_frameCaret->absoluteCaretBounds(); | 729 return m_frameCaret->absoluteCaretBounds(); |
767 } | 730 } |
768 | 731 |
(...skipping 299 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1068 | 1031 |
1069 void FrameSelection::commitAppearanceIfNeeded(LayoutView& layoutView) { | 1032 void FrameSelection::commitAppearanceIfNeeded(LayoutView& layoutView) { |
1070 return m_pendingSelection->commit(layoutView); | 1033 return m_pendingSelection->commit(layoutView); |
1071 } | 1034 } |
1072 | 1035 |
1073 void FrameSelection::didLayout() { | 1036 void FrameSelection::didLayout() { |
1074 updateAppearance(); | 1037 updateAppearance(); |
1075 } | 1038 } |
1076 | 1039 |
1077 void FrameSelection::updateAppearance() { | 1040 void FrameSelection::updateAppearance() { |
1078 m_frameCaret->updateAppearance(); | 1041 DCHECK(!m_frame->contentLayoutItem().isNull()); |
1079 | 1042 m_frameCaret->scheduleVisualUpdateForPaintInvalidationIfNeeded(); |
1080 if (m_frame->contentLayoutItem().isNull()) | |
1081 return; | |
1082 m_pendingSelection->setHasPendingSelection(); | 1043 m_pendingSelection->setHasPendingSelection(); |
1083 } | 1044 } |
1084 | 1045 |
1085 void FrameSelection::notifyLayoutObjectOfSelectionChange( | 1046 void FrameSelection::notifyLayoutObjectOfSelectionChange( |
1086 EUserTriggered userTriggered) { | 1047 EUserTriggered userTriggered) { |
1087 if (TextControlElement* textControl = enclosingTextControl(start())) | 1048 if (TextControlElement* textControl = enclosingTextControl(start())) |
1088 textControl->selectionChanged(userTriggered == UserTriggered); | 1049 textControl->selectionChanged(userTriggered == UserTriggered); |
1089 } | 1050 } |
1090 | 1051 |
1091 // Helper function that tells whether a particular node is an element that has | 1052 // 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 Loading... |
1274 | 1235 |
1275 Document* document = m_frame->document(); | 1236 Document* document = m_frame->document(); |
1276 if (!isNone() || !(blink::hasEditableStyle(*document))) | 1237 if (!isNone() || !(blink::hasEditableStyle(*document))) |
1277 return; | 1238 return; |
1278 | 1239 |
1279 Element* documentElement = document->documentElement(); | 1240 Element* documentElement = document->documentElement(); |
1280 if (!documentElement) | 1241 if (!documentElement) |
1281 return; | 1242 return; |
1282 if (HTMLBodyElement* body = | 1243 if (HTMLBodyElement* body = |
1283 Traversal<HTMLBodyElement>::firstChild(*documentElement)) { | 1244 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() | 1245 setSelection(SelectionInDOMTree::Builder() |
1289 .collapse(firstPositionInOrBeforeNode(body)) | 1246 .collapse(firstPositionInOrBeforeNode(body)) |
1290 .build()); | 1247 .build()); |
1291 } | 1248 } |
1292 } | 1249 } |
1293 | 1250 |
1294 // TODO(yoichio): We should have LocalFrame having FrameCaret, | 1251 // TODO(yoichio): We should have LocalFrame having FrameCaret, |
1295 // Editor and PendingSelection using FrameCaret directly | 1252 // Editor and PendingSelection using FrameCaret directly |
1296 // and get rid of this. | 1253 // and get rid of this. |
1297 bool FrameSelection::shouldShowBlockCursor() const { | 1254 bool FrameSelection::shouldShowBlockCursor() const { |
(...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1388 FrameSelection::DoNotClearStrategy | UserTriggered, | 1345 FrameSelection::DoNotClearStrategy | UserTriggered, |
1389 CursorAlignOnScroll::IfNeeded, CharacterGranularity); | 1346 CursorAlignOnScroll::IfNeeded, CharacterGranularity); |
1390 } | 1347 } |
1391 | 1348 |
1392 // TODO(yosin): We should make |FrameSelection::moveRangeSelection()| to take | 1349 // TODO(yosin): We should make |FrameSelection::moveRangeSelection()| to take |
1393 // two |IntPoint| instead of two |VisiblePosition| like | 1350 // two |IntPoint| instead of two |VisiblePosition| like |
1394 // |moveRangeSelectionExtent()|. | 1351 // |moveRangeSelectionExtent()|. |
1395 void FrameSelection::moveRangeSelection(const VisiblePosition& basePosition, | 1352 void FrameSelection::moveRangeSelection(const VisiblePosition& basePosition, |
1396 const VisiblePosition& extentPosition, | 1353 const VisiblePosition& extentPosition, |
1397 TextGranularity granularity) { | 1354 TextGranularity granularity) { |
1398 VisibleSelection newSelection = createVisibleSelection( | 1355 SelectionInDOMTree newSelection = |
1399 SelectionInDOMTree::Builder() | 1356 SelectionInDOMTree::Builder() |
1400 .setBaseAndExtentDeprecated(basePosition.deepEquivalent(), | 1357 .setBaseAndExtentDeprecated(basePosition.deepEquivalent(), |
1401 extentPosition.deepEquivalent()) | 1358 extentPosition.deepEquivalent()) |
1402 .setAffinity(basePosition.affinity()) | 1359 .setAffinity(basePosition.affinity()) |
1403 .setGranularity(granularity) | 1360 .setGranularity(granularity) |
1404 .build()); | 1361 .setIsHandleVisible(isHandleVisible()) |
| 1362 .build(); |
1405 | 1363 |
1406 if (newSelection.isNone()) | 1364 if (newSelection.isNone()) |
1407 return; | 1365 return; |
1408 | 1366 |
1409 setSelection(newSelection, m_handleVisibility, CloseTyping | ClearTypingStyle, | 1367 setSelection(newSelection, CloseTyping | ClearTypingStyle, |
1410 CursorAlignOnScroll::IfNeeded, granularity); | 1368 CursorAlignOnScroll::IfNeeded, granularity); |
1411 } | 1369 } |
1412 | 1370 |
1413 void FrameSelection::updateIfNeeded() { | 1371 void FrameSelection::updateIfNeeded() { |
1414 DCHECK(!m_frame->document()->needsLayoutTreeUpdate()); | 1372 DCHECK(!m_frame->document()->needsLayoutTreeUpdate()); |
1415 m_selectionEditor->updateIfNeeded(); | 1373 m_selectionEditor->updateIfNeeded(); |
1416 } | 1374 } |
1417 | 1375 |
1418 void FrameSelection::setCaretVisible(bool caretIsVisible) { | 1376 void FrameSelection::setCaretVisible(bool caretIsVisible) { |
1419 m_frameCaret->setCaretVisibility(caretIsVisible ? CaretVisibility::Visible | 1377 m_frameCaret->setCaretVisibility(caretIsVisible ? CaretVisibility::Visible |
(...skipping 29 matching lines...) Expand all Loading... |
1449 } | 1407 } |
1450 | 1408 |
1451 void showTree(const blink::FrameSelection* sel) { | 1409 void showTree(const blink::FrameSelection* sel) { |
1452 if (sel) | 1410 if (sel) |
1453 sel->showTreeForThis(); | 1411 sel->showTreeForThis(); |
1454 else | 1412 else |
1455 LOG(INFO) << "Cannot showTree for <null> FrameSelection."; | 1413 LOG(INFO) << "Cannot showTree for <null> FrameSelection."; |
1456 } | 1414 } |
1457 | 1415 |
1458 #endif | 1416 #endif |
OLD | NEW |