Index: third_party/WebKit/Source/core/editing/Editor.cpp |
diff --git a/third_party/WebKit/Source/core/editing/Editor.cpp b/third_party/WebKit/Source/core/editing/Editor.cpp |
index c1d7b1601c31f25d33007acffabad03502910b9f..3ee2d287a2a898919defb77bf55789baad84c1a7 100644 |
--- a/third_party/WebKit/Source/core/editing/Editor.cpp |
+++ b/third_party/WebKit/Source/core/editing/Editor.cpp |
@@ -86,6 +86,7 @@ |
#include "core/page/Page.h" |
#include "core/svg/SVGImageElement.h" |
#include "platform/KillRing.h" |
+#include "platform/clipboard/ClipboardMimeTypes.h" |
#include "platform/weborigin/KURL.h" |
#include "wtf/PtrUtil.h" |
#include "wtf/text/CharacterNames.h" |
@@ -98,18 +99,48 @@ using namespace Unicode; |
namespace { |
+DispatchEventResult dispatchBeforeInputEvent( |
+ Node* target, |
+ InputEvent::InputType inputType, |
+ const String& data, |
+ DataTransfer* dataTransfer, |
+ InputEvent::EventCancelable isCancelable, |
+ InputEvent::EventIsComposing isComposing, |
+ const RangeVector* ranges) { |
+ if (!RuntimeEnabledFeatures::inputEventEnabled()) |
+ return DispatchEventResult::NotCanceled; |
+ if (!target || !target->isConnected()) |
+ return DispatchEventResult::NotCanceled; |
+ |
+ 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); |
+ } |
+ return target->dispatchEvent(beforeInputEvent); |
+} |
+ |
void dispatchInputEvent(Element* target, |
InputEvent::InputType inputType, |
const String& data, |
InputEvent::EventIsComposing isComposing) { |
if (!RuntimeEnabledFeatures::inputEventEnabled()) |
return; |
- if (!target) |
+ if (!target || !target->isConnected()) |
return; |
- // TODO(chongz): Pass appreciate |ranges| after it's defined on spec. |
- // http://w3c.github.io/editing/input-events.html#dom-inputevent-inputtype |
InputEvent* inputEvent = |
- InputEvent::createInput(inputType, data, isComposing, nullptr); |
+ InputEvent::createInput(inputType, data, isComposing); |
target->dispatchScopedEvent(inputEvent); |
} |
@@ -130,8 +161,17 @@ InputEvent::EventIsComposing isComposingFromCommand( |
if (command->isTypingCommand() && |
toTypingCommand(command)->compositionType() != |
TypingCommand::TextCompositionNone) |
- return InputEvent::EventIsComposing::IsComposing; |
- return InputEvent::EventIsComposing::NotComposing; |
+ return InputEvent::IsComposing; |
+ return InputEvent::NotComposing; |
+} |
+ |
+InputEvent::EventCancelable isCancelableFromCommand( |
+ const CompositeEditCommand* command) { |
+ if (command->isTypingCommand() && |
+ toTypingCommand(command)->compositionType() == |
+ TypingCommand::TextCompositionUpdate) |
+ return InputEvent::NotCancelable; |
+ return InputEvent::IsCancelable; |
} |
} // anonymous namespace |
@@ -610,62 +650,6 @@ void Editor::replaceSelectionAfterDragging(DocumentFragment* fragment, |
->apply(); |
} |
-bool Editor::deleteSelectionAfterDraggingWithEvents( |
- Element* dragSource, |
- DeleteMode deleteMode, |
- const Position& referenceMovePosition) { |
- if (!dragSource || !dragSource->isConnected()) |
- return true; |
- |
- // Dispatch 'beforeinput'. |
- const bool shouldDelete = dispatchBeforeInputEditorCommand( |
- dragSource, InputEvent::InputType::DeleteByDrag, |
- nullptr) == DispatchEventResult::NotCanceled; |
- |
- // 'beforeinput' event handler may destroy frame, return false to cancel |
- // remaining actions; |
- if (m_frame->document()->frame() != m_frame) |
- return false; |
- |
- if (shouldDelete && dragSource->isConnected()) { |
- deleteSelectionWithSmartDelete( |
- deleteMode, InputEvent::InputType::DeleteByDrag, referenceMovePosition); |
- } |
- |
- return true; |
-} |
- |
-bool Editor::replaceSelectionAfterDraggingWithEvents( |
- Element* dropTarget, |
- DragData* dragData, |
- DocumentFragment* fragment, |
- Range* dropCaretRange, |
- InsertMode insertMode, |
- DragSourceType dragSourceType) { |
- if (!dropTarget || !dropTarget->isConnected()) |
- return true; |
- |
- // Dispatch 'beforeinput'. |
- DataTransfer* dataTransfer = |
- DataTransfer::create(DataTransfer::DragAndDrop, DataTransferReadable, |
- dragData->platformData()); |
- dataTransfer->setSourceOperation(dragData->draggingSourceOperationMask()); |
- const bool shouldInsert = |
- dispatchBeforeInputDataTransfer( |
- dropTarget, InputEvent::InputType::InsertFromDrop, dataTransfer, |
- nullptr) == DispatchEventResult::NotCanceled; |
- |
- // 'beforeinput' event handler may destroy frame, return false to cancel |
- // remaining actions; |
- if (m_frame->document()->frame() != m_frame) |
- return false; |
- |
- if (shouldInsert && dropTarget->isConnected()) |
- replaceSelectionAfterDragging(fragment, insertMode, dragSourceType); |
- |
- return true; |
-} |
- |
EphemeralRange Editor::selectedRange() { |
return frame().selection().selection().toNormalizedEphemeralRange(); |
} |
@@ -802,6 +786,24 @@ static void dispatchEditableContentChangedEvents(Element* startRoot, |
Event::create(EventTypeNames::webkitEditableContentChanged)); |
} |
+bool Editor::willApplyEditing(CompositeEditCommand* cmd) { |
+ // Don't fire 'beforeinput', return true to continue. |
+ if (m_executingCommandFromDOM || |
+ cmd->inputType() == InputEvent::InputType::None) |
+ return true; |
+ |
+ DispatchEventResult result = dispatchBeforeInputEvent( |
+ eventTargetNodeForDocument(m_frame->document()), cmd->inputType(), |
+ cmd->textDataForInputEvent(), cmd->dataTransferForInputEvent(), |
+ isCancelableFromCommand(cmd), isComposingFromCommand(cmd), |
+ cmd->targetRangesForInputEvent()); |
+ |
+ // 'beforeinput' event handler may destroy target frame. |
+ if (m_frame->document()->frame() != m_frame) |
+ return false; |
+ return result == DispatchEventResult::NotCanceled; |
+} |
+ |
void Editor::appliedEditing(CompositeEditCommand* cmd) { |
DCHECK(!cmd->isCommandGroupWrapper()); |
EventQueueScope scope; |
@@ -933,7 +935,8 @@ Editor::Editor(LocalFrame& frame) |
m_killRing(wrapUnique(new KillRing)), |
m_areMarkedTextMatchesHighlighted(false), |
m_defaultParagraphSeparator(EditorParagraphSeparatorIsDiv), |
- m_overwriteModeEnabled(false) {} |
+ m_overwriteModeEnabled(false), |
+ m_executingCommandFromDOM(false) {} |
Editor::~Editor() {} |
@@ -1042,16 +1045,6 @@ void Editor::cut(EditorCommandSource source) { |
writeSelectionToPasteboard(); |
} |
- if (source == CommandFromMenuOrKeyBinding) { |
- if (dispatchBeforeInputDataTransfer(findEventTargetFromSelection(), |
- InputEvent::InputType::DeleteByCut, |
- nullptr, nullptr) != |
- DispatchEventResult::NotCanceled) |
- return; |
- // 'beforeinput' event handler may destroy target frame. |
- if (m_frame->document()->frame() != m_frame) |
- return; |
- } |
deleteSelectionWithSmartDelete( |
canSmartCopyOrDelete() ? DeleteMode::Smart : DeleteMode::Simple, |
InputEvent::InputType::DeleteByCut); |
@@ -1100,21 +1093,6 @@ void Editor::paste(EditorCommandSource source) { |
? AllMimeTypes |
: PlainTextOnly; |
- if (source == CommandFromMenuOrKeyBinding) { |
- DataTransfer* dataTransfer = |
- DataTransfer::create(DataTransfer::CopyAndPaste, DataTransferReadable, |
- DataObject::createFromPasteboard(pasteMode)); |
- |
- if (dispatchBeforeInputDataTransfer(findEventTargetFromSelection(), |
- InputEvent::InputType::InsertFromPaste, |
- dataTransfer, nullptr) != |
- DispatchEventResult::NotCanceled) |
- return; |
- // 'beforeinput' event handler may destroy target frame. |
- if (m_frame->document()->frame() != m_frame) |
- return; |
- } |
- |
if (pasteMode == AllMimeTypes) |
pasteWithPasteboard(Pasteboard::generalPasteboard()); |
else |
@@ -1231,6 +1209,17 @@ bool Editor::canUndo() { |
} |
void Editor::undo() { |
+ if (!m_executingCommandFromDOM) { |
+ if (dispatchBeforeInputEvent( |
+ m_frame->document(), InputEvent::InputType::HistoryUndo, nullAtom, |
+ nullptr, InputEvent::IsCancelable, InputEvent::NotComposing, |
+ nullptr) != DispatchEventResult::NotCanceled) |
+ return; |
+ |
+ // 'beforeinput' event handler may destroy target frame. |
+ if (m_frame->document()->frame() != m_frame) |
+ return; |
+ } |
m_undoStack->undo(); |
} |
@@ -1239,6 +1228,17 @@ bool Editor::canRedo() { |
} |
void Editor::redo() { |
+ if (!m_executingCommandFromDOM) { |
+ if (dispatchBeforeInputEvent( |
+ m_frame->document(), InputEvent::InputType::HistoryRedo, nullAtom, |
+ nullptr, InputEvent::IsCancelable, InputEvent::NotComposing, |
+ nullptr) != DispatchEventResult::NotCanceled) |
+ return; |
+ |
+ // 'beforeinput' event handler may destroy target frame. |
+ if (m_frame->document()->frame() != m_frame) |
+ return; |
+ } |
m_undoStack->redo(); |
} |
@@ -1268,7 +1268,7 @@ void Editor::setBaseWritingDirection(WritingDirection direction) { |
void Editor::revealSelectionAfterEditingOperation( |
const ScrollAlignment& alignment, |
RevealExtentOption revealExtentOption) { |
- if (m_preventRevealSelection) |
+ if (m_preventRevealSelection || !m_frame->selection().isAvailable()) |
return; |
frame().selection().revealSelection(alignment, revealExtentOption); |
} |