Bug 218148

Summary: using input method in the preedit mode , if the cursor not in the last letter , webkit2gtk report the wrong location
Product: WebKit Reporter: YanVV <yanwh0311>
Component: WebKitGTKAssignee: Nobody <webkit-unassigned>
Status: NEW ---    
Severity: Normal CC: bugs-noreply, taoky99, webkit-bug-importer
Priority: P2    
Version: Other   
Hardware: PC   
OS: Linux   
Attachments:
Description Flags
input window could not follow the cursor
none
gdb `thread apply all bt full` on webkitInputMethodContextImplGtkNotifyCursorArea breakpoint none

Description YanVV 2020-10-23 23:23:46 PDT
Created attachment 412235 [details]
input window could not follow the cursor

When using input method such as fcitx , input window could not follow the cursor.
Comment 1 YanVV 2021-07-31 19:44:40 PDT
By default ibus use preedit mode , the cursor is at the last letter,but if one press the left arrow while it show the candidate, and continue input something, the candidate not follow the cursor.
Comment 2 Keyu Tao 2024-04-10 10:07:18 PDT
This bug still exists in WebKit today, tested with following configurations:
- GNOME Wayland and Xorg, Epiphany (Stable and Technology Preview, from Flatpak), iBus in Fedora 40.
- GNOME Wayland, Epiphany Stable from Flatpak, Fcitx5 in Arch Linux
- GNOME Flashback (Metacity), Suckless Surf (Gtk3), iBus. Fedora 40 with webkit2gtk4.0

With debug symbol and gdb attached, this looks like that `webkitInputMethodContextImplGtkNotifyCursorArea()` in `Source/WebKit/UIProcess/API/gtk/WebKitInputMethodContextImplGtk.cpp` gets incorrect x, y, width and height all as 0 for popup after it gets correct value the first time:

```
Thread 1 "surf" hit Breakpoint 1, webkitInputMethodContextImplGtkNotifyCursorArea (context=0x19fd780 [WebKitInputMethodContextImplGtk], x=502, y=353, 
    width=1, height=22) at /usr/src/debug/webkit2gtk4.0-2.42.5-1.fc40.x86_64/Source/WebKit/UIProcess/API/gtk/WebKitInputMethodContextImplGtk.cpp:194
194	{
(gdb) c
Continuing.

Thread 1 "surf" hit Breakpoint 1, webkitInputMethodContextImplGtkNotifyCursorArea (context=0x19fd780 [WebKitInputMethodContextImplGtk], x=0, y=0, 
    width=0, height=0) at /usr/src/debug/webkit2gtk4.0-2.42.5-1.fc40.x86_64/Source/WebKit/UIProcess/API/gtk/WebKitInputMethodContextImplGtk.cpp:194
194	{
(gdb) c
Continuing.
```

And when input method is not using preedit mode, this function could always get correct value.
Comment 3 Keyu Tao 2024-04-10 13:19:56 PDT
Created attachment 470853 [details]
gdb `thread apply all bt full` on webkitInputMethodContextImplGtkNotifyCursorArea breakpoint

I didn't compile latest webkitgtk successfully so now what I could get `bt full` from is 2.42.5 from Fedora 40. But considering that this bug is reproducible with Arch[^1] + Epiphany and Fedora 40 + Epiphany Technology Preview, it seems that this issue still exists in 2.44.0.

[^1]: I tried installing webkitgtk-6.0-debug on Arch but it does not contain source code and no variable in `bt full` output. Its backtrace looks alike the 2.42.5 one.
Comment 4 Keyu Tao 2024-04-13 10:24:57 PDT
After a success build locally with git main branch webkitgtk, and a lot of `printf()` manually added and running with MiniBrowser, the reason for the Gtk cursor update function getting empty rect in IM preedit mode is that:

1. In `FrameSelection::recomputeCaretRect()`, `clearCaretRect()` makes it empty, as `m_selection` is a Type::Range (isNonOrphanedCaret returns false).

2. `frame.selection().absoluteCaretBounds()` in `WebPage::getPlatformEditorState()` (glib) gets that empty rect and gives it to 

3. `WebPage::sendEditorStateUpdate` => `WebPage::editorState()` => `getPlatformEditorState()`

4. `sendEditorStateUpdate` sends IPC msg (Messages::WebPageProxy::EditorStateChanged(state)), with the empty rect.

5. It gets to `WebPageProxy::editorStateChanged` => `WebPageProxy::updateEditorState` => `WebPageProxy::didUpdateEditorState` => `PageClientImpl::selectionDidChange()` => `webkitWebViewBaseUpdateTextInputState()` => `webkitWebViewBase->priv->inputMethodFilter.notifyCursorRect()` = `InputMethodFilter::notifyCursorRect` (glib) => `webkit_input_method_context_notify_cursor_area` => `imClass->notify_cursor_area` => `webkitInputMethodContextImplGtkNotifyCursorArea()` => `gtk_im_context_set_cursor_location()`.

Looks like the most naive workaround is to check if the rect is empty (x, y, width and height are all 0) in webkit_input_method_context_notify_cursor_area, and if so, just don't notify cursor area. However, unfortunately I could not get the flatpak WebKit SDK working on my computer so I guess I would not submit this as a patch in recent. It would be very appreciated if anyone could help validate this (or find a better solution).