WebKit Bugzilla
New
Browse
Search+
Log In
×
Sign in with GitHub
or
Remember my login
Create Account
·
Forgot Password
Forgotten password account recovery
[patch]
Patch for landing
bug-163021-20161007161212.patch (text/plain), 38.80 KB, created by
Wenson Hsieh
on 2016-10-07 16:15:28 PDT
(
hide
)
Description:
Patch for landing
Filename:
MIME Type:
Creator:
Wenson Hsieh
Created:
2016-10-07 16:15:28 PDT
Size:
38.80 KB
patch
obsolete
>Subversion Revision: 206866 >diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog >index e9820b5e0f2fcaeec86ae2351928088553af8113..0029528166f0114a1c132e551aef356f92a8b1ca 100644 >--- a/Source/WebCore/ChangeLog >+++ b/Source/WebCore/ChangeLog >@@ -1,3 +1,92 @@ >+2016-10-07 Wenson Hsieh <wenson_hsieh@apple.com> >+ >+ Support onbeforeinput event handling for the new InputEvent spec >+ https://bugs.webkit.org/show_bug.cgi?id=163021 >+ <rdar://problem/28658073> >+ >+ Reviewed by Darin Adler. >+ >+ Adds support for parsing the onbeforeinput attribute, and for sending default-preventable >+ `beforeinput` InputEvents to the page. To do this, we introduce two new virtual methods: >+ willApplyCommand and didApplyCommand on the CompositeEditCommand that are called before and >+ after CompositeEditCommand::doApply, respectively. willApplyCommand indicates whether or not >+ the composite editor command should proceed with applying the command. >+ >+ Tweaks existing layout tests and adds new tests. >+ >+ Tests: fast/events/before-input-events-different-start-end-elements.html >+ fast/events/before-input-events-prevent-default-in-textfield.html >+ fast/events/before-input-events-prevent-default.html >+ >+ * dom/Document.idl: >+ * dom/Element.idl: >+ * dom/EventNames.h: >+ * dom/Node.cpp: >+ (WebCore::Node::dispatchInputEvent): >+ (WebCore::Node::defaultEventHandler): >+ >+ Currently, we fire input events in Node in response to dispatching a webkitEditableContentChangedEvent. After >+ some discussion, Ryosuke and I believe that it will be ok to instead directly dispatch the input event where we >+ would normally dispatch a webkitEditableContentChangedEvent. >+ >+ * editing/CompositeEditCommand.cpp: >+ (WebCore::EditCommandComposition::unapply): >+ (WebCore::EditCommandComposition::reapply): >+ >+ Added calls to Editor::willUnapplyEditing and Editor::willReapplyEditing. >+ >+ (WebCore::CompositeEditCommand::willApplyCommand): >+ (WebCore::CompositeEditCommand::apply): >+ (WebCore::CompositeEditCommand::didApplyCommand): >+ >+ Added new virtual functions, willApplyCommand and didApplyCommand, that surround a call to >+ CompositeEditCommand::doApply. By default, they call willApplyEditing and appliedEditing on the editor, but may >+ be overridden in special cases, such as in TypingCommand, where we invoke appliedEditing after adding a new >+ typing command to the last open command. >+ >+ If willApplyCommand returns false, CompositeEditCommand::apply will bail and not proceed with the command. >+ >+ * editing/CompositeEditCommand.h: >+ * editing/Editor.cpp: >+ (WebCore::dispatchBeforeInputEvent): >+ (WebCore::dispatchBeforeInputEvents): >+ (WebCore::dispatchInputEvents): >+ (WebCore::Editor::willApplyEditing): >+ (WebCore::Editor::appliedEditing): >+ (WebCore::Editor::willUnapplyEditing): >+ (WebCore::Editor::unappliedEditing): >+ (WebCore::Editor::willReapplyEditing): >+ (WebCore::Editor::reappliedEditing): >+ (WebCore::Editor::computeAndSetTypingStyle): >+ (WebCore::dispatchEditableContentChangedEvents): Deleted. >+ * editing/Editor.h: >+ * editing/TypingCommand.cpp: >+ (WebCore::TypingCommand::willApplyCommand): >+ (WebCore::TypingCommand::didApplyCommand): >+ (WebCore::TypingCommand::willAddTypingToOpenCommand): >+ (WebCore::TypingCommand::insertTextRunWithoutNewlines): >+ (WebCore::TypingCommand::insertLineBreak): >+ (WebCore::TypingCommand::insertParagraphSeparator): >+ (WebCore::TypingCommand::insertParagraphSeparatorInQuotedContent): >+ (WebCore::TypingCommand::deleteKeyPressed): >+ (WebCore::TypingCommand::forwardDeleteKeyPressed): >+ (WebCore::TypingCommand::deleteSelection): >+ >+ These now invoke willAddTypingToOpenCommand before proceeding with creating the command and applying it. The >+ flow is now: >+ - willAddTypingToOpenCommand >+ - create and apply a new command >+ - typingAddedToOpenCommand >+ >+ * editing/TypingCommand.h: >+ (WebCore::TypingCommand::preservesTypingStyle): Deleted. >+ (WebCore::TypingCommand::shouldRetainAutocorrectionIndicator): Deleted. >+ (WebCore::TypingCommand::setShouldRetainAutocorrectionIndicator): Deleted. >+ (WebCore::TypingCommand::shouldStopCaretBlinking): Deleted. >+ * html/HTMLAttributeNames.in: >+ * html/HTMLElement.cpp: >+ (WebCore::HTMLElement::createEventHandlerNameMap): >+ > 2016-10-05 Philippe Normand <pnormand@igalia.com> > > [GStreamer][OWR] GL rendering support >diff --git a/Source/WebCore/dom/Document.idl b/Source/WebCore/dom/Document.idl >index cda4e6bb7e1010f2ceab4238d5f41ac9d7c53b4f..85949748ad5c5526b65fc052bf05c4654b9fa876 100644 >--- a/Source/WebCore/dom/Document.idl >+++ b/Source/WebCore/dom/Document.idl >@@ -192,6 +192,7 @@ > // FIXME: Should these be exposed on Window as well (and therefore moved to GlobalEventHandlers.idl)? > [NotEnumerable] attribute EventHandler onbeforecopy; > [NotEnumerable] attribute EventHandler onbeforecut; >+ [NotEnumerable] attribute EventHandler onbeforeinput; > [NotEnumerable] attribute EventHandler onbeforepaste; > [NotEnumerable] attribute EventHandler oncopy; > [NotEnumerable] attribute EventHandler oncut; >diff --git a/Source/WebCore/dom/Element.idl b/Source/WebCore/dom/Element.idl >index bcf353b64fe8a742da986a11a1bb5342ec072287..4e7cf1c25447219623083707eb99383eea5592c7 100644 >--- a/Source/WebCore/dom/Element.idl >+++ b/Source/WebCore/dom/Element.idl >@@ -145,6 +145,7 @@ > // FIXME: Should these be exposed on Window as well (and therefore moved to GlobalEventHandlers.idl)? > [NotEnumerable] attribute EventHandler onbeforecopy; > [NotEnumerable] attribute EventHandler onbeforecut; >+ [NotEnumerable] attribute EventHandler onbeforeinput; > [NotEnumerable] attribute EventHandler onbeforepaste; > [NotEnumerable] attribute EventHandler oncopy; > [NotEnumerable] attribute EventHandler oncut; >diff --git a/Source/WebCore/dom/EventNames.h b/Source/WebCore/dom/EventNames.h >index da6df40491fb40009a4f3cadeeb52ba7167b158d..cb2d2c2de8daa734087722363a30693f1230bdb9 100644 >--- a/Source/WebCore/dom/EventNames.h >+++ b/Source/WebCore/dom/EventNames.h >@@ -60,6 +60,7 @@ namespace WebCore { > macro(autocompleteerror) \ > macro(beforecopy) \ > macro(beforecut) \ >+ macro(beforeinput) \ > macro(beforeload) \ > macro(beforepaste) \ > macro(beforeunload) \ >diff --git a/Source/WebCore/dom/Node.cpp b/Source/WebCore/dom/Node.cpp >index c3e74008f54a7f1295547a4e69e008c35677ccd0..24c40917b9a861ebf2ca2eabf3f49f7eeed7f9dd 100644 >--- a/Source/WebCore/dom/Node.cpp >+++ b/Source/WebCore/dom/Node.cpp >@@ -2204,7 +2204,8 @@ bool Node::dispatchBeforeLoadEvent(const String& sourceURL) > > void Node::dispatchInputEvent(const AtomicString& inputType) > { >- if (document().settings()->inputEventsEnabled()) >+ auto* settings = document().settings(); >+ if (settings && settings->inputEventsEnabled()) > dispatchScopedEvent(InputEvent::create(eventNames().inputEvent, inputType, true, false, document().defaultView(), 0)); > else > dispatchScopedEvent(Event::create(eventNames().inputEvent, true, false)); >@@ -2272,8 +2273,6 @@ void Node::defaultEventHandler(Event& event) > frame->eventHandler().defaultTouchEventHandler(renderer->node(), &downcast<TouchEvent>(event)); > } > #endif >- } else if (event.type() == eventNames().webkitEditableContentChangedEvent) { >- dispatchInputEvent(emptyString()); > } > } > >diff --git a/Source/WebCore/editing/CompositeEditCommand.cpp b/Source/WebCore/editing/CompositeEditCommand.cpp >index 7db87bd7048e9c0e6553c5410043861f31530432..61fa1f6d9ae853059b680763ed9875b85a82aad8 100644 >--- a/Source/WebCore/editing/CompositeEditCommand.cpp >+++ b/Source/WebCore/editing/CompositeEditCommand.cpp >@@ -231,6 +231,9 @@ void EditCommandComposition::unapply() > frame->editor().cancelComposition(); > #endif > >+ if (!frame->editor().willUnapplyEditing(*this)) >+ return; >+ > size_t size = m_commands.size(); > for (size_t i = size; i; --i) > m_commands[i - 1]->doUnapply(); >@@ -255,6 +258,9 @@ void EditCommandComposition::reapply() > // if one is necessary (like for the creation of VisiblePositions). > m_document->updateLayoutIgnorePendingStylesheets(); > >+ if (!frame->editor().willReapplyEditing(*this)) >+ return; >+ > for (auto& command : m_commands) > command->doReapply(); > >@@ -311,6 +317,11 @@ CompositeEditCommand::~CompositeEditCommand() > ASSERT(isTopLevelCommand() || !m_composition); > } > >+bool CompositeEditCommand::willApplyCommand() >+{ >+ return frame().editor().willApplyEditing(*this); >+} >+ > void CompositeEditCommand::apply() > { > if (!endingSelection().isContentRichlyEditable()) { >@@ -337,18 +348,23 @@ void CompositeEditCommand::apply() > // if one is necessary (like for the creation of VisiblePositions). > document().updateLayoutIgnorePendingStylesheets(); > >+ if (!willApplyCommand()) >+ return; >+ > { > EventQueueScope eventQueueScope; > doApply(); > } > >- // Only need to call appliedEditing for top-level commands, >- // and TypingCommands do it on their own (see TypingCommand::typingAddedToOpenCommand). >- if (!isTypingCommand()) >- frame().editor().appliedEditing(this); >+ didApplyCommand(); > setShouldRetainAutocorrectionIndicator(false); > } > >+void CompositeEditCommand::didApplyCommand() >+{ >+ frame().editor().appliedEditing(this); >+} >+ > EditCommandComposition* CompositeEditCommand::ensureComposition() > { > CompositeEditCommand* command = this; >diff --git a/Source/WebCore/editing/CompositeEditCommand.h b/Source/WebCore/editing/CompositeEditCommand.h >index 08d243dd3022d15b804cf5b07bc1b445581df72d..147d2741a55ea86d3ae45d34b5ea4fa5c033f1a8 100644 >--- a/Source/WebCore/editing/CompositeEditCommand.h >+++ b/Source/WebCore/editing/CompositeEditCommand.h >@@ -117,6 +117,10 @@ public: > protected: > explicit CompositeEditCommand(Document&, EditAction = EditActionUnspecified); > >+ // If willApplyCommand returns false, we won't proceed with applying the command. >+ virtual bool willApplyCommand(); >+ virtual void didApplyCommand(); >+ > // > // sugary-sweet convenience functions to help create and apply edit commands in composite commands > // >diff --git a/Source/WebCore/editing/Editor.cpp b/Source/WebCore/editing/Editor.cpp >index 608f745c69ae2d72d584204daa2b9062d02962c6..03100f80cef4185279d3cb150f611d70ec00918d 100644 >--- a/Source/WebCore/editing/Editor.cpp >+++ b/Source/WebCore/editing/Editor.cpp >@@ -59,7 +59,9 @@ > #include "HTMLTextAreaElement.h" > #include "HitTestResult.h" > #include "IndentOutdentCommand.h" >+#include "InputEvent.h" > #include "InsertListCommand.h" >+#include "InsertTextCommand.h" > #include "KeyboardEvent.h" > #include "KillRing.h" > #include "Logging.h" >@@ -109,6 +111,18 @@ > > namespace WebCore { > >+static bool dispatchBeforeInputEvent(Element& element, const AtomicString& inputType) >+{ >+ auto* settings = element.document().settings(); >+ if (!settings || !settings->inputEventsEnabled()) >+ return true; >+ >+ auto event = InputEvent::create(eventNames().beforeinputEvent, inputType, true, true, element.document().defaultView(), 0); >+ element.dispatchScopedEvent(event); >+ >+ return !event->defaultPrevented(); >+} >+ > class ClearTextCommand : public DeleteSelectionCommand { > public: > ClearTextCommand(Document& document); >@@ -1025,14 +1039,31 @@ static void notifyTextFromControls(Element* startRoot, Element* endRoot) > endingTextControl->didEditInnerTextValue(); > } > >-static void dispatchEditableContentChangedEvents(PassRefPtr<Element> prpStartRoot, PassRefPtr<Element> prpEndRoot) >+static bool dispatchBeforeInputEvents(RefPtr<Element> startRoot, RefPtr<Element> endRoot, const AtomicString& inputTypeName) > { >- RefPtr<Element> startRoot = prpStartRoot; >- RefPtr<Element> endRoot = prpEndRoot; >+ bool continueWithDefaultBehavior = true; > if (startRoot) >- startRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentChangedEvent, false, false)); >+ continueWithDefaultBehavior &= dispatchBeforeInputEvent(*startRoot, inputTypeName); > if (endRoot && endRoot != startRoot) >- endRoot->dispatchEvent(Event::create(eventNames().webkitEditableContentChangedEvent, false, false)); >+ continueWithDefaultBehavior &= dispatchBeforeInputEvent(*endRoot, inputTypeName); >+ return continueWithDefaultBehavior; >+} >+ >+static void dispatchInputEvents(RefPtr<Element> startRoot, RefPtr<Element> endRoot, const AtomicString& inputTypeName) >+{ >+ if (startRoot) >+ startRoot->dispatchInputEvent(inputTypeName); >+ if (endRoot && endRoot != startRoot) >+ endRoot->dispatchInputEvent(inputTypeName); >+} >+ >+bool Editor::willApplyEditing(CompositeEditCommand& command) const >+{ >+ auto* composition = command.composition(); >+ if (!composition) >+ return true; >+ >+ return dispatchBeforeInputEvents(composition->startingRootEditableElement(), composition->endingRootEditableElement(), emptyString()); > } > > void Editor::appliedEditing(PassRefPtr<CompositeEditCommand> cmd) >@@ -1051,7 +1082,7 @@ void Editor::appliedEditing(PassRefPtr<CompositeEditCommand> cmd) > FrameSelection::SetSelectionOptions options = cmd->isDictationCommand() ? FrameSelection::DictationTriggered : 0; > > changeSelectionAfterCommand(newSelection, options); >- dispatchEditableContentChangedEvents(composition->startingRootEditableElement(), composition->endingRootEditableElement()); >+ dispatchInputEvents(composition->startingRootEditableElement(), composition->endingRootEditableElement(), emptyString()); > > updateEditorUINowIfScheduled(); > >@@ -1074,6 +1105,11 @@ void Editor::appliedEditing(PassRefPtr<CompositeEditCommand> cmd) > respondToChangedContents(newSelection); > } > >+bool Editor::willUnapplyEditing(const EditCommandComposition& composition) const >+{ >+ return dispatchBeforeInputEvents(composition.startingRootEditableElement(), composition.endingRootEditableElement(), emptyString()); >+} >+ > void Editor::unappliedEditing(PassRefPtr<EditCommandComposition> cmd) > { > document().updateLayout(); >@@ -1082,7 +1118,7 @@ void Editor::unappliedEditing(PassRefPtr<EditCommandComposition> cmd) > > VisibleSelection newSelection(cmd->startingSelection()); > changeSelectionAfterCommand(newSelection, FrameSelection::defaultSetSelectionOptions()); >- dispatchEditableContentChangedEvents(cmd->startingRootEditableElement(), cmd->endingRootEditableElement()); >+ dispatchInputEvents(cmd->startingRootEditableElement(), cmd->endingRootEditableElement(), emptyString()); > > updateEditorUINowIfScheduled(); > >@@ -1094,6 +1130,11 @@ void Editor::unappliedEditing(PassRefPtr<EditCommandComposition> cmd) > respondToChangedContents(newSelection); > } > >+bool Editor::willReapplyEditing(const EditCommandComposition& composition) const >+{ >+ return dispatchBeforeInputEvents(composition.startingRootEditableElement(), composition.endingRootEditableElement(), emptyString()); >+} >+ > void Editor::reappliedEditing(PassRefPtr<EditCommandComposition> cmd) > { > document().updateLayout(); >@@ -1102,7 +1143,7 @@ void Editor::reappliedEditing(PassRefPtr<EditCommandComposition> cmd) > > VisibleSelection newSelection(cmd->endingSelection()); > changeSelectionAfterCommand(newSelection, FrameSelection::defaultSetSelectionOptions()); >- dispatchEditableContentChangedEvents(cmd->startingRootEditableElement(), cmd->endingRootEditableElement()); >+ dispatchInputEvents(cmd->startingRootEditableElement(), cmd->endingRootEditableElement(), emptyString()); > > updateEditorUINowIfScheduled(); > >@@ -3052,6 +3093,10 @@ void Editor::computeAndSetTypingStyle(EditingStyle& style, EditAction editingAct > return; > } > >+ auto* element = m_frame.selection().selection().rootEditableElement(); >+ if (element && !dispatchBeforeInputEvent(*element, emptyString())) >+ return; >+ > // Calculate the current typing style. > RefPtr<EditingStyle> typingStyle; > if (auto existingTypingStyle = m_frame.selection().typingStyle()) >@@ -3065,6 +3110,9 @@ void Editor::computeAndSetTypingStyle(EditingStyle& style, EditAction editingAct > if (!blockStyle->isEmpty()) > applyCommand(ApplyStyleCommand::create(document(), blockStyle.get(), editingAction)); > >+ if (element) >+ element->dispatchInputEvent(emptyString()); >+ > // Set the remaining style as the typing style. > m_frame.selection().setTypingStyle(typingStyle); > } >diff --git a/Source/WebCore/editing/Editor.h b/Source/WebCore/editing/Editor.h >index 738e8f6c4e195eb066b95d0bd104e3ee270cbd5a..46abc179a176fe69beb2f2bff496c3b8418bbf3d 100644 >--- a/Source/WebCore/editing/Editor.h >+++ b/Source/WebCore/editing/Editor.h >@@ -198,6 +198,11 @@ public: > WEBCORE_EXPORT void applyStyleToSelection(Ref<EditingStyle>&&, EditAction); > void applyParagraphStyleToSelection(StyleProperties*, EditAction); > >+ // Returns whether or not we should proceed with editing. >+ bool willApplyEditing(CompositeEditCommand&) const; >+ bool willUnapplyEditing(const EditCommandComposition&) const; >+ bool willReapplyEditing(const EditCommandComposition&) const; >+ > void appliedEditing(PassRefPtr<CompositeEditCommand>); > void unappliedEditing(PassRefPtr<EditCommandComposition>); > void reappliedEditing(PassRefPtr<EditCommandComposition>); >diff --git a/Source/WebCore/editing/TypingCommand.cpp b/Source/WebCore/editing/TypingCommand.cpp >index 079aac4e4414cb6d6761aaf68fa6aa54c4005c51..14127113541d0ad724085302a79347a0ce432f5b 100644 >--- a/Source/WebCore/editing/TypingCommand.cpp >+++ b/Source/WebCore/editing/TypingCommand.cpp >@@ -262,6 +262,16 @@ void TypingCommand::postTextStateChangeNotificationForDeletion(const VisibleSele > composition()->setRangeDeletedByUnapply(range); > } > >+bool TypingCommand::willApplyCommand() >+{ >+ if (!m_isHandlingInitialTypingCommand) { >+ // The TypingCommand will handle the willApplyCommand logic separately in TypingCommand::willAddTypingToOpenCommand. >+ return true; >+ } >+ >+ return CompositeEditCommand::willApplyCommand(); >+} >+ > void TypingCommand::doApply() > { > if (endingSelection().isNoneOrOrphaned()) >@@ -298,6 +308,12 @@ void TypingCommand::doApply() > ASSERT_NOT_REACHED(); > } > >+void TypingCommand::didApplyCommand() >+{ >+ // TypingCommands handle applied editing separately (see TypingCommand::typingAddedToOpenCommand). >+ m_isHandlingInitialTypingCommand = false; >+} >+ > void TypingCommand::markMisspellingsAfterTyping(ETypingCommand commandType) > { > Frame& frame = this->frame(); >@@ -352,6 +368,16 @@ void TypingCommand::markMisspellingsAfterTyping(ETypingCommand commandType) > } > } > >+bool TypingCommand::willAddTypingToOpenCommand(ETypingCommand, TextGranularity) >+{ >+ if (m_isHandlingInitialTypingCommand) >+ return true; >+ >+ // FIXME: Use the newly added typing command and granularity to ensure that an InputEvent with the >+ // correct inputType is dispatched. >+ return frame().editor().willApplyEditing(*this); >+} >+ > void TypingCommand::typingAddedToOpenCommand(ETypingCommand commandTypeForAddedTyping) > { > Frame& frame = this->frame(); >@@ -393,6 +419,9 @@ void TypingCommand::insertTextAndNotifyAccessibility(const String &text, bool se > > void TypingCommand::insertTextRunWithoutNewlines(const String &text, bool selectInsertedText) > { >+ if (!willAddTypingToOpenCommand(InsertText, CharacterGranularity)) >+ return; >+ > RefPtr<InsertTextCommand> command = InsertTextCommand::create(document(), text, selectInsertedText, > m_compositionType == TextCompositionNone ? InsertTextCommand::RebalanceLeadingAndTrailingWhitespaces : InsertTextCommand::RebalanceAllWhitespaces, EditActionTyping); > >@@ -406,6 +435,9 @@ void TypingCommand::insertLineBreak() > if (!canAppendNewLineFeedToSelection(endingSelection())) > return; > >+ if (!willAddTypingToOpenCommand(InsertLineBreak, LineGranularity)) >+ return; >+ > applyCommandToComposite(InsertLineBreakCommand::create(document())); > typingAddedToOpenCommand(InsertLineBreak); > } >@@ -423,6 +455,9 @@ void TypingCommand::insertParagraphSeparator() > if (!canAppendNewLineFeedToSelection(endingSelection())) > return; > >+ if (!willAddTypingToOpenCommand(InsertParagraphSeparator, ParagraphGranularity)) >+ return; >+ > applyCommandToComposite(InsertParagraphSeparatorCommand::create(document(), false, false, EditActionTyping)); > typingAddedToOpenCommand(InsertParagraphSeparator); > } >@@ -437,6 +472,9 @@ void TypingCommand::insertParagraphSeparatorAndNotifyAccessibility() > > void TypingCommand::insertParagraphSeparatorInQuotedContent() > { >+ if (!willAddTypingToOpenCommand(InsertParagraphSeparatorInQuotedContent, ParagraphGranularity)) >+ return; >+ > // If the selection starts inside a table, just insert the paragraph separator normally > // Breaking the blockquote would also break apart the table, which is unecessary when inserting a newline > if (enclosingNodeOfType(endingSelection().start(), &isTableStructureNode)) { >@@ -479,6 +517,9 @@ bool TypingCommand::makeEditableRootEmpty() > > void TypingCommand::deleteKeyPressed(TextGranularity granularity, bool shouldAddToKillRing) > { >+ if (!willAddTypingToOpenCommand(DeleteKey, granularity)) >+ return; >+ > Frame& frame = this->frame(); > > frame.editor().updateMarkersForWordsAffectedByEditing(false); >@@ -592,6 +633,9 @@ void TypingCommand::deleteKeyPressed(TextGranularity granularity, bool shouldAdd > > void TypingCommand::forwardDeleteKeyPressed(TextGranularity granularity, bool shouldAddToKillRing) > { >+ if (!willAddTypingToOpenCommand(ForwardDeleteKey, granularity)) >+ return; >+ > Frame& frame = this->frame(); > > frame.editor().updateMarkersForWordsAffectedByEditing(false); >@@ -690,6 +734,9 @@ void TypingCommand::forwardDeleteKeyPressed(TextGranularity granularity, bool sh > > void TypingCommand::deleteSelection(bool smartDelete) > { >+ if (!willAddTypingToOpenCommand(DeleteSelection, CharacterGranularity)) >+ return; >+ > CompositeEditCommand::deleteSelection(smartDelete); > typingAddedToOpenCommand(DeleteSelection); > } >diff --git a/Source/WebCore/editing/TypingCommand.h b/Source/WebCore/editing/TypingCommand.h >index 9d15d3b6978c59bf138a9dd352df49a37f777b33..15684bd385477027cc082f7007633795a98a9167 100644 >--- a/Source/WebCore/editing/TypingCommand.h >+++ b/Source/WebCore/editing/TypingCommand.h >@@ -30,7 +30,7 @@ > > namespace WebCore { > >-class TypingCommand : public TextInsertionBaseCommand { >+class TypingCommand final : public TextInsertionBaseCommand { > public: > enum ETypingCommand { > DeleteSelection, >@@ -104,21 +104,22 @@ private: > > static RefPtr<TypingCommand> lastTypingCommandIfStillOpenForTyping(Frame&); > >- virtual void doApply(); >- virtual bool isTypingCommand() const; >- virtual bool preservesTypingStyle() const { return m_preservesTypingStyle; } >- virtual bool shouldRetainAutocorrectionIndicator() const >+ void doApply(); >+ bool isTypingCommand() const; >+ bool preservesTypingStyle() const { return m_preservesTypingStyle; } >+ bool shouldRetainAutocorrectionIndicator() const > { > ASSERT(isTopLevelCommand()); > return m_shouldRetainAutocorrectionIndicator; > } >- virtual void setShouldRetainAutocorrectionIndicator(bool retain) { m_shouldRetainAutocorrectionIndicator = retain; } >- virtual bool shouldStopCaretBlinking() const { return true; } >+ void setShouldRetainAutocorrectionIndicator(bool retain) { m_shouldRetainAutocorrectionIndicator = retain; } >+ bool shouldStopCaretBlinking() const { return true; } > void setShouldPreventSpellChecking(bool prevent) { m_shouldPreventSpellChecking = prevent; } > > static void updateSelectionIfDifferentFromCurrentSelection(TypingCommand*, Frame*); > > void updatePreservesTypingStyle(ETypingCommand); >+ bool willAddTypingToOpenCommand(ETypingCommand, TextGranularity); > void markMisspellingsAfterTyping(ETypingCommand); > void typingAddedToOpenCommand(ETypingCommand); > bool makeEditableRootEmpty(); >@@ -129,11 +130,15 @@ private: > void insertParagraphSeparatorInQuotedContentAndNotifyAccessibility(); > void insertParagraphSeparatorAndNotifyAccessibility(); > >+ bool willApplyCommand(); >+ void didApplyCommand(); >+ > ETypingCommand m_commandType; > String m_textToInsert; > bool m_openForMoreTyping; > bool m_selectInsertedText; > bool m_smartDelete; >+ bool m_isHandlingInitialTypingCommand { true }; > TextGranularity m_granularity; > TextCompositionType m_compositionType; > bool m_shouldAddToKillRing; >diff --git a/Source/WebCore/html/HTMLAttributeNames.in b/Source/WebCore/html/HTMLAttributeNames.in >index 02d86d0d79d99ec758856f3d1318a105b7653d12..2ea1af84a3c0d1377fd1ed947fbf763d7c86b52a 100644 >--- a/Source/WebCore/html/HTMLAttributeNames.in >+++ b/Source/WebCore/html/HTMLAttributeNames.in >@@ -188,6 +188,7 @@ onautocomplete > onautocompleteerror > onbeforecopy > onbeforecut >+onbeforeinput > onbeforeload > onbeforepaste > onbeforeunload >diff --git a/Source/WebCore/html/HTMLElement.cpp b/Source/WebCore/html/HTMLElement.cpp >index 85df6089c1dca6d9993c2720c1dbdbc433dc922f..f1ff252f79be5cc10ffa314b1f7fa2c8ed98be8b 100644 >--- a/Source/WebCore/html/HTMLElement.cpp >+++ b/Source/WebCore/html/HTMLElement.cpp >@@ -231,6 +231,7 @@ HTMLElement::EventHandlerNameMap HTMLElement::createEventHandlerNameMap() > &onautocompleteerrorAttr, > &onbeforecopyAttr, > &onbeforecutAttr, >+ &onbeforeinputAttr, > &onbeforeloadAttr, > &onbeforepasteAttr, > &onblurAttr, >diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog >index 2c57e73eed029c3a3b06e540acf2b3dce84311e3..2ce6c4d9eec2d2578b7a77e25e8389158596425f 100644 >--- a/LayoutTests/ChangeLog >+++ b/LayoutTests/ChangeLog >@@ -1,3 +1,27 @@ >+2016-10-07 Wenson Hsieh <wenson_hsieh@apple.com> >+ >+ Support onbeforeinput event handling for the new InputEvent spec >+ https://bugs.webkit.org/show_bug.cgi?id=163021 >+ <rdar://problem/28658073> >+ >+ Reviewed by Darin Adler. >+ >+ Tweak an existing test to hook into the 'input' event instead of 'webkitEditableContentChanged', as well as >+ tests added in r206843 to verify that `onbeforeinput` handlers are invoked with InputEvents. Also introduces >+ new unit tests verifying that calling preventDefault on InputEvents fired by `onbeforeinput` correctly prevent >+ text from being inserted or deleted. >+ >+ * editing/undo/undo-after-event-edited.html: >+ * fast/events/before-input-events-different-start-end-elements-expected.txt: Added. >+ * fast/events/before-input-events-different-start-end-elements.html: Added. >+ * fast/events/before-input-events-prevent-default-expected.txt: Added. >+ * fast/events/before-input-events-prevent-default-in-textfield-expected.txt: Added. >+ * fast/events/before-input-events-prevent-default-in-textfield.html: Added. >+ * fast/events/before-input-events-prevent-default.html: Added. >+ * fast/events/input-events-fired-when-typing-expected.txt: >+ * fast/events/input-events-fired-when-typing.html: >+ * platform/ios-simulator/TestExpectations: >+ > 2016-10-06 Ryan Haddad <ryanhaddad@apple.com> > > Skip accessibility/mac/wk1-set-selected-text-marker-range-input-element.html on mac-wk2. >diff --git a/LayoutTests/editing/undo/undo-after-event-edited.html b/LayoutTests/editing/undo/undo-after-event-edited.html >index 8289a7a48363b247a0d8dc39e33c1fbd851ce81e..991827dc4978204ad0efa998caa21c6e79aa84d0 100644 >--- a/LayoutTests/editing/undo/undo-after-event-edited.html >+++ b/LayoutTests/editing/undo/undo-after-event-edited.html >@@ -17,7 +17,7 @@ var scriptElements = document.getElementsByTagName("script"); > scriptElements[0].parentNode.removeChild(scriptElements[0]); > var eventHandlerActive = false; > >-document.addEventListener("webkitEditableContentChanged", function () { >+document.addEventListener("input", function () { > if (eventHandlerActive) > return; > eventHandlerActive = true; >diff --git a/LayoutTests/fast/events/before-input-events-different-start-end-elements-expected.txt b/LayoutTests/fast/events/before-input-events-different-start-end-elements-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..c16b0c7eeb9db1d592ced2a456f6856b7789d80b >--- /dev/null >+++ b/LayoutTests/fast/events/before-input-events-different-start-end-elements-expected.txt >@@ -0,0 +1,27 @@ >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+Fired `onbeforeinput` handler! >+Fired `oninput` handler! >+Fired `onbeforeinput` handler! >+Fired `oninput` handler! >+Fired `onbeforeinput` handler! >+Fired `oninput` handler! >+Fired `onbeforeinput` handler! >+Fired `oninput` handler! >+Fired `onbeforeinput` handler! >+Fired `oninput` handler! >+Fired `onbeforeinput` handler! >+Fired `oninput` handler! >+Fired `onbeforeinput` handler! >+Fired `oninput` handler! >+Fired `onbeforeinput` handler! >+Fired `oninput` handler! >+Fired `onbeforeinput` handler! >+Fired `oninput` handler! >+Fired `onbeforeinput` handler! >+Fired `oninput` handler! >+Fired `onbeforeinput` handler! >+Fired `oninput` handler! >+ >+ >diff --git a/LayoutTests/fast/events/before-input-events-different-start-end-elements.html b/LayoutTests/fast/events/before-input-events-different-start-end-elements.html >new file mode 100644 >index 0000000000000000000000000000000000000000..5f8e20d345b01db718002c1d04f5e6ee55448852 >--- /dev/null >+++ b/LayoutTests/fast/events/before-input-events-different-start-end-elements.html >@@ -0,0 +1,43 @@ >+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> >+<html> >+ >+<head> >+ <script src="../../resources/js-test-pre.js"></script> >+ <script> >+ function beginTest() >+ { >+ if (!window.eventSender || !window.internals || !window.testRunner) >+ return; >+ >+ internals.settings.setInputEventsEnabled(true); >+ testRunner.dumpAsText(); >+ document.querySelector("#foo").focus(); >+ >+ for (var i = 0; i < 11; i++) >+ eventSender.keyDown("delete"); >+ } >+ >+ function checkInputEvent(event) >+ { >+ debug("Fired `oninput` handler!"); >+ } >+ >+ function checkBeforeInputEvent(event) >+ { >+ debug("Fired `onbeforeinput` handler!"); >+ } >+ </script> >+</head> >+ >+<body onload=beginTest()> >+ <div id="foo" contenteditable oninput=checkInputEvent(event) onbeforeinput=checkBeforeInputEvent(event)> >+ <b> >+ abc >+ <i>def</i> >+ <u>ghi</u> >+ </b> >+ </div> >+ <script src="../../resources/js-test-post.js"></script> >+</body> >+ >+</html> >diff --git a/LayoutTests/fast/events/before-input-events-prevent-default-expected.txt b/LayoutTests/fast/events/before-input-events-prevent-default-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..b9cf947d5844c0f09ace551c99c6c16d02d6d91a >--- /dev/null >+++ b/LayoutTests/fast/events/before-input-events-prevent-default-expected.txt >@@ -0,0 +1,5 @@ >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+Fired `onbeforeinput`: preventing default! >+ >diff --git a/LayoutTests/fast/events/before-input-events-prevent-default-in-textfield-expected.txt b/LayoutTests/fast/events/before-input-events-prevent-default-in-textfield-expected.txt >new file mode 100644 >index 0000000000000000000000000000000000000000..0661146d9fb67c1cc4544fcfb057d498ba57b1c9 >--- /dev/null >+++ b/LayoutTests/fast/events/before-input-events-prevent-default-in-textfield-expected.txt >@@ -0,0 +1,6 @@ >+PASS successfullyParsed is true >+ >+TEST COMPLETE >+Fired `onbeforeinput`: preventing default! >+The final value is: abc >+ >diff --git a/LayoutTests/fast/events/before-input-events-prevent-default-in-textfield.html b/LayoutTests/fast/events/before-input-events-prevent-default-in-textfield.html >new file mode 100644 >index 0000000000000000000000000000000000000000..c6273bb847674a7c65ed5872b9fe84a741d527b9 >--- /dev/null >+++ b/LayoutTests/fast/events/before-input-events-prevent-default-in-textfield.html >@@ -0,0 +1,50 @@ >+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> >+<html> >+ >+<head> >+ <script src="../../resources/js-test-pre.js"></script> >+ <script> >+ var preventDefaultInputEvents = false; >+ >+ function beginTest() >+ { >+ if (!window.eventSender || !window.internals || !window.testRunner) >+ return; >+ >+ internals.settings.setInputEventsEnabled(true); >+ testRunner.dumpAsText(); >+ let input = document.querySelector("#foo"); >+ input.focus(); >+ >+ eventSender.keyDown("a", []); >+ eventSender.keyDown("b", []); >+ eventSender.keyDown("c", []); >+ >+ preventDefaultInputEvents = true; >+ >+ eventSender.keyDown("delete"); >+ debug(`The final value is: ${input.value}`); >+ } >+ >+ function checkInputEvent(event) >+ { >+ if (preventDefaultInputEvents) >+ debug("FAIL: Did not expect to the `oninput` handler to fire."); >+ } >+ >+ function checkBeforeInputEvent(event) >+ { >+ if (preventDefaultInputEvents) { >+ debug("Fired `onbeforeinput`: preventing default!"); >+ event.preventDefault(); >+ } >+ } >+ </script> >+</head> >+ >+<body onload=beginTest()> >+ <input id="foo" contenteditable value="helloworld" oninput=checkInputEvent(event) onbeforeinput=checkBeforeInputEvent(event)></div> >+ <script src="../../resources/js-test-post.js"></script> >+</body> >+ >+</html> >diff --git a/LayoutTests/fast/events/before-input-events-prevent-default.html b/LayoutTests/fast/events/before-input-events-prevent-default.html >new file mode 100644 >index 0000000000000000000000000000000000000000..6aa60f6d46bff07ff868a33f0113d326cf673fc0 >--- /dev/null >+++ b/LayoutTests/fast/events/before-input-events-prevent-default.html >@@ -0,0 +1,36 @@ >+<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN"> >+<html> >+ >+<head> >+ <script src="../../resources/js-test-pre.js"></script> >+ <script> >+ function beginTest() >+ { >+ if (!window.eventSender || !window.internals || !window.testRunner) >+ return; >+ >+ internals.settings.setInputEventsEnabled(true); >+ testRunner.dumpAsText(); >+ document.querySelector("#foo").focus(); >+ eventSender.keyDown("a", []); >+ } >+ >+ function checkInputEvent(event) >+ { >+ debug("FAIL: Did not expect to the `oninput` handler to fire."); >+ } >+ >+ function checkBeforeInputEvent(event) >+ { >+ debug("Fired `onbeforeinput`: preventing default!"); >+ event.preventDefault(); >+ } >+ </script> >+</head> >+ >+<body onload=beginTest()> >+ <div id="foo" contenteditable oninput=checkInputEvent(event) onbeforeinput=checkBeforeInputEvent(event)></div> >+ <script src="../../resources/js-test-post.js"></script> >+</body> >+ >+</html> >diff --git a/LayoutTests/fast/events/input-events-fired-when-typing-expected.txt b/LayoutTests/fast/events/input-events-fired-when-typing-expected.txt >index 0d63d49f18f9c631003bc69fde6865d37cee1cce..67ba19332f0f8cb944d0f5b7eccefb7d55fc2e40 100644 >--- a/LayoutTests/fast/events/input-events-fired-when-typing-expected.txt >+++ b/LayoutTests/fast/events/input-events-fired-when-typing-expected.txt >@@ -1,12 +1,28 @@ > PASS successfullyParsed is true > > TEST COMPLETE >+Fired `onbeforeinput`! >+PASS event.__lookupGetter__('inputType') is defined. >+PASS Object.getPrototypeOf(event) is InputEvent.prototype >+PASS event.target.id is expectedTargetID >+PASS event.bubbles is true >+PASS event.cancelable is true >+PASS event.composed is true >+Fired `oninput`! > PASS event.__lookupGetter__('inputType') is defined. > PASS Object.getPrototypeOf(event) is InputEvent.prototype > PASS event.target.id is expectedTargetID > PASS event.bubbles is true > PASS event.cancelable is false > PASS event.composed is true >+Fired `onbeforeinput`! >+PASS event.__lookupGetter__('inputType') is defined. >+PASS Object.getPrototypeOf(event) is InputEvent.prototype >+PASS event.target.id is expectedTargetID >+PASS event.bubbles is true >+PASS event.cancelable is true >+PASS event.composed is true >+Fired `oninput`! > PASS event.__lookupGetter__('inputType') is defined. > PASS Object.getPrototypeOf(event) is InputEvent.prototype > PASS event.target.id is expectedTargetID >diff --git a/LayoutTests/fast/events/input-events-fired-when-typing.html b/LayoutTests/fast/events/input-events-fired-when-typing.html >index dd6261c44713ef76f1b117247ff9a516be35d543..b46f6147c4787f25c7bb9fb02a0f716af4b4c18c 100644 >--- a/LayoutTests/fast/events/input-events-fired-when-typing.html >+++ b/LayoutTests/fast/events/input-events-fired-when-typing.html >@@ -33,6 +33,7 @@ > > function checkInputEvent(event) > { >+ debug("Fired `oninput`!"); > shouldBeDefined("event.__lookupGetter__('inputType')"); > shouldBe("Object.getPrototypeOf(event)", "InputEvent.prototype"); > shouldBe("event.target.id", "expectedTargetID"); >@@ -40,12 +41,23 @@ > shouldBe("event.cancelable", "false"); > shouldBe("event.composed", "true"); > } >+ >+ function checkBeforeInputEvent(event) >+ { >+ debug("Fired `onbeforeinput`!"); >+ shouldBeDefined("event.__lookupGetter__('inputType')"); >+ shouldBe("Object.getPrototypeOf(event)", "InputEvent.prototype"); >+ shouldBe("event.target.id", "expectedTargetID"); >+ shouldBe("event.bubbles", "true"); >+ shouldBe("event.cancelable", "true"); >+ shouldBe("event.composed", "true"); >+ } > </script> > </head> > > <body onload=beginTest()> >- <div id="foo" contenteditable oninput=checkInputEvent(event)></div> >- <input id="bar" oninput=checkInputEvent(event)></input> >+ <div id="foo" contenteditable oninput=checkInputEvent(event) onbeforeinput=checkBeforeInputEvent(event)></div> >+ <input id="bar" oninput=checkInputEvent(event) onbeforeinput=checkBeforeInputEvent(event)></input> > <script src="../../resources/js-test-post.js"></script> > </body> > >diff --git a/LayoutTests/platform/ios-simulator/TestExpectations b/LayoutTests/platform/ios-simulator/TestExpectations >index bfc0b91936cbd4b9927afce1550e7a209f3168ac..54b75de6f5627e2469ab811f4fdd97673896032a 100644 >--- a/LayoutTests/platform/ios-simulator/TestExpectations >+++ b/LayoutTests/platform/ios-simulator/TestExpectations >@@ -1198,6 +1198,8 @@ fast/events/frame-tab-focus.html [ Failure ] > fast/events/ime-composition-events-001.html [ Failure ] > fast/events/inputText-never-fired-on-keydown-cancel.html [ Failure ] > fast/events/input-events-fired-when-typing.html [ Failure ] >+fast/events/before-input-events-prevent-default.html [ Failure ] >+fast/events/before-input-events-prevent-default-in-textfield.html [ Failure ] > fast/events/key-events-in-input-button.html [ Failure ] > fast/events/keydown-1.html [ Failure ] > fast/events/keydown-leftright-keys.html [ Failure ]
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Formatted Diff
|
Diff
Attachments on
bug 163021
:
290826
|
290833
|
290835
|
290836
|
290838
|
290858
| 290983