Commit 448a8f78 authored by Anupam Snigdha's avatar Anupam Snigdha Committed by Chromium LUCI CQ

Fix candidate window positioning during composition.

This patch fixes a bug where the text input state updates are not
being sent to IME when control bounds change due to the change in
active element's position.

Bug: 1151301

Change-Id: I7d1bf8a26bd43e49ffb480e1900ed257ecd6bba1
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2570081
Commit-Queue: Anupam Snigdha <snianu@microsoft.com>
Reviewed-by: default avatardanakj <danakj@chromium.org>
Reviewed-by: default avatarDavid Bokan <bokan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#833562}
parent 0b7367ff
......@@ -1689,14 +1689,12 @@ TEST_F(RenderViewImplTextInputStateChanged,
TEST_F(RenderViewImplTextInputStateChanged, ActiveElementGetLayoutBounds) {
// Load an HTML page consisting of one input fields.
LoadHTML(
"<html>"
"<head>"
"</head>"
"<body>"
"<input id=\"test\" type=\"text\"></input>"
"</body>"
"</html>");
LoadHTML(R"HTML(
<style>
input { position: fixed; }
</style>
<input id='test' type='text'></input>
)HTML");
ClearState();
// Create an EditContext with control and selection bounds and set input
// panel policy to auto.
......@@ -1722,6 +1720,82 @@ TEST_F(RenderViewImplTextInputStateChanged, ActiveElementGetLayoutBounds) {
updated_states()[0]->edit_context_control_bounds.value());
EXPECT_EQ(actual_active_element_control_bounds,
expected_control_bounds_in_dips);
// Update the position of the element and that should trigger control bounds
// update to IME.
ExecuteJavaScriptForTests(
"document.getElementById('test').style.top = 50 + "
"\"px\";document.getElementById('test').style.left = 350 + \"px\";");
// This RunLoop is waiting for styles to be processed for the active element.
base::RunLoop run_loop2;
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
run_loop2.QuitClosure());
run_loop2.Run();
// Update the IME status and verify if our IME backend sends an IPC message
// to notify layout bounds of the EditContext.
main_frame_widget()->UpdateTextInputState();
// This RunLoop is to flush the TextInputState update message.
base::RunLoop run_loop3;
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
run_loop3.QuitClosure());
run_loop3.Run();
EXPECT_EQ(2u, updated_states().size());
controller->GetLayoutBounds(&expected_control_bounds, &temp_selection_bounds);
gfx::Rect expected_control_bounds_in_dips_updated =
main_frame_widget()->BlinkSpaceToEnclosedDIPs(expected_control_bounds);
actual_active_element_control_bounds =
updated_states()[1]->edit_context_control_bounds.value();
EXPECT_EQ(actual_active_element_control_bounds,
expected_control_bounds_in_dips_updated);
// Also check that the updated bounds are different from last reported bounds.
EXPECT_NE(expected_control_bounds_in_dips_updated,
expected_control_bounds_in_dips);
}
TEST_F(RenderViewImplTextInputStateChanged,
ActiveElementMultipleLayoutBoundsUpdates) {
// Load an HTML page consisting of one input fields.
LoadHTML(R"HTML(
<input id='test' type='text'></input>
)HTML");
ClearState();
// Create an EditContext with control and selection bounds and set input
// panel policy to auto.
ExecuteJavaScriptForTests("document.getElementById('test').focus();");
// This RunLoop is waiting for focus to be processed for the active element.
base::RunLoop run_loop;
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
run_loop.QuitClosure());
run_loop.Run();
// Update the IME status and verify if our IME backend sends an IPC message
// to notify layout bounds of the EditContext.
main_frame_widget()->UpdateTextInputState();
// This RunLoop is to flush the TextInputState update message.
base::RunLoop run_loop2;
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
run_loop2.QuitClosure());
run_loop2.Run();
EXPECT_EQ(1u, updated_states().size());
blink::WebInputMethodController* controller =
frame()->GetWebFrame()->GetInputMethodController();
blink::WebRect expected_control_bounds;
blink::WebRect temp_selection_bounds;
controller->GetLayoutBounds(&expected_control_bounds, &temp_selection_bounds);
gfx::Rect expected_control_bounds_in_dips =
main_frame_widget()->BlinkSpaceToEnclosedDIPs(expected_control_bounds);
gfx::Rect actual_active_element_control_bounds(
updated_states()[0]->edit_context_control_bounds.value());
EXPECT_EQ(actual_active_element_control_bounds,
expected_control_bounds_in_dips);
// No updates in control bounds so this shouldn't trigger an update to IME.
main_frame_widget()->UpdateTextInputState();
// This RunLoop is to flush the TextInputState update message.
base::RunLoop run_loop3;
base::ThreadTaskRunnerHandle::Get()->PostTask(FROM_HERE,
run_loop3.QuitClosure());
run_loop3.Run();
EXPECT_EQ(1u, updated_states().size());
}
TEST_F(RenderViewImplTextInputStateChanged, VirtualKeyboardPolicyAuto) {
......
......@@ -854,6 +854,8 @@ void WidgetBase::UpdateTextInputStateInternal(bool show_virtual_keyboard,
ui::mojom::VirtualKeyboardVisibilityRequest last_vk_visibility_request =
ui::mojom::VirtualKeyboardVisibilityRequest::NONE;
bool always_hide_ime = false;
base::Optional<gfx::Rect> control_bounds;
base::Optional<gfx::Rect> selection_bounds;
if (frame_widget) {
new_info = frame_widget->TextInputInfo();
// This will be used to decide whether or not to show VK when VK policy is
......@@ -864,6 +866,8 @@ void WidgetBase::UpdateTextInputStateInternal(bool show_virtual_keyboard,
// Check whether the keyboard should always be hidden for the currently
// focused element.
always_hide_ime = frame_widget->ShouldSuppressKeyboardForFocusedElement();
frame_widget->GetEditContextBoundsInWindow(&control_bounds,
&selection_bounds);
}
const ui::TextInputMode new_mode =
ConvertWebTextInputMode(new_info.input_mode);
......@@ -880,7 +884,9 @@ void WidgetBase::UpdateTextInputStateInternal(bool show_virtual_keyboard,
always_hide_ime_ != always_hide_ime || vk_policy_ != new_vk_policy ||
(new_vk_policy == ui::mojom::VirtualKeyboardPolicy::MANUAL &&
(last_vk_visibility_request !=
ui::mojom::VirtualKeyboardVisibilityRequest::NONE))) {
ui::mojom::VirtualKeyboardVisibilityRequest::NONE)) ||
(control_bounds && frame_control_bounds_ != control_bounds) ||
(selection_bounds && frame_selection_bounds_ != selection_bounds)) {
ui::mojom::blink::TextInputStatePtr params =
ui::mojom::blink::TextInputState::New();
params->type = new_type;
......@@ -889,15 +895,13 @@ void WidgetBase::UpdateTextInputStateInternal(bool show_virtual_keyboard,
params->flags = new_info.flags;
params->vk_policy = new_vk_policy;
params->last_vk_visibility_request = last_vk_visibility_request;
params->edit_context_control_bounds = control_bounds;
params->edit_context_selection_bounds = selection_bounds;
if (!new_info.ime_text_spans.empty()) {
params->ime_text_spans_info =
frame_widget->GetImeTextSpansInfo(new_info.ime_text_spans);
}
if (frame_widget) {
frame_widget->GetEditContextBoundsInWindow(
&params->edit_context_control_bounds,
&params->edit_context_selection_bounds);
}
#if defined(OS_ANDROID)
if (next_previous_flags_ == kInvalidNextPreviousFlagsValue) {
// Due to a focus change, values will be reset by the frame.
......@@ -939,6 +943,10 @@ void WidgetBase::UpdateTextInputStateInternal(bool show_virtual_keyboard,
can_compose_inline_ = new_can_compose_inline;
always_hide_ime_ = always_hide_ime;
text_input_flags_ = new_info.flags;
frame_control_bounds_ = control_bounds.value_or(gfx::Rect());
// Selection bounds are not populated in non-EditContext scenarios.
// It is communicated to IMEs via |WidgetBase::UpdateSelectionBounds|.
frame_selection_bounds_ = selection_bounds.value_or(gfx::Rect());
// Reset the show/hide state in the InputMethodController.
if (frame_widget) {
if (last_vk_visibility_request !=
......
......@@ -405,6 +405,13 @@ class PLATFORM_EXPORT WidgetBase : public mojom::blink::Widget,
ui::mojom::VirtualKeyboardPolicy vk_policy_ =
ui::mojom::VirtualKeyboardPolicy::AUTO;
// Stores the current control and selection bounds of |webwidget_|
// that are used to position the candidate window during IME composition.
// These are stored in DIPs if use-zoom-for-dsf is disabled and are relative
// to the widget
gfx::Rect frame_control_bounds_;
gfx::Rect frame_selection_bounds_;
// Stores the current text input flags of |webwidget_|.
int text_input_flags_ = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment