From 3349026fb3a4656f48910ca38cd6c30cce8d19d4 Mon Sep 17 00:00:00 2001 From: "Michael[tm] Smith" Date: Sun, 26 May 2024 15:52:40 +0900 Subject: [PATCH] The beforeinput event should fire before textInput https://bugs.webkit.org/show_bug.cgi?id=268988 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Reviewed by NOBODY (OOPS!). This change (controlled by the ConformantBeforeinputEventFiringOrderEnabled, preference, also introduced in this change) makes WebKit fire the beforeinput and textInput events in the order: beforeinput first, textInput after — conforming to the requirements at https://github.com/w3c/uievents/pull/362 and https://w3c.github.io/uievents/event-algo.html#fire%20key%20input%20events and consistent with the order in which the events are fired in Blink. Otherwise, without this change, WebKit fires the events in the order: textInput first, beforeinput after — which breaks conformance with the spec requirements, and breaks compatibility with Blink. Note also that this change makes WebKit conform to the requirements in https://w3c.github.io/uievents/event-algo.html#fire%20key%20input%20events, https://w3c.github.io/uievents/event-algo.html#handle%20native%20paste, and https://w3c.github.io/uievents/event-algo.html#end%20composition — limiting textInput to being fired only when ending a composition or when the input type is insertText, insertParagraph, insertLineBreak, or insertFromPaste. * LayoutTests/editing/execCommand/break-out-of-empty-list-item.html: * LayoutTests/editing/inserting/typing-space-to-trigger-smart-link.html: * LayoutTests/editing/pasteboard/paste-text-events-expected.txt: * LayoutTests/editing/pasteboard/paste-text-events.html: * LayoutTests/editing/style/highlight-insert-paragraph.html: * LayoutTests/fast/events/input-events-fired-when-typing-expected.txt: * LayoutTests/fast/events/input-events-fired-when-typing-nonconforming-expected.txt: Copied from LayoutTests/fast/events/input-events-fired-when-typing-expected.txt. * LayoutTests/fast/events/input-events-fired-when-typing-nonconforming.html: Copied from LayoutTests/fast/events/input-events-fired-when-typing.html. * LayoutTests/fast/events/input-events-fired-when-typing.html: * LayoutTests/fast/events/ios/submit-form-target-blank-using-return-key-old-code-path-expected.txt: Added. * LayoutTests/fast/events/ios/submit-form-target-blank-using-return-key-old-code-path.html: Added. * LayoutTests/fast/forms/onchange-change-type.html: * LayoutTests/http/tests/navigation/keyboard-events-during-provisional-navigation-expected.txt: * LayoutTests/http/tests/navigation/keyboard-events-during-provisional-subframe-navigation-expected.txt: * LayoutTests/platform/ios/TestExpectations: * LayoutTests/platform/mac-wk2/http/tests/navigation/keyboard-events-during-provisional-navigation-expected.txt: * Source/WTF/Scripts/Preferences/UnifiedWebPreferences.yaml: * Source/WebCore/editing/AlternativeTextController.cpp: (WebCore::AlternativeTextController::insertDictatedText): * Source/WebCore/editing/Editor.cpp: (WebCore::dispatchTextInputEvent): (WebCore::Editor::selectionForCommand): (WebCore::Editor::handleTextEvent): (WebCore::Editor::pasteAsPlainText): (WebCore::Editor::pasteAsFragment): (WebCore::dispatchTextInputEvents): (WebCore::Editor::appliedEditing): (WebCore::Editor::insertText): (WebCore::Editor::insertTextForConfirmedComposition): (WebCore::Editor::insertTextWithoutSendingTextEventNew): (WebCore::Editor::insertTextWithoutSendingTextEventOld): (WebCore::Editor::setComposition): (WebCore::Editor::insertTextWithoutSendingTextEvent): Deleted. * Source/WebCore/editing/Editor.h: * Source/WebCore/editing/EditorCommand.cpp: (WebCore::executeInsertBacktab): (WebCore::executeInsertLineBreak): (WebCore::executeInsertNewline): (WebCore::executeInsertTab): (WebCore::executeYank): (WebCore::executeYankAndSelect): (WebCore::enabledVisibleSelection): (WebCore::enabledVisibleSelectionAndMark): (WebCore::enableCaretInEditableText): (WebCore::enabledInEditableText): * Source/WebCore/html/HTMLInputElement.cpp: (WebCore::HTMLInputElement::defaultEventHandler): * Source/WebCore/page/EventHandler.cpp: (WebCore::EventHandler::handleTextInput): * Source/WebCore/page/EventHandler.h: --- .../break-out-of-empty-list-item.html | 17 +-- .../typing-space-to-trigger-smart-link.html | 39 ++--- .../pasteboard/paste-text-events-expected.txt | 13 -- .../editing/pasteboard/paste-text-events.html | 18 --- .../style/highlight-insert-paragraph.html | 18 +-- ...nput-events-fired-when-typing-expected.txt | 41 ++++++ ...red-when-typing-nonconforming-expected.txt | 86 +++++++++++ ...vents-fired-when-typing-nonconforming.html | 99 +++++++++++++ .../input-events-fired-when-typing.html | 36 ++++- ...sing-return-key-old-code-path-expected.txt | 10 ++ ...-blank-using-return-key-old-code-path.html | 51 +++++++ .../fast/forms/onchange-change-type.html | 10 +- ...during-provisional-navigation-expected.txt | 4 +- ...ovisional-subframe-navigation-expected.txt | 7 +- LayoutTests/platform/ios/TestExpectations | 1 + ...during-provisional-navigation-expected.txt | 7 +- .../Preferences/UnifiedWebPreferences.yaml | 14 ++ .../editing/AlternativeTextController.cpp | 2 + Source/WebCore/editing/Editor.cpp | 137 ++++++++++++++++-- Source/WebCore/editing/Editor.h | 4 +- Source/WebCore/editing/EditorCommand.cpp | 28 +++- Source/WebCore/html/HTMLInputElement.cpp | 6 +- Source/WebCore/page/EventHandler.cpp | 46 ++++++ Source/WebCore/page/EventHandler.h | 2 + 24 files changed, 568 insertions(+), 128 deletions(-) create mode 100644 LayoutTests/fast/events/input-events-fired-when-typing-nonconforming-expected.txt create mode 100644 LayoutTests/fast/events/input-events-fired-when-typing-nonconforming.html create mode 100644 LayoutTests/fast/events/ios/submit-form-target-blank-using-return-key-old-code-path-expected.txt create mode 100644 LayoutTests/fast/events/ios/submit-form-target-blank-using-return-key-old-code-path.html diff --git a/LayoutTests/editing/execCommand/break-out-of-empty-list-item.html b/LayoutTests/editing/execCommand/break-out-of-empty-list-item.html index ca720207830df..babab38d3fbc2 100644 --- a/LayoutTests/editing/execCommand/break-out-of-empty-list-item.html +++ b/LayoutTests/editing/execCommand/break-out-of-empty-list-item.html @@ -11,20 +11,6 @@ testContainer.contentEditable = true; document.body.appendChild(testContainer); -function pressKey(key) -{ - if (window.KeyEvent) { - var ev = document.createEvent("KeyboardEvent"); - ev.initKeyEvent("keypress", true, true, window, 0,0,0,0, 0, key.charCodeAt(0)); - document.body.dispatchEvent(ev); - } - else { - var ev = document.createEvent("TextEvent"); - ev.initTextEvent('textInput', true, true, null, key.charAt(0)); - document.body.dispatchEvent(ev); - } -} - function enterAtTarget(initialContent) { testContainer.innerHTML = initialContent; @@ -39,8 +25,7 @@ s.removeAllRanges(); s.addRange(r); - pressKey('\n'); - + document.execCommand("InsertParagraph"); return testContainer.innerHTML; } diff --git a/LayoutTests/editing/inserting/typing-space-to-trigger-smart-link.html b/LayoutTests/editing/inserting/typing-space-to-trigger-smart-link.html index e9ae04dc2107f..b3c2037c6054a 100644 --- a/LayoutTests/editing/inserting/typing-space-to-trigger-smart-link.html +++ b/LayoutTests/editing/inserting/typing-space-to-trigger-smart-link.html @@ -12,7 +12,7 @@ var testTypeSpaceDiv = document.getElementById('testTypeSpace'); var targetText = testTypeSpaceDiv.firstChild; window.getSelection().setPosition(targetText, 15); - pressKey(" "); + document.execCommand("InsertText", false, " "); var expectedContents = "The www.foo.com should be underlined and there is an anchor node created for it."; if (expectedContents == testTypeSpaceDiv.innerHTML) document.getElementById('log').textContent = "PASS: the anchor for 'www.foo.com' has been created.\n" @@ -22,18 +22,18 @@ var testTypeLinkDiv = document.getElementById('testTypeLink'); targetText = testTypeLinkDiv.firstChild; window.getSelection().setPosition(targetText, 4); - pressKey("w"); - pressKey("w"); - pressKey("w"); - pressKey("."); - pressKey("b"); - pressKey("a"); - pressKey("r"); - pressKey("."); - pressKey("c"); - pressKey("o"); - pressKey("m"); - pressKey(" "); + document.execCommand("InsertText", false, "w"); + document.execCommand("InsertText", false, "w"); + document.execCommand("InsertText", false, "w"); + document.execCommand("InsertText", false, "."); + document.execCommand("InsertText", false, "b"); + document.execCommand("InsertText", false, "a"); + document.execCommand("InsertText", false, "r"); + document.execCommand("InsertText", false, "."); + document.execCommand("InsertText", false, "c"); + document.execCommand("InsertText", false, "o"); + document.execCommand("InsertText", false, "m"); + document.execCommand("InsertText", false, " "); expectedContents = "The www.bar.com should be underlined and there is an anchor node created for it."; if (expectedContents == testTypeLinkDiv.innerHTML) document.getElementById('log').textContent += "PASS: the anchor for 'www.bar.com' has been created." @@ -43,19 +43,6 @@ if (window.internals) internals.setAutomaticLinkDetectionEnabled(false); } - -function pressKey(key) -{ - if (window.KeyEvent) { - var ev = document.createEvent("KeyboardEvent"); - ev.initKeyEvent("keypress", true, true, window, 0,0,0,0, 0, key.charCodeAt(0)); - document.body.dispatchEvent(ev); - } else { - var ev = document.createEvent("TextEvent"); - ev.initTextEvent('textInput', true, true, null, key.charAt(0)); - document.body.dispatchEvent(ev); - } -} diff --git a/LayoutTests/editing/pasteboard/paste-text-events-expected.txt b/LayoutTests/editing/pasteboard/paste-text-events-expected.txt index c81e8e202da92..39e3371132b4f 100644 --- a/LayoutTests/editing/pasteboard/paste-text-events-expected.txt +++ b/LayoutTests/editing/pasteboard/paste-text-events-expected.txt @@ -16,19 +16,6 @@ PASS testTargetInput.value is 'RichHello' PASS event.data is '' PASS testTargetEditable.innerHTML is 'RichHello' PASS textInputCount is proceedingTestCases.length -PASS event.data is 'PlainHello' -PASS testTargetTextarea.value is '' -PASS event.data is 'PlainHello' -PASS testTargetInput.value is '' -PASS event.data is '' -PASS testTargetEditable.innerHTML is '' -PASS event.data is 'RichHello' -PASS testTargetTextarea.value is '' -PASS event.data is 'RichHello' -PASS testTargetInput.value is '' -PASS event.data is '' -PASS testTargetEditable.innerHTML is '' -PASS textInputCount is cancelingTestCases.length PASS successfullyParsed is true TEST COMPLETE diff --git a/LayoutTests/editing/pasteboard/paste-text-events.html b/LayoutTests/editing/pasteboard/paste-text-events.html index b1b375db35af1..694013d344c13 100644 --- a/LayoutTests/editing/pasteboard/paste-text-events.html +++ b/LayoutTests/editing/pasteboard/paste-text-events.html @@ -22,8 +22,6 @@ { shouldBe("event.data", toStringLiteral(expectedTextEventData)); textInputCount++; - if (willCancelTextInput) - evt.preventDefault(); } var testSourceRoot = document.createElement("div"); @@ -112,15 +110,6 @@ [copyRichText, pasteToTargetEditable, targetEditableShouldHave, "RichHello", ""], ]; -var cancelingTestCases = [ - [copyPlainText, pasteToTargetTextarea, targetTextareaShouldHave, "", "PlainHello"], - [copyPlainText, pasteToTargetInput, targetInputShouldHave, "", "PlainHello"], - [copyPlainText, pasteToTargetEditable, targetEditableShouldHave, "", ""], - [copyRichText, pasteToTargetTextarea, targetTextareaShouldHave, "", "RichHello"], - [copyRichText, pasteToTargetInput, targetInputShouldHave, "", "RichHello"], - [copyRichText, pasteToTargetEditable, targetEditableShouldHave, "", ""], -]; - function runSingleTest(caseData) { var copy = caseData[0]; @@ -136,17 +125,10 @@ } textInputCount = 0; -willCancelTextInput = false; for (var i = 0; i < proceedingTestCases.length; ++i) runSingleTest(proceedingTestCases[i]); shouldBe("textInputCount", "proceedingTestCases.length"); -textInputCount = 0; -willCancelTextInput = true; -for (var i = 0; i < cancelingTestCases.length; ++i) - runSingleTest(cancelingTestCases[i]); -shouldBe("textInputCount", "cancelingTestCases.length"); - // Hides dataset to make dump clean. testTargetRoot.style.display = "none"; testSourceRoot.style.display = "none"; diff --git a/LayoutTests/editing/style/highlight-insert-paragraph.html b/LayoutTests/editing/style/highlight-insert-paragraph.html index e9c0ca01811b5..4174d9deb9e88 100644 --- a/LayoutTests/editing/style/highlight-insert-paragraph.html +++ b/LayoutTests/editing/style/highlight-insert-paragraph.html @@ -9,20 +9,6 @@
+ + + + +
+ + + + + + + diff --git a/LayoutTests/fast/events/input-events-fired-when-typing.html b/LayoutTests/fast/events/input-events-fired-when-typing.html index 114e97f4557f5..6441cbd2f69a5 100644 --- a/LayoutTests/fast/events/input-events-fired-when-typing.html +++ b/LayoutTests/fast/events/input-events-fired-when-typing.html @@ -1,4 +1,4 @@ - + @@ -11,23 +11,36 @@ return document.querySelector("#foo"); } - function plainText() + function inputElement() { return document.querySelector("#bar"); } + function textareaElement() + { + return document.querySelector("#baz"); + } + function beginTest() { if (!window.eventSender || !window.internals || !window.testRunner) return; testRunner.dumpAsText(); + + debug("Typing into contenteditable div element"); contentEditable().focus(); eventSender.keyDown("a", []); + debug("Typing into input element"); expectedTargetID = "bar"; - plainText().focus(); + inputElement().focus(); eventSender.keyDown("b", []); + + debug("Typing into textarea element"); + expectedTargetID = "baz"; + textareaElement().focus(); + eventSender.keyDown("c", []); } function checkInputEvent(event) @@ -57,12 +70,29 @@ shouldBe("event.composed", "true"); shouldBe("event.isComposing", "false"); } + + function checkTextInputEvent(event) + { + debug("Fired `textInput`!"); + shouldBeDefined("event.__lookupGetter__('data')"); + shouldBe("event.target.id", "expectedTargetID"); + shouldBe("event.bubbles", "true"); + shouldBe("event.cancelable", "true"); + shouldBe("event.composed", "true"); + } +
+ + diff --git a/LayoutTests/fast/events/ios/submit-form-target-blank-using-return-key-old-code-path-expected.txt b/LayoutTests/fast/events/ios/submit-form-target-blank-using-return-key-old-code-path-expected.txt new file mode 100644 index 0000000000000..18183b82100ee --- /dev/null +++ b/LayoutTests/fast/events/ios/submit-form-target-blank-using-return-key-old-code-path-expected.txt @@ -0,0 +1,10 @@ +Tests that pressing the Return key in a text field with an associated form implicitly submits the form. To run this test by hand, focus the text field below and press the Return key. + +On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE". + + +PASS event.key is "Enter" +PASS successfullyParsed is true + +TEST COMPLETE + diff --git a/LayoutTests/fast/events/ios/submit-form-target-blank-using-return-key-old-code-path.html b/LayoutTests/fast/events/ios/submit-form-target-blank-using-return-key-old-code-path.html new file mode 100644 index 0000000000000..cc81158322180 --- /dev/null +++ b/LayoutTests/fast/events/ios/submit-form-target-blank-using-return-key-old-code-path.html @@ -0,0 +1,51 @@ + + + + + + + +

+
+ +
+
+ + + diff --git a/LayoutTests/fast/forms/onchange-change-type.html b/LayoutTests/fast/forms/onchange-change-type.html index 27eb1590a05de..42f706a42d71b 100644 --- a/LayoutTests/fast/forms/onchange-change-type.html +++ b/LayoutTests/fast/forms/onchange-change-type.html @@ -2,12 +2,6 @@