Index: third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp |
diff --git a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp |
index ee81dce271d7319aab59e5652f6a218db8f031a0..5702b3bbc81c4eed9754786df090bca029fbba18 100644 |
--- a/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp |
+++ b/third_party/WebKit/Source/core/editing/commands/CompositeEditCommand.cpp |
@@ -77,28 +77,71 @@ |
namespace blink { |
+namespace { |
+ |
+bool dispatchBeforeInputEvent(EditCommandSource source, |
+ LocalFrame* frame, |
+ Node* target, |
+ InputEvent::InputType inputType, |
+ const String& data, |
+ DataTransfer* dataTransfer, |
+ InputEvent::EventCancelable isCancelable, |
+ InputEvent::EventIsComposing isComposing, |
+ const RangeVector* ranges) { |
+ // Don't fire 'beforeinput', return true to continue. |
+ if (source != EditCommandSource::kMenuOrKeyBinding || |
+ inputType == InputEvent::InputType::None) |
+ return true; |
+ if (!RuntimeEnabledFeatures::inputEventEnabled()) |
+ return true; |
+ if (!frame || !target || !target->isConnected()) |
+ return true; |
+ |
+ if (!hasRichlyEditableStyle(*target)) { |
+ // Plain-text only elements (<input>, <textarea>, etc.) don't support |
+ // DataTransfer or Range. |
+ dataTransfer = nullptr; |
+ ranges = nullptr; |
+ } |
+ |
+ InputEvent* beforeInputEvent; |
+ |
+ if (dataTransfer) { |
+ beforeInputEvent = InputEvent::createBeforeInput( |
+ inputType, dataTransfer, isCancelable, isComposing, ranges); |
+ } else { |
+ beforeInputEvent = InputEvent::createBeforeInput( |
+ inputType, data, isCancelable, isComposing, ranges); |
+ } |
+ |
+ DispatchEventResult result = target->dispatchEvent(beforeInputEvent); |
+ // 'beforeinput' event handler may destroy target frame. |
+ if (frame->document()->frame() != frame) |
+ return false; |
+ return result == DispatchEventResult::NotCanceled; |
+} |
+ |
+} // anonymous namespace |
+ |
using namespace HTMLNames; |
EditCommandComposition* EditCommandComposition::create( |
Document* document, |
const VisibleSelection& startingSelection, |
- const VisibleSelection& endingSelection, |
- InputEvent::InputType inputType) { |
+ const VisibleSelection& endingSelection) { |
return new EditCommandComposition(document, startingSelection, |
- endingSelection, inputType); |
+ endingSelection); |
} |
EditCommandComposition::EditCommandComposition( |
Document* document, |
const VisibleSelection& startingSelection, |
- const VisibleSelection& endingSelection, |
- InputEvent::InputType inputType) |
+ const VisibleSelection& endingSelection) |
: m_document(document), |
m_startingSelection(startingSelection), |
m_endingSelection(endingSelection), |
m_startingRootEditableElement(startingSelection.rootEditableElement()), |
- m_endingRootEditableElement(endingSelection.rootEditableElement()), |
- m_inputType(inputType) {} |
+ m_endingRootEditableElement(endingSelection.rootEditableElement()) {} |
bool EditCommandComposition::belongsTo(const LocalFrame& frame) const { |
DCHECK(m_document); |
@@ -152,18 +195,18 @@ void EditCommandComposition::reapply(EditCommandSource source) { |
frame->editor().reappliedEditing(this); |
} |
-bool EditCommandComposition::willUnapply(EditCommandSource) { |
- // TODO(chongz): Fire 'beforeinput' for 'historyUndo'. |
- return true; |
-} |
- |
-bool EditCommandComposition::willReapply(EditCommandSource) { |
- // TODO(chongz): Fire 'beforeinput' for 'historyRedo'. |
- return true; |
+bool EditCommandComposition::willUnapply(EditCommandSource source) { |
+ return dispatchBeforeInputEvent(source, m_document->frame(), m_document, |
+ InputEvent::InputType::HistoryUndo, nullAtom, |
+ nullptr, InputEvent::IsCancelable, |
+ InputEvent::NotComposing, nullptr); |
} |
-InputEvent::InputType EditCommandComposition::inputType() const { |
- return m_inputType; |
+bool EditCommandComposition::willReapply(EditCommandSource source) { |
+ return dispatchBeforeInputEvent(source, m_document->frame(), m_document, |
+ InputEvent::InputType::HistoryRedo, nullAtom, |
+ nullptr, InputEvent::IsCancelable, |
+ InputEvent::NotComposing, nullptr); |
} |
void EditCommandComposition::append(SimpleEditCommand* command) { |
@@ -232,6 +275,11 @@ bool CompositeEditCommand::apply(EditCommandSource source) { |
} |
ensureComposition(); |
+ // Covers the initial TypingCommand and other top-level commands. |
+ // TypingCommand::willAddTypingToOpenCommand() also calls willApplyEditing(). |
+ if (!willApplyEditing(source)) |
+ return false; |
+ |
// Changes to the document may have been made since the last editing operation |
// that require a layout, as in <rdar://problem/5658603>. Low level |
// operations, like RemoveNodeCommand, don't require a layout because the high |
@@ -239,9 +287,6 @@ bool CompositeEditCommand::apply(EditCommandSource source) { |
// the creation of VisiblePositions). |
document().updateStyleAndLayoutIgnorePendingStylesheets(); |
- if (!willApplyEditing(source)) |
- return false; |
- |
LocalFrame* frame = document().frame(); |
DCHECK(frame); |
EditingState editingState; |
@@ -262,15 +307,37 @@ EditCommandComposition* CompositeEditCommand::ensureComposition() { |
CompositeEditCommand* command = this; |
while (command && command->parent()) |
command = command->parent(); |
- if (!command->m_composition) |
+ if (!command->m_composition) { |
command->m_composition = EditCommandComposition::create( |
- &document(), startingSelection(), endingSelection(), inputType()); |
+ &document(), startingSelection(), endingSelection()); |
+ } |
return command->m_composition.get(); |
} |
-bool CompositeEditCommand::willApplyEditing(EditCommandSource) { |
- // TODO(chongz): Move all the 'beforeinput' dispatching logic here. |
- return true; |
+bool CompositeEditCommand::willApplyEditing(EditCommandSource source) { |
+ return dispatchBeforeInputEvent( |
+ source, document().frame(), eventTargetNodeForDocument(&document()), |
+ inputType(), textDataForInputEvent(), dataTransferForInputEvent(), |
+ isCancelableFromCommand(this), isComposingFromCommand(this), |
+ targetRangesForInputEvent()); |
+} |
+ |
+InputEvent::InputType CompositeEditCommand::inputType() const { |
+ return InputEvent::InputType::None; |
+} |
+ |
+String CompositeEditCommand::textDataForInputEvent() const { |
+ return nullAtom; |
+} |
+ |
+DataTransfer* CompositeEditCommand::dataTransferForInputEvent() const { |
+ return nullptr; |
+} |
+ |
+RangeVector* CompositeEditCommand::targetRangesForInputEvent() const { |
+ if (!document().frame()->editor().canEditRichly()) |
+ return nullptr; |
+ return new RangeVector(1, document().frame()->selection().firstRange()); |
} |
bool CompositeEditCommand::preservesTypingStyle() const { |