Branch: refs/heads/main
Home: https://github.com/WebKit/WebKit
Commit: 2e47ba3f800b7e2edbdb24cce348bfd086c8ef2e
https://github.com/WebKit/WebKit/commit/2e47ba3f800b7e2edbdb24cce348bfd086c8ef2e
Author: Ryosuke Niwa <[email protected]>
Date: 2026-05-23 (Sat, 23 May 2026)
Changed paths:
M Source/WebCore/editing/Editor.cpp
M Tools/Scripts/webkitpy/api_tests/allowlist.txt
M Tools/TestWebKitAPI/Tests/WebKit/WKWebView/mac/WKWebViewMacEditingTests.mm
Log Message:
-----------
REGRESSION(310113@main): On ChatGPT, typing a long text in Japanese IM
results in a partially confirmed composition to be displaced after the caret
https://bugs.webkit.org/show_bug.cgi?id=315419
rdar://177691343
Reviewed by Wenson Hsieh.
Editor::setComposition dispatches compositionstart/compositionupdate to JS,
then calls
TypingCommand::insertText to install the marked text — without flushing layout
in between.
If the JS handler mutates the DOM around the caret (any insertion/removal that
touches
the selected text node), two things could go wrong together:
1. The selection's start position can end up parent-anchored on a non-text
container
(e.g. <p>:1) instead of inside a text node either because the JS
explicitly set
a Selection range, or because FrameSelection::nodeWillBeRemoved
auto-adjusted the
position via setWithoutValidation (which bypasses canonicalPosition, the
one place
that would have flushed layout).
2. Any text nodes the handler added are in the DOM but may not have a
RenderText yet
as render-tree attachment only happens in the next layout.
When TypingCommand::insertText then runs, Position::upstream() walks from <p>:1
looking
for a text-node candidate. It reaches the pending text node, but at
Position.cpp:728 it
sees renderer() is null and continues past it. It falls back to <p>:0, and
positionInsideTextNode creates a new text node there. The marked text is
installed into
that fresh node, ending up on the wrong side of the existing text.
The ProseMirror-specific insertBefore + removeChild sequence is one way to land
in this
state, but it's not what the bug is about. It's about setComposition proceeding
to
TypingCommand::insertText while the render tree is stale relative to the DOM
the JS
handler just produced.
This PR fixes the issue by forcing a layout flush in Editor::setComposition
after the
composition events fire and before TypingCommand::insertText. This attaches the
pending
renderers and Position::upstream() can walk into the new text nodes and resolve
the start
position correctly.
Co-authored with Claude and Simon Fraser.
Test:
TestWebKitAPI.WKWebViewMacEditingTests.JapaneseAutoCommitWithDOMRebuildInCompositionStartLandsTextAtCursor
* Source/WebCore/editing/Editor.cpp:
(WebCore::Editor::setComposition):
* Tools/Scripts/webkitpy/api_tests/allowlist.txt:
* Tools/TestWebKitAPI/Tests/WebKit/WKWebView/mac/WKWebViewMacEditingTests.mm:
(TestWebKitAPI::TEST(WKWebViewMacEditingTests,
JapaneseAutoCommitWithDOMRebuildInCompositionStartLandsTextAtCursor)):
Canonical link: https://commits.webkit.org/313806@main
To unsubscribe from these emails, change your notification settings at
https://github.com/WebKit/WebKit/settings/notifications