Bug 327694
| Summary: | [GTK][WPE] Input method delete-surrounding can be applied before text committed just before it | ||
|---|---|---|---|
| Product: | WebKit | Reporter: | Simon Pena <spena> |
| Component: | WPE WebKit | Assignee: | Nobody <webkit-unassigned> |
| Status: | NEW | ||
| Severity: | Normal | CC: | aperez, bugs-noreply, cgarcia, fujii |
| Priority: | P2 | ||
| Version: | WebKit Nightly Build | ||
| Hardware: | Unspecified | ||
| OS: | Unspecified | ||
| See Also: |
https://bugs.webkit.org/show_bug.cgi?id=327412 https://bugs.webkit.org/show_bug.cgi?id=327413 |
||
Simon Pena
When an input method commits text and then deletes surrounding text with no gap in between, WebKit can apply the delete first.
Commits are turned into synthesized key presses (webkitWebViewConfirmComposition()), so they wait in the key event queue until the previous key event has been handled by the web process. Delete-surrounding is sent to the web process right away (webkitWebViewDeleteSurrounding()). So a delete can overtake a commit that is still queued.
For example, in an empty textarea: commit "x", commit "y", delete-surrounding (-1, 1). The expected result is "x". The page gets the edits as insert "x", delete, insert "y", and the result is "y".
This can happen with a keyboard that replaces text quickly, for example deleting part of a word and committing a suggestion while the previous commit has not been handled yet.
The API test below reproduces it on WPE, 10 runs out of 10 (Release build, 323811@main plus unrelated local changes). GTK goes through the same path (webkitWebViewBaseSynthesizeCompositionKeyPress() calls WebPageProxy::handleKeyboardEvent()), but I did not run the test there:
static void testWebKitInputMethodContextCommitThenDeleteSurrounding(InputMethodTest* test, gconstpointer)
{
test->loadHtml(testHTML, nullptr);
test->waitUntilLoadFinished();
test->focusEditableAndWaitUntilInputMethodEnabled();
test->runJavaScriptAndWaitUntilFinished("window.inputEvents = [];"
"input.addEventListener('input', event => inputEvents.push(event.inputType + ':' + input.value));", nullptr);
g_signal_emit_by_name(test->m_context.get(), "committed", "x", nullptr);
g_signal_emit_by_name(test->m_context.get(), "committed", "y", nullptr);
test->deleteSurrounding(-1, 1);
test->assertJavaScriptBecomesTrue("inputEvents.filter(event => event.startsWith('insertText:')).length === 2");
auto editableValue = test->editableValue();
g_assert_cmpstr(editableValue.get(), ==, "x");
}
Result:
input events: ["insertText:x","deleteContent:","insertText:y"]
assertion failed (editableValue.get() == "x"): ("y" == "x")
| Attachments | ||
|---|---|---|
| Add attachment proposed patch, testcase, etc. |