#include "ash/system/tray/system_tray_delegate.h"
#include "base/command_line.h"
#include "base/synchronization/waitable_event.h"
+#include "ui/aura/client/aura_constants.h"
#include "ui/aura/client/cursor_client.h"
#include "ui/aura/window.h"
-#include "ui/aura/window_property.h"
#include "ui/aura/window_tree_host.h"
+#include "ui/base/ime/input_method.h"
+#include "ui/base/ime/input_method_observer.h"
+#include "ui/base/ime/text_input_client.h"
#include "ui/compositor/dip_util.h"
#include "ui/compositor/layer.h"
#include "ui/compositor/layer_animation_observer.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/screen.h"
#include "ui/wm/core/compound_event_filter.h"
+#include "ui/wm/core/coordinate_conversion.h"
namespace {
// |kPanningMergin| from the edge, the view-port moves.
const int kPanningMergin = 100;
+// Gives a little panning margin for following caret, so that we will move the
+// view-port before the caret is completely out of sight.
+const int kCaretPanningMargin = 10;
+
void MoveCursorTo(aura::WindowTreeHost* host, const gfx::Point& root_location) {
gfx::Point3F host_location_3f(root_location);
host->GetRootTransform().TransformPoint(&host_location_3f);
class MagnificationControllerImpl : virtual public MagnificationController,
public ui::EventHandler,
public ui::ImplicitAnimationObserver,
- public aura::WindowObserver {
+ public aura::WindowObserver,
+ public ui::InputMethodObserver {
public:
MagnificationControllerImpl();
- virtual ~MagnificationControllerImpl();
+ ~MagnificationControllerImpl() override;
// MagnificationController overrides:
- virtual void SetEnabled(bool enabled) OVERRIDE;
- virtual bool IsEnabled() const OVERRIDE;
- virtual void SetScale(float scale, bool animate) OVERRIDE;
- virtual float GetScale() const OVERRIDE { return scale_; }
- virtual void MoveWindow(int x, int y, bool animate) OVERRIDE;
- virtual void MoveWindow(const gfx::Point& point, bool animate) OVERRIDE;
- virtual gfx::Point GetWindowPosition() const OVERRIDE {
+ void SetEnabled(bool enabled) override;
+ bool IsEnabled() const override;
+ void SetScale(float scale, bool animate) override;
+ float GetScale() const override { return scale_; }
+ void MoveWindow(int x, int y, bool animate) override;
+ void MoveWindow(const gfx::Point& point, bool animate) override;
+ gfx::Point GetWindowPosition() const override {
return gfx::ToFlooredPoint(origin_);
}
- virtual void SetScrollDirection(ScrollDirection direction) OVERRIDE;
+ void SetScrollDirection(ScrollDirection direction) override;
// For test
- virtual gfx::Point GetPointOfInterestForTesting() OVERRIDE {
+ gfx::Point GetPointOfInterestForTesting() override {
return point_of_interest_;
}
private:
// ui::ImplicitAnimationObserver overrides:
- virtual void OnImplicitAnimationsCompleted() OVERRIDE;
+ void OnImplicitAnimationsCompleted() override;
// aura::WindowObserver overrides:
- virtual void OnWindowDestroying(aura::Window* root_window) OVERRIDE;
- virtual void OnWindowBoundsChanged(aura::Window* window,
- const gfx::Rect& old_bounds,
- const gfx::Rect& new_bounds) OVERRIDE;
+ void OnWindowDestroying(aura::Window* root_window) override;
+ void OnWindowBoundsChanged(aura::Window* window,
+ const gfx::Rect& old_bounds,
+ const gfx::Rect& new_bounds) override;
// Redraws the magnification window with the given origin position and the
// given scale. Returns true if the window is changed; otherwise, false.
void ValidateScale(float* scale);
// ui::EventHandler overrides:
- virtual void OnMouseEvent(ui::MouseEvent* event) OVERRIDE;
- virtual void OnScrollEvent(ui::ScrollEvent* event) OVERRIDE;
- virtual void OnTouchEvent(ui::TouchEvent* event) OVERRIDE;
+ void OnMouseEvent(ui::MouseEvent* event) override;
+ void OnScrollEvent(ui::ScrollEvent* event) override;
+ void OnTouchEvent(ui::TouchEvent* event) override;
+
+ // Moves the view port when |point| is located within
+ // |x_panning_margin| and |y_pannin_margin| to the edge of the visible
+ // window region. The view port will be moved so that the |point| will be
+ // moved to the point where it has |x_target_margin| and |y_target_margin|
+ // to the edge of the visible region.
+ void MoveMagnifierWindow(const gfx::Point& point,
+ int x_panning_margin,
+ int y_panning_margin,
+ int x_target_margin,
+ int y_target_margin);
+
+ // ui::InputMethodObserver:
+ void OnTextInputTypeChanged(const ui::TextInputClient* client) override {}
+ void OnFocus() override {}
+ void OnBlur() override {}
+ void OnTextInputStateChanged(const ui::TextInputClient* client) override {}
+ void OnInputMethodDestroyed(const ui::InputMethod* input_method) override {}
+ void OnShowImeIfNeeded() override {}
+ void OnCaretBoundsChanged(const ui::TextInputClient* client) override;
// Target root window. This must not be NULL.
aura::Window* root_window_;
ScrollDirection scroll_direction_;
+ ui::InputMethod* input_method_; // Not owned.
+
DISALLOW_COPY_AND_ASSIGN(MagnificationControllerImpl);
};
is_enabled_(false),
move_cursor_after_animation_(false),
scale_(kNonMagnifiedScale),
- scroll_direction_(SCROLL_NONE) {
+ scroll_direction_(SCROLL_NONE),
+ input_method_(NULL) {
Shell::GetInstance()->AddPreTargetHandler(this);
root_window_->AddObserver(this);
point_of_interest_ = root_window_->bounds().CenterPoint();
}
MagnificationControllerImpl::~MagnificationControllerImpl() {
+ if (input_method_)
+ input_method_->RemoveObserver(this);
+
root_window_->RemoveObserver(this);
Shell::GetInstance()->RemovePreTargetHandler(this);
DCHECK(root_window_);
gfx::Point mouse(location);
-
- int x = origin_.x();
- int y = origin_.y();
- bool start_zoom = false;
-
- const gfx::Rect window_rect = gfx::ToEnclosingRect(GetWindowRectDIP(scale_));
- const int left = window_rect.x();
- const int right = window_rect.right();
int margin = kPanningMergin / scale_; // No need to consider DPI.
-
- int x_diff = 0;
-
- if (mouse.x() < left + margin) {
- // Panning left.
- x_diff = mouse.x() - (left + margin);
- start_zoom = true;
- } else if (right - margin < mouse.x()) {
- // Panning right.
- x_diff = mouse.x() - (right - margin);
- start_zoom = true;
- }
- x = left + x_diff;
-
- const int top = window_rect.y();
- const int bottom = window_rect.bottom();
-
- int y_diff = 0;
- if (mouse.y() < top + margin) {
- // Panning up.
- y_diff = mouse.y() - (top + margin);
- start_zoom = true;
- } else if (bottom - margin < mouse.y()) {
- // Panning down.
- y_diff = mouse.y() - (bottom - margin);
- start_zoom = true;
- }
- y = top + y_diff;
-
- if (start_zoom && !is_on_animation_) {
- // No animation on panning.
- bool animate = false;
- bool ret = RedrawDIP(gfx::Point(x, y), scale_, animate);
-
- if (ret) {
- // If the magnified region is moved, hides the mouse cursor and moves it.
- if (x_diff != 0 || y_diff != 0)
- MoveCursorTo(root_window_->GetHost(), mouse);
- }
- }
+ MoveMagnifierWindow(mouse, margin, margin, margin, margin);
}
void MagnificationControllerImpl::AfterAnimationMoveCursorTo(
void MagnificationControllerImpl::SetEnabled(bool enabled) {
Shell* shell = Shell::GetInstance();
if (enabled) {
+ if (!input_method_) {
+ input_method_ =
+ root_window_->GetProperty(aura::client::kRootWindowInputMethodKey);
+ if (input_method_)
+ input_method_->AddObserver(this);
+ }
+
float scale =
Shell::GetInstance()->accessibility_delegate()->
GetSavedScreenMagnifierScale();
if (!is_enabled_)
return;
+ if (input_method_) {
+ input_method_->RemoveObserver(this);
+ input_method_ = NULL;
+ }
+
RedrawKeepingMousePosition(kNonMagnifiedScale, true);
is_enabled_ = enabled;
}
}
}
+void MagnificationControllerImpl::MoveMagnifierWindow(const gfx::Point& point,
+ int x_panning_margin,
+ int y_panning_margin,
+ int x_target_margin,
+ int y_target_margin) {
+ DCHECK(root_window_);
+ int x = origin_.x();
+ int y = origin_.y();
+ bool start_zoom = false;
+
+ const gfx::Rect window_rect = gfx::ToEnclosingRect(GetWindowRectDIP(scale_));
+ const int left = window_rect.x();
+ const int right = window_rect.right();
+
+ int x_diff = 0;
+ if (point.x() < left + x_panning_margin) {
+ // Panning left.
+ x_diff = point.x() - (left + x_target_margin);
+ start_zoom = true;
+ } else if (right - x_panning_margin < point.x()) {
+ // Panning right.
+ x_diff = point.x() - (right - x_target_margin);
+ start_zoom = true;
+ }
+ x = left + x_diff;
+
+ const int top = window_rect.y();
+ const int bottom = window_rect.bottom();
+
+ int y_diff = 0;
+ if (point.y() < top + y_panning_margin) {
+ // Panning up.
+ y_diff = point.y() - (top + y_target_margin);
+ start_zoom = true;
+ } else if (bottom - y_panning_margin < point.y()) {
+ // Panning down.
+ y_diff = point.y() - (bottom - y_target_margin);
+ start_zoom = true;
+ }
+ y = top + y_diff;
+ if (start_zoom && !is_on_animation_) {
+ // No animation on panning.
+ bool animate = false;
+ bool ret = RedrawDIP(gfx::Point(x, y), scale_, animate);
+
+ if (ret) {
+ // If the magnified region is moved, hides the mouse cursor and moves it.
+ if (x_diff != 0 || y_diff != 0)
+ MoveCursorTo(root_window_->GetHost(), point);
+ }
+ }
+}
+
+void MagnificationControllerImpl::OnCaretBoundsChanged(
+ const ui::TextInputClient* client) {
+ // caret bounds in screen coordinates.
+ const gfx::Rect caret_bounds = client->GetCaretBounds();
+ // Note: OnCaretBoundsChanged could be fired OnTextInputTypeChanged during
+ // which the caret position is not set a meaning position, and we do not
+ // need to adjust the view port position based on the bogus caret position.
+ // This is only a transition period, the caret position will be fixed upon
+ // focusing right after.
+ if (caret_bounds.width() == 0 && caret_bounds.height() == 0)
+ return;
+
+ gfx::Point caret_origin = caret_bounds.origin();
+ // caret_origin in |root_window_| coordinates.
+ wm::ConvertPointFromScreen(root_window_, &caret_origin);
+
+ // Visible window_rect in |root_window_| coordinates.
+ const gfx::Rect visible_window_rect =
+ gfx::ToEnclosingRect(GetWindowRectDIP(scale_));
+
+ const int panning_margin = kCaretPanningMargin / scale_;
+ MoveMagnifierWindow(caret_origin,
+ panning_margin,
+ panning_margin,
+ visible_window_rect.width() / 2,
+ visible_window_rect.height() / 2);
+}
+
////////////////////////////////////////////////////////////////////////////////
// MagnificationController: