Commit 591bdd0d authored by James Cook's avatar James Cook Committed by Commit Bot

Fix text caret visibility after screen rotation on SingleProcessMash

There can be a race between the browser receiving window bounds updates
and the IME ensuring the text caret is visible.

* Repeat the text caret visibility request after virtual keyboard
  occluded bounds update. This is a no-op if the caret is already
  visible.
* Fix double-conversion of local bounds to screen bounds in chrome's
  receipt of occluded bounds from ash.
* Clarify variable names with coordinate system.

Bug: 937722

Change-Id: I0f49413ca63582469cf0a4b61cde69733c1841ab
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1504150Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Reviewed-by: default avatarDarren Shen <shend@chromium.org>
Commit-Queue: James Cook <jamescook@chromium.org>
Cr-Commit-Position: refs/heads/master@{#638308}
parent f1092ff4
...@@ -80,10 +80,9 @@ void AshKeyboardController::DestroyVirtualKeyboard() { ...@@ -80,10 +80,9 @@ void AshKeyboardController::DestroyVirtualKeyboard() {
} }
void AshKeyboardController::SendOnKeyboardVisibleBoundsChanged( void AshKeyboardController::SendOnKeyboardVisibleBoundsChanged(
const gfx::Rect& bounds) { const gfx::Rect& screen_bounds) {
DVLOG(1) << "OnKeyboardVisibleBoundsChanged: " << bounds.ToString(); DVLOG(1) << "OnKeyboardVisibleBoundsChanged: " << screen_bounds.ToString();
// Pass the bounds in screen coordinates over mojo. // Pass the bounds in screen coordinates over mojo.
gfx::Rect screen_bounds = BoundsToScreen(bounds);
observers_.ForAllPtrs( observers_.ForAllPtrs(
[&screen_bounds](mojom::KeyboardControllerObserver* observer) { [&screen_bounds](mojom::KeyboardControllerObserver* observer) {
observer->OnKeyboardVisibleBoundsChanged(screen_bounds); observer->OnKeyboardVisibleBoundsChanged(screen_bounds);
...@@ -274,15 +273,14 @@ void AshKeyboardController::OnKeyboardVisibilityStateChanged(bool is_visible) { ...@@ -274,15 +273,14 @@ void AshKeyboardController::OnKeyboardVisibilityStateChanged(bool is_visible) {
} }
void AshKeyboardController::OnKeyboardVisibleBoundsChanged( void AshKeyboardController::OnKeyboardVisibleBoundsChanged(
const gfx::Rect& bounds) { const gfx::Rect& screen_bounds) {
SendOnKeyboardVisibleBoundsChanged(bounds); SendOnKeyboardVisibleBoundsChanged(screen_bounds);
} }
void AshKeyboardController::OnKeyboardWorkspaceOccludedBoundsChanged( void AshKeyboardController::OnKeyboardWorkspaceOccludedBoundsChanged(
const gfx::Rect& bounds) { const gfx::Rect& screen_bounds) {
DVLOG(1) << "OnKeyboardOccludedBoundsChanged: " << bounds.ToString(); DVLOG(1) << "OnKeyboardOccludedBoundsChanged: " << screen_bounds.ToString();
// Pass the bounds in screen coordinates over mojo. // Pass the bounds in screen coordinates over mojo.
gfx::Rect screen_bounds = BoundsToScreen(bounds);
observers_.ForAllPtrs( observers_.ForAllPtrs(
[&screen_bounds](mojom::KeyboardControllerObserver* observer) { [&screen_bounds](mojom::KeyboardControllerObserver* observer) {
observer->OnKeyboardOccludedBoundsChanged(screen_bounds); observer->OnKeyboardOccludedBoundsChanged(screen_bounds);
...@@ -305,12 +303,4 @@ void AshKeyboardController::OnKeyboardEnabledChanged(bool is_enabled) { ...@@ -305,12 +303,4 @@ void AshKeyboardController::OnKeyboardEnabledChanged(bool is_enabled) {
}); });
} }
gfx::Rect AshKeyboardController::BoundsToScreen(const gfx::Rect& bounds) {
DCHECK(keyboard_controller_->GetKeyboardWindow());
gfx::Rect screen_bounds(bounds);
::wm::ConvertRectToScreen(keyboard_controller_->GetKeyboardWindow(),
&screen_bounds);
return screen_bounds;
}
} // namespace ash } // namespace ash
...@@ -60,7 +60,7 @@ class ASH_EXPORT AshKeyboardController ...@@ -60,7 +60,7 @@ class ASH_EXPORT AshKeyboardController
void DestroyVirtualKeyboard(); void DestroyVirtualKeyboard();
// Forwards events to mojo observers. // Forwards events to mojo observers.
void SendOnKeyboardVisibleBoundsChanged(const gfx::Rect& bounds); void SendOnKeyboardVisibleBoundsChanged(const gfx::Rect& screen_bounds);
void SendOnLoadKeyboardContentsRequested(); void SendOnLoadKeyboardContentsRequested();
void SendOnKeyboardUIDestroyed(); void SendOnKeyboardUIDestroyed();
...@@ -113,16 +113,14 @@ class ASH_EXPORT AshKeyboardController ...@@ -113,16 +113,14 @@ class ASH_EXPORT AshKeyboardController
// keyboard::KeyboardControllerObserver // keyboard::KeyboardControllerObserver
void OnKeyboardConfigChanged() override; void OnKeyboardConfigChanged() override;
void OnKeyboardVisibilityStateChanged(bool is_visible) override; void OnKeyboardVisibilityStateChanged(bool is_visible) override;
void OnKeyboardVisibleBoundsChanged(const gfx::Rect& bounds) override; void OnKeyboardVisibleBoundsChanged(const gfx::Rect& screen_bounds) override;
void OnKeyboardWorkspaceOccludedBoundsChanged( void OnKeyboardWorkspaceOccludedBoundsChanged(
const gfx::Rect& bounds) override; const gfx::Rect& screen_bounds) override;
void OnKeyboardEnableFlagsChanged( void OnKeyboardEnableFlagsChanged(
std::set<keyboard::mojom::KeyboardEnableFlag>& keyboard_enable_flags) std::set<keyboard::mojom::KeyboardEnableFlag>& keyboard_enable_flags)
override; override;
void OnKeyboardEnabledChanged(bool is_enabled) override; void OnKeyboardEnabledChanged(bool is_enabled) override;
gfx::Rect BoundsToScreen(const gfx::Rect& bounds);
SessionController* session_controller_; // unowned SessionController* session_controller_; // unowned
std::unique_ptr<keyboard::KeyboardUIFactory> keyboard_ui_factory_; std::unique_ptr<keyboard::KeyboardUIFactory> keyboard_ui_factory_;
std::unique_ptr<keyboard::KeyboardController> keyboard_controller_; std::unique_ptr<keyboard::KeyboardController> keyboard_controller_;
......
...@@ -12,6 +12,9 @@ ...@@ -12,6 +12,9 @@
#include "content/public/browser/render_widget_host_view.h" #include "content/public/browser/render_widget_host_view.h"
#include "extensions/browser/app_window/app_window.h" #include "extensions/browser/app_window/app_window.h"
#include "ui/aura/window.h" #include "ui/aura/window.h"
#include "ui/base/ime/ime_bridge.h"
#include "ui/base/ime/input_method.h"
#include "ui/base/ime/text_input_client.h"
#include "ui/base/ui_base_features.h" #include "ui/base/ui_base_features.h"
#include "ui/display/display.h" #include "ui/display/display.h"
#include "ui/display/screen.h" #include "ui/display/screen.h"
...@@ -33,6 +36,13 @@ content::RenderWidgetHostView* GetHostViewForWindow(aura::Window* window) { ...@@ -33,6 +36,13 @@ content::RenderWidgetHostView* GetHostViewForWindow(aura::Window* window) {
return nullptr; return nullptr;
} }
ui::InputMethod* GetCurrentInputMethod() {
ui::IMEBridge* bridge = ui::IMEBridge::Get();
if (bridge && bridge->GetInputContextHandler())
return bridge->GetInputContextHandler()->GetInputMethod();
return nullptr;
}
} // namespace } // namespace
ChromeKeyboardBoundsObserver::ChromeKeyboardBoundsObserver( ChromeKeyboardBoundsObserver::ChromeKeyboardBoundsObserver(
...@@ -51,25 +61,25 @@ ChromeKeyboardBoundsObserver::~ChromeKeyboardBoundsObserver() { ...@@ -51,25 +61,25 @@ ChromeKeyboardBoundsObserver::~ChromeKeyboardBoundsObserver() {
} }
void ChromeKeyboardBoundsObserver::OnKeyboardOccludedBoundsChanged( void ChromeKeyboardBoundsObserver::OnKeyboardOccludedBoundsChanged(
const gfx::Rect& bounds) { const gfx::Rect& screen_bounds) {
DVLOG(1) << "OnKeyboardOccludedBoundsChanged: " << bounds.ToString(); DVLOG(1) << "OnKeyboardOccludedBoundsChanged: " << screen_bounds.ToString();
UpdateOccludedBounds( UpdateOccludedBounds(
ChromeKeyboardControllerClient::Get()->IsKeyboardOverscrollEnabled() ChromeKeyboardControllerClient::Get()->IsKeyboardOverscrollEnabled()
? bounds ? screen_bounds
: gfx::Rect()); : gfx::Rect());
} }
void ChromeKeyboardBoundsObserver::UpdateOccludedBounds( void ChromeKeyboardBoundsObserver::UpdateOccludedBounds(
const gfx::Rect& occluded_bounds) { const gfx::Rect& screen_bounds) {
DVLOG(1) << "UpdateOccludedBounds: " << occluded_bounds.ToString(); DVLOG(1) << "UpdateOccludedBounds: " << screen_bounds.ToString();
occluded_bounds_ = occluded_bounds; occluded_bounds_in_screen_ = screen_bounds;
std::unique_ptr<content::RenderWidgetHostIterator> hosts( std::unique_ptr<content::RenderWidgetHostIterator> hosts(
content::RenderWidgetHost::GetRenderWidgetHosts()); content::RenderWidgetHost::GetRenderWidgetHosts());
// If |occluded_bounds| is empty (i.e. the keyboard is hidden or floating) // If the keyboard is hidden or floating then reset the insets for all
// reset the insets for all RenderWidgetHosts and remove observers. // RenderWidgetHosts and remove observers.
if (occluded_bounds.IsEmpty()) { if (occluded_bounds_in_screen_.IsEmpty()) {
while (content::RenderWidgetHost* host = hosts->GetNextHost()) { while (content::RenderWidgetHost* host = hosts->GetNextHost()) {
content::RenderWidgetHostView* view = host->GetView(); content::RenderWidgetHostView* view = host->GetView();
if (view) if (view)
...@@ -102,6 +112,13 @@ void ChromeKeyboardBoundsObserver::UpdateOccludedBounds( ...@@ -102,6 +112,13 @@ void ChromeKeyboardBoundsObserver::UpdateOccludedBounds(
UpdateInsets(window, view); UpdateInsets(window, view);
AddObservedWindow(window); AddObservedWindow(window);
} }
// Window reshape can race with the IME trying to keep the text input caret
// visible. Do this here because the widget bounds change happens before the
// occluded bounds are updated. https://crbug.com/937722
ui::InputMethod* ime = GetCurrentInputMethod();
if (ime && ime->GetTextInputClient())
ime->GetTextInputClient()->EnsureCaretNotInRect(occluded_bounds_in_screen_);
} }
void ChromeKeyboardBoundsObserver::AddObservedWindow(aura::Window* window) { void ChromeKeyboardBoundsObserver::AddObservedWindow(aura::Window* window) {
...@@ -124,7 +141,8 @@ void ChromeKeyboardBoundsObserver::RemoveAllObservedWindows() { ...@@ -124,7 +141,8 @@ void ChromeKeyboardBoundsObserver::RemoveAllObservedWindows() {
void ChromeKeyboardBoundsObserver::OnWidgetBoundsChanged( void ChromeKeyboardBoundsObserver::OnWidgetBoundsChanged(
views::Widget* widget, views::Widget* widget,
const gfx::Rect& new_bounds) { const gfx::Rect& new_bounds) {
DVLOG(1) << "OnWidgetBoundsChanged: " << new_bounds.ToString(); DVLOG(1) << "OnWidgetBoundsChanged: " << widget->GetName() << " "
<< new_bounds.ToString();
aura::Window* window = widget->GetNativeView(); aura::Window* window = widget->GetNativeView();
if (!ShouldWindowOverscroll(window)) if (!ShouldWindowOverscroll(window))
...@@ -146,18 +164,20 @@ void ChromeKeyboardBoundsObserver::OnWidgetDestroying(views::Widget* widget) { ...@@ -146,18 +164,20 @@ void ChromeKeyboardBoundsObserver::OnWidgetDestroying(views::Widget* widget) {
void ChromeKeyboardBoundsObserver::UpdateInsets( void ChromeKeyboardBoundsObserver::UpdateInsets(
aura::Window* window, aura::Window* window,
content::RenderWidgetHostView* view) { content::RenderWidgetHostView* view) {
gfx::Rect view_bounds = view->GetViewBounds(); gfx::Rect view_bounds_in_screen = view->GetViewBounds();
if (!ShouldEnableInsets(window)) { if (!ShouldEnableInsets(window)) {
DVLOG(2) << "ResetInsets: " << window->GetName() DVLOG(2) << "ResetInsets: " << window->GetName()
<< " Bounds: " << view_bounds.ToString(); << " Bounds: " << view_bounds_in_screen.ToString();
view->SetInsets(gfx::Insets()); view->SetInsets(gfx::Insets());
return; return;
} }
gfx::Rect intersect = gfx::IntersectRects(view_bounds, occluded_bounds_); gfx::Rect intersect =
gfx::IntersectRects(view_bounds_in_screen, occluded_bounds_in_screen_);
int overlap = intersect.height(); int overlap = intersect.height();
DVLOG(2) << "SetInsets: " << window->GetName() DVLOG(2) << "SetInsets: " << window->GetName()
<< " Bounds: " << view_bounds.ToString() << " Overlap: " << overlap; << " Bounds: " << view_bounds_in_screen.ToString()
if (overlap > 0 && overlap < view_bounds.height()) << " Overlap: " << overlap;
if (overlap > 0 && overlap < view_bounds_in_screen.height())
view->SetInsets(gfx::Insets(0, 0, overlap, 0)); view->SetInsets(gfx::Insets(0, 0, overlap, 0));
else else
view->SetInsets(gfx::Insets()); view->SetInsets(gfx::Insets());
......
...@@ -27,12 +27,12 @@ class ChromeKeyboardBoundsObserver ...@@ -27,12 +27,12 @@ class ChromeKeyboardBoundsObserver
// keyboard::ChromeKeyboardControllerClient::Observer: // keyboard::ChromeKeyboardControllerClient::Observer:
void OnKeyboardVisibilityChanged(bool visible) override {} void OnKeyboardVisibilityChanged(bool visible) override {}
void OnKeyboardOccludedBoundsChanged(const gfx::Rect& bounds) override; void OnKeyboardOccludedBoundsChanged(const gfx::Rect& screen_bounds) override;
private: private:
// Provides the bounds occluded by the keyboard any time they change. // Provides the bounds occluded by the keyboard any time they change.
// (i.e. by the KeyboardController through KeyboardUI::InitInsets). // (i.e. by the KeyboardController through KeyboardUI::InitInsets).
void UpdateOccludedBounds(const gfx::Rect& occluded_bounds); void UpdateOccludedBounds(const gfx::Rect& screen_bounds);
void AddObservedWindow(aura::Window* window); void AddObservedWindow(aura::Window* window);
void RemoveAllObservedWindows(); void RemoveAllObservedWindows();
...@@ -48,7 +48,7 @@ class ChromeKeyboardBoundsObserver ...@@ -48,7 +48,7 @@ class ChromeKeyboardBoundsObserver
aura::Window* const keyboard_window_; aura::Window* const keyboard_window_;
std::set<views::Widget*> observed_widgets_; std::set<views::Widget*> observed_widgets_;
gfx::Rect occluded_bounds_; gfx::Rect occluded_bounds_in_screen_;
DISALLOW_COPY_AND_ASSIGN(ChromeKeyboardBoundsObserver); DISALLOW_COPY_AND_ASSIGN(ChromeKeyboardBoundsObserver);
}; };
......
...@@ -362,10 +362,9 @@ void ChromeKeyboardControllerClient::OnKeyboardOccludedBoundsChanged( ...@@ -362,10 +362,9 @@ void ChromeKeyboardControllerClient::OnKeyboardOccludedBoundsChanged(
const gfx::Rect& screen_bounds) { const gfx::Rect& screen_bounds) {
if (!GetKeyboardWindow()) if (!GetKeyboardWindow())
return; return;
gfx::Rect bounds = BoundsFromScreen(screen_bounds); DVLOG(1) << "OnKeyboardOccludedBoundsChanged: " << screen_bounds.ToString();
DVLOG(1) << "OnKeyboardOccludedBoundsChanged: " << bounds.ToString();
for (auto& observer : observers_) for (auto& observer : observers_)
observer.OnKeyboardOccludedBoundsChanged(bounds); observer.OnKeyboardOccludedBoundsChanged(screen_bounds);
} }
void ChromeKeyboardControllerClient::OnLoadKeyboardContentsRequested() { void ChromeKeyboardControllerClient::OnLoadKeyboardContentsRequested() {
......
...@@ -51,9 +51,9 @@ class ChromeKeyboardControllerClient ...@@ -51,9 +51,9 @@ class ChromeKeyboardControllerClient
// Forwards the 'OnKeyboardOccludedBoundsChanged' mojo observer method. // Forwards the 'OnKeyboardOccludedBoundsChanged' mojo observer method.
// This is used to update the insets of browser and app windows when the // This is used to update the insets of browser and app windows when the
// keyboard is shown. |bounds| is in the frame of reference of the // keyboard is shown.
// keyboard window. virtual void OnKeyboardOccludedBoundsChanged(
virtual void OnKeyboardOccludedBoundsChanged(const gfx::Rect& bounds) {} const gfx::Rect& screen_bounds) {}
// Notifies observers when the keyboard content (i.e. the extension) has // Notifies observers when the keyboard content (i.e. the extension) has
// loaded. Note: if the content is already loaded when the observer is // loaded. Note: if the content is already loaded when the observer is
......
...@@ -27,6 +27,7 @@ class Shadow; ...@@ -27,6 +27,7 @@ class Shadow;
// Subclass of KeyboardUI. It is used by KeyboardController to get // Subclass of KeyboardUI. It is used by KeyboardController to get
// access to the virtual keyboard window and setup Chrome extension functions. // access to the virtual keyboard window and setup Chrome extension functions.
// Used in classic ash, not in mash.
class ChromeKeyboardUI : public keyboard::KeyboardUI, class ChromeKeyboardUI : public keyboard::KeyboardUI,
public aura::WindowObserver { public aura::WindowObserver {
public: public:
......
...@@ -14,6 +14,8 @@ ...@@ -14,6 +14,8 @@
// This implementation of ui::TextInputClient sends all updates via mojo IPC to // This implementation of ui::TextInputClient sends all updates via mojo IPC to
// a remote client. This is intended to be passed to the overrides of // a remote client. This is intended to be passed to the overrides of
// ui::InputMethod::SetFocusedTextInputClient(). // ui::InputMethod::SetFocusedTextInputClient().
// NOTE: Under SingleProcessMash this is used by ash code, for example by the
// virtual keyboard controller in //ui/keyboard.
class RemoteTextInputClient : public ui::TextInputClient, class RemoteTextInputClient : public ui::TextInputClient,
public ui::internal::InputMethodDelegate { public ui::internal::InputMethodDelegate {
public: public:
......
...@@ -757,7 +757,10 @@ void KeyboardController::OnWindowBoundsChanged( ...@@ -757,7 +757,10 @@ void KeyboardController::OnWindowBoundsChanged(
return; return;
// |window| could be the root window (for detecting screen rotations) or the // |window| could be the root window (for detecting screen rotations) or the
// keyboard window (for detecting keyboard bounds changes). // keyboard window (for detecting keyboard bounds changes). For the root
// window, |new_bounds| is in screen coordinates. For the keyboard window,
// |new_bounds| is also in screen coordinates because VK container has
// kUsesScreenCoordinatesKey set.
if (window == GetRootWindow()) if (window == GetRootWindow())
container_behavior_->SetCanonicalBounds(GetKeyboardWindow(), new_bounds); container_behavior_->SetCanonicalBounds(GetKeyboardWindow(), new_bounds);
else if (window == GetKeyboardWindow()) else if (window == GetKeyboardWindow())
......
...@@ -186,7 +186,8 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver, ...@@ -186,7 +186,8 @@ class KEYBOARD_EXPORT KeyboardController : public ui::InputMethodObserver,
// Returns the current bounds that affect the workspace layout. If the // Returns the current bounds that affect the workspace layout. If the
// keyboard is not shown or if the keyboard mode should not affect the usable // keyboard is not shown or if the keyboard mode should not affect the usable
// region of the screen, an empty rectangle will be returned. // region of the screen, an empty rectangle will be returned. Bounds are in
// screen coordinates.
gfx::Rect GetWorkspaceOccludedBounds() const; gfx::Rect GetWorkspaceOccludedBounds() const;
// Returns the current bounds that affect the window layout of the various // Returns the current bounds that affect the window layout of the various
......
...@@ -47,11 +47,11 @@ class KEYBOARD_EXPORT KeyboardControllerObserver { ...@@ -47,11 +47,11 @@ class KEYBOARD_EXPORT KeyboardControllerObserver {
// Called when the keyboard bounds have changed in a way that should affect // Called when the keyboard bounds have changed in a way that should affect
// the usable region of the workspace. The user interface should respond to // the usable region of the workspace. The user interface should respond to
// this event by moving important elements away from |new_bounds| so that they // this event by moving important elements away from |new_bounds_in_screen|
// don't overlap. However, drastic visual changes should be avoided, as the // so that they don't overlap. However, drastic visual changes should be
// occluded bounds may change frequently. // avoided, as the occluded bounds may change frequently.
virtual void OnKeyboardWorkspaceOccludedBoundsChanged( virtual void OnKeyboardWorkspaceOccludedBoundsChanged(
const gfx::Rect& new_bounds) {} const gfx::Rect& new_bounds_in_screen) {}
// Called when the keyboard bounds have changed in a way that affects how the // Called when the keyboard bounds have changed in a way that affects how the
// workspace should change to not take up the screen space occupied by the // workspace should change to not take up the screen space occupied by the
......
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