| 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 {
|
|
|