OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. | 2 * Copyright (C) 2005, 2006, 2007, 2008 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 59 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
70 #include "core/html/HTMLQuoteElement.h" | 70 #include "core/html/HTMLQuoteElement.h" |
71 #include "core/html/HTMLSpanElement.h" | 71 #include "core/html/HTMLSpanElement.h" |
72 #include "core/layout/LayoutBlock.h" | 72 #include "core/layout/LayoutBlock.h" |
73 #include "core/layout/LayoutListItem.h" | 73 #include "core/layout/LayoutListItem.h" |
74 #include "core/layout/LayoutText.h" | 74 #include "core/layout/LayoutText.h" |
75 #include "core/layout/line/InlineTextBox.h" | 75 #include "core/layout/line/InlineTextBox.h" |
76 #include <algorithm> | 76 #include <algorithm> |
77 | 77 |
78 namespace blink { | 78 namespace blink { |
79 | 79 |
| 80 namespace { |
| 81 |
| 82 bool dispatchBeforeInputEvent(EditCommandSource source, |
| 83 LocalFrame* frame, |
| 84 Node* target, |
| 85 InputEvent::InputType inputType, |
| 86 const String& data, |
| 87 DataTransfer* dataTransfer, |
| 88 InputEvent::EventCancelable isCancelable, |
| 89 InputEvent::EventIsComposing isComposing, |
| 90 const RangeVector* ranges) { |
| 91 // Don't fire 'beforeinput', return true to continue. |
| 92 if (source != EditCommandSource::kMenuOrKeyBinding || |
| 93 inputType == InputEvent::InputType::None) |
| 94 return true; |
| 95 if (!RuntimeEnabledFeatures::inputEventEnabled()) |
| 96 return true; |
| 97 if (!frame || !target || !target->isConnected()) |
| 98 return true; |
| 99 |
| 100 if (!hasRichlyEditableStyle(*target)) { |
| 101 // Plain-text only elements (<input>, <textarea>, etc.) don't support |
| 102 // DataTransfer or Range. |
| 103 dataTransfer = nullptr; |
| 104 ranges = nullptr; |
| 105 } |
| 106 |
| 107 InputEvent* beforeInputEvent; |
| 108 |
| 109 if (dataTransfer) { |
| 110 beforeInputEvent = InputEvent::createBeforeInput( |
| 111 inputType, dataTransfer, isCancelable, isComposing, ranges); |
| 112 } else { |
| 113 beforeInputEvent = InputEvent::createBeforeInput( |
| 114 inputType, data, isCancelable, isComposing, ranges); |
| 115 } |
| 116 |
| 117 DispatchEventResult result = target->dispatchEvent(beforeInputEvent); |
| 118 // 'beforeinput' event handler may destroy target frame. |
| 119 if (frame->document()->frame() != frame) |
| 120 return false; |
| 121 return result == DispatchEventResult::NotCanceled; |
| 122 } |
| 123 |
| 124 } // anonymous namespace |
| 125 |
80 using namespace HTMLNames; | 126 using namespace HTMLNames; |
81 | 127 |
82 EditCommandComposition* EditCommandComposition::create( | 128 EditCommandComposition* EditCommandComposition::create( |
83 Document* document, | 129 Document* document, |
84 const VisibleSelection& startingSelection, | 130 const VisibleSelection& startingSelection, |
85 const VisibleSelection& endingSelection, | 131 const VisibleSelection& endingSelection) { |
86 InputEvent::InputType inputType) { | |
87 return new EditCommandComposition(document, startingSelection, | 132 return new EditCommandComposition(document, startingSelection, |
88 endingSelection, inputType); | 133 endingSelection); |
89 } | 134 } |
90 | 135 |
91 EditCommandComposition::EditCommandComposition( | 136 EditCommandComposition::EditCommandComposition( |
92 Document* document, | 137 Document* document, |
93 const VisibleSelection& startingSelection, | 138 const VisibleSelection& startingSelection, |
94 const VisibleSelection& endingSelection, | 139 const VisibleSelection& endingSelection) |
95 InputEvent::InputType inputType) | |
96 : m_document(document), | 140 : m_document(document), |
97 m_startingSelection(startingSelection), | 141 m_startingSelection(startingSelection), |
98 m_endingSelection(endingSelection), | 142 m_endingSelection(endingSelection), |
99 m_startingRootEditableElement(startingSelection.rootEditableElement()), | 143 m_startingRootEditableElement(startingSelection.rootEditableElement()), |
100 m_endingRootEditableElement(endingSelection.rootEditableElement()), | 144 m_endingRootEditableElement(endingSelection.rootEditableElement()) {} |
101 m_inputType(inputType) {} | |
102 | 145 |
103 bool EditCommandComposition::belongsTo(const LocalFrame& frame) const { | 146 bool EditCommandComposition::belongsTo(const LocalFrame& frame) const { |
104 DCHECK(m_document); | 147 DCHECK(m_document); |
105 return m_document->frame() == &frame; | 148 return m_document->frame() == &frame; |
106 } | 149 } |
107 | 150 |
108 void EditCommandComposition::unapply(EditCommandSource source) { | 151 void EditCommandComposition::unapply(EditCommandSource source) { |
109 DCHECK(m_document); | 152 DCHECK(m_document); |
110 LocalFrame* frame = m_document->frame(); | 153 LocalFrame* frame = m_document->frame(); |
111 DCHECK(frame); | 154 DCHECK(frame); |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
145 m_document->updateStyleAndLayoutIgnorePendingStylesheets(); | 188 m_document->updateStyleAndLayoutIgnorePendingStylesheets(); |
146 | 189 |
147 { | 190 { |
148 for (const auto& command : m_commands) | 191 for (const auto& command : m_commands) |
149 command->doReapply(); | 192 command->doReapply(); |
150 } | 193 } |
151 | 194 |
152 frame->editor().reappliedEditing(this); | 195 frame->editor().reappliedEditing(this); |
153 } | 196 } |
154 | 197 |
155 bool EditCommandComposition::willUnapply(EditCommandSource) { | 198 bool EditCommandComposition::willUnapply(EditCommandSource source) { |
156 // TODO(chongz): Fire 'beforeinput' for 'historyUndo'. | 199 return dispatchBeforeInputEvent(source, m_document->frame(), m_document, |
157 return true; | 200 InputEvent::InputType::HistoryUndo, nullAtom, |
| 201 nullptr, InputEvent::IsCancelable, |
| 202 InputEvent::NotComposing, nullptr); |
158 } | 203 } |
159 | 204 |
160 bool EditCommandComposition::willReapply(EditCommandSource) { | 205 bool EditCommandComposition::willReapply(EditCommandSource source) { |
161 // TODO(chongz): Fire 'beforeinput' for 'historyRedo'. | 206 return dispatchBeforeInputEvent(source, m_document->frame(), m_document, |
162 return true; | 207 InputEvent::InputType::HistoryRedo, nullAtom, |
163 } | 208 nullptr, InputEvent::IsCancelable, |
164 | 209 InputEvent::NotComposing, nullptr); |
165 InputEvent::InputType EditCommandComposition::inputType() const { | |
166 return m_inputType; | |
167 } | 210 } |
168 | 211 |
169 void EditCommandComposition::append(SimpleEditCommand* command) { | 212 void EditCommandComposition::append(SimpleEditCommand* command) { |
170 m_commands.push_back(command); | 213 m_commands.push_back(command); |
171 } | 214 } |
172 | 215 |
173 void EditCommandComposition::append(EditCommandComposition* composition) { | 216 void EditCommandComposition::append(EditCommandComposition* composition) { |
174 m_commands.appendVector(composition->m_commands); | 217 m_commands.appendVector(composition->m_commands); |
175 } | 218 } |
176 | 219 |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
225 case InputEvent::InputType::DeleteByDrag: | 268 case InputEvent::InputType::DeleteByDrag: |
226 case InputEvent::InputType::None: | 269 case InputEvent::InputType::None: |
227 break; | 270 break; |
228 default: | 271 default: |
229 NOTREACHED(); | 272 NOTREACHED(); |
230 return false; | 273 return false; |
231 } | 274 } |
232 } | 275 } |
233 ensureComposition(); | 276 ensureComposition(); |
234 | 277 |
| 278 // Covers the initial TypingCommand and other top-level commands. |
| 279 // TypingCommand::willAddTypingToOpenCommand() also calls willApplyEditing(). |
| 280 if (!willApplyEditing(source)) |
| 281 return false; |
| 282 |
235 // Changes to the document may have been made since the last editing operation | 283 // Changes to the document may have been made since the last editing operation |
236 // that require a layout, as in <rdar://problem/5658603>. Low level | 284 // that require a layout, as in <rdar://problem/5658603>. Low level |
237 // operations, like RemoveNodeCommand, don't require a layout because the high | 285 // operations, like RemoveNodeCommand, don't require a layout because the high |
238 // level operations that use them perform one if one is necessary (like for | 286 // level operations that use them perform one if one is necessary (like for |
239 // the creation of VisiblePositions). | 287 // the creation of VisiblePositions). |
240 document().updateStyleAndLayoutIgnorePendingStylesheets(); | 288 document().updateStyleAndLayoutIgnorePendingStylesheets(); |
241 | 289 |
242 if (!willApplyEditing(source)) | |
243 return false; | |
244 | |
245 LocalFrame* frame = document().frame(); | 290 LocalFrame* frame = document().frame(); |
246 DCHECK(frame); | 291 DCHECK(frame); |
247 EditingState editingState; | 292 EditingState editingState; |
248 { | 293 { |
249 EventQueueScope eventQueueScope; | 294 EventQueueScope eventQueueScope; |
250 doApply(&editingState); | 295 doApply(&editingState); |
251 } | 296 } |
252 | 297 |
253 // Only need to call appliedEditing for top-level commands, and TypingCommands | 298 // Only need to call appliedEditing for top-level commands, and TypingCommands |
254 // do it on their own (see TypingCommand::typingAddedToOpenCommand). | 299 // do it on their own (see TypingCommand::typingAddedToOpenCommand). |
255 if (!isTypingCommand()) | 300 if (!isTypingCommand()) |
256 frame->editor().appliedEditing(this); | 301 frame->editor().appliedEditing(this); |
257 setShouldRetainAutocorrectionIndicator(false); | 302 setShouldRetainAutocorrectionIndicator(false); |
258 return !editingState.isAborted(); | 303 return !editingState.isAborted(); |
259 } | 304 } |
260 | 305 |
261 EditCommandComposition* CompositeEditCommand::ensureComposition() { | 306 EditCommandComposition* CompositeEditCommand::ensureComposition() { |
262 CompositeEditCommand* command = this; | 307 CompositeEditCommand* command = this; |
263 while (command && command->parent()) | 308 while (command && command->parent()) |
264 command = command->parent(); | 309 command = command->parent(); |
265 if (!command->m_composition) | 310 if (!command->m_composition) { |
266 command->m_composition = EditCommandComposition::create( | 311 command->m_composition = EditCommandComposition::create( |
267 &document(), startingSelection(), endingSelection(), inputType()); | 312 &document(), startingSelection(), endingSelection()); |
| 313 } |
268 return command->m_composition.get(); | 314 return command->m_composition.get(); |
269 } | 315 } |
270 | 316 |
271 bool CompositeEditCommand::willApplyEditing(EditCommandSource) { | 317 bool CompositeEditCommand::willApplyEditing(EditCommandSource source) { |
272 // TODO(chongz): Move all the 'beforeinput' dispatching logic here. | 318 return dispatchBeforeInputEvent( |
273 return true; | 319 source, document().frame(), eventTargetNodeForDocument(&document()), |
| 320 inputType(), textDataForInputEvent(), dataTransferForInputEvent(), |
| 321 isCancelableFromCommand(this), isComposingFromCommand(this), |
| 322 targetRangesForInputEvent()); |
| 323 } |
| 324 |
| 325 InputEvent::InputType CompositeEditCommand::inputType() const { |
| 326 return InputEvent::InputType::None; |
| 327 } |
| 328 |
| 329 String CompositeEditCommand::textDataForInputEvent() const { |
| 330 return nullAtom; |
| 331 } |
| 332 |
| 333 DataTransfer* CompositeEditCommand::dataTransferForInputEvent() const { |
| 334 return nullptr; |
| 335 } |
| 336 |
| 337 RangeVector* CompositeEditCommand::targetRangesForInputEvent() const { |
| 338 if (!document().frame()->editor().canEditRichly()) |
| 339 return nullptr; |
| 340 return new RangeVector(1, document().frame()->selection().firstRange()); |
274 } | 341 } |
275 | 342 |
276 bool CompositeEditCommand::preservesTypingStyle() const { | 343 bool CompositeEditCommand::preservesTypingStyle() const { |
277 return false; | 344 return false; |
278 } | 345 } |
279 | 346 |
280 bool CompositeEditCommand::isTypingCommand() const { | 347 bool CompositeEditCommand::isTypingCommand() const { |
281 return false; | 348 return false; |
282 } | 349 } |
283 | 350 |
(...skipping 1769 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2053 return node; | 2120 return node; |
2054 } | 2121 } |
2055 | 2122 |
2056 DEFINE_TRACE(CompositeEditCommand) { | 2123 DEFINE_TRACE(CompositeEditCommand) { |
2057 visitor->trace(m_commands); | 2124 visitor->trace(m_commands); |
2058 visitor->trace(m_composition); | 2125 visitor->trace(m_composition); |
2059 EditCommand::trace(visitor); | 2126 EditCommand::trace(visitor); |
2060 } | 2127 } |
2061 | 2128 |
2062 } // namespace blink | 2129 } // namespace blink |
OLD | NEW |