#include "ash/magnifier/magnification_controller.h"
+#include "ash/accelerators/accelerator_controller.h"
#include "ash/accessibility_delegate.h"
+#include "ash/ash_switches.h"
#include "ash/display/root_window_transformers.h"
+#include "ash/host/ash_window_tree_host.h"
+#include "ash/host/root_window_transformer.h"
+#include "ash/root_window_controller.h"
#include "ash/shell.h"
#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/root_window.h"
-#include "ui/aura/root_window_transformer.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/point_f.h"
#include "ui/gfx/rect_conversions.h"
#include "ui/gfx/screen.h"
-#include "ui/views/corewm/compound_event_filter.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;
-void MoveCursorTo(aura::RootWindow* root_window,
- const gfx::Point& root_location) {
+// 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);
- root_window->GetRootTransform().TransformPoint(&host_location_3f);
- root_window->MoveCursorToHostLocation(
+ host->GetRootTransform().TransformPoint(&host_location_3f);
+ host->MoveCursorToHostLocation(
gfx::ToCeiledPoint(host_location_3f.AsPointF()));
}
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 EnsureRectIsVisible(const gfx::Rect& rect,
- bool animate) OVERRIDE;
- virtual void EnsurePointIsVisible(const gfx::Point& point,
- bool animate) 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.
bool Redraw(const gfx::PointF& position, float scale, bool animate);
bool RedrawDIP(const gfx::PointF& position, float scale, bool animate);
+ // 1) If the screen is scrolling (i.e. animating) and should scroll further,
+ // it does nothing.
+ // 2) If the screen is scrolling (i.e. animating) and the direction is NONE,
+ // it stops the scrolling animation.
+ // 3) If the direction is set to value other than NONE, it starts the
+ // scrolling/ animation towards that direction.
+ void StartOrStopScrollIfNecessary();
+
// Redraw with the given zoom scale keeping the mouse cursor location. In
// other words, zoom (or unzoom) centering around the cursor.
void RedrawKeepingMousePosition(float scale, bool animate);
- // Ensures that the given point, rect or last mouse location is inside
- // magnification window. If not, the controller moves the window to contain
- // the given point/rect.
- void EnsureRectIsVisibleWithScale(const gfx::Rect& target_rect,
- float scale,
- bool animate);
- void EnsureRectIsVisibleDIP(const gfx::Rect& target_rect_in_dip,
- float scale,
- bool animate);
- void EnsurePointIsVisibleWithScale(const gfx::Point& point,
- float scale,
- bool animate);
void OnMouseMove(const gfx::Point& location);
// Move the mouse cursot to the given point. Actual move will be done when
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_;
float scale_;
gfx::PointF origin_;
+ ScrollDirection scroll_direction_;
+
+ ui::InputMethod* input_method_; // Not owned.
+
DISALLOW_COPY_AND_ASSIGN(MagnificationControllerImpl);
};
// MagnificationControllerImpl:
MagnificationControllerImpl::MagnificationControllerImpl()
- : root_window_(ash::Shell::GetPrimaryRootWindow()),
+ : root_window_(Shell::GetPrimaryRootWindow()),
is_on_animation_(false),
is_enabled_(false),
move_cursor_after_animation_(false),
- scale_(kNonMagnifiedScale) {
+ scale_(kNonMagnifiedScale),
+ 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);
gfx::Display display =
Shell::GetScreen()->GetDisplayNearestWindow(root_window_);
- scoped_ptr<aura::RootWindowTransformer> transformer(
- internal::CreateRootWindowTransformerForDisplay(root_window_, display));
- root_window_->GetDispatcher()->SetRootWindowTransformer(transformer.Pass());
+ scoped_ptr<RootWindowTransformer> transformer(
+ CreateRootWindowTransformerForDisplay(root_window_, display));
+ GetRootWindowController(root_window_)->ash_host()->SetRootWindowTransformer(
+ transformer.Pass());
if (animate)
is_on_animation_ = true;
return true;
}
-void MagnificationControllerImpl::EnsureRectIsVisibleWithScale(
- const gfx::Rect& target_rect,
- float scale,
- bool animate) {
- const gfx::Rect target_rect_in_dip =
- ui::ConvertRectToDIP(root_window_->layer(), target_rect);
- EnsureRectIsVisibleDIP(target_rect_in_dip, scale, animate);
-}
-
-void MagnificationControllerImpl::EnsureRectIsVisibleDIP(
- const gfx::Rect& target_rect,
- float scale,
- bool animate) {
- ValidateScale(&scale);
-
- const gfx::Rect window_rect = gfx::ToEnclosingRect(GetWindowRectDIP(scale));
- if (scale == scale_ && window_rect.Contains(target_rect))
+void MagnificationControllerImpl::StartOrStopScrollIfNecessary() {
+ // This value controls the scrolling speed.
+ const int kMoveOffset = 40;
+ if (is_on_animation_) {
+ if (scroll_direction_ == SCROLL_NONE)
+ root_window_->layer()->GetAnimator()->StopAnimating();
return;
+ }
- // TODO(yoshiki): Un-zoom and change the scale if the magnification window
- // can't contain the whole given rect.
-
- gfx::Rect rect = window_rect;
- if (target_rect.width() > rect.width())
- rect.set_x(target_rect.CenterPoint().x() - rect.x() / 2);
- else if (target_rect.right() < rect.x())
- rect.set_x(target_rect.right());
- else if (rect.right() < target_rect.x())
- rect.set_x(target_rect.x() - rect.width());
-
- if (rect.height() > window_rect.height())
- rect.set_y(target_rect.CenterPoint().y() - rect.y() / 2);
- else if (target_rect.bottom() < rect.y())
- rect.set_y(target_rect.bottom());
- else if (rect.bottom() < target_rect.y())
- rect.set_y(target_rect.y() - rect.height());
-
- RedrawDIP(rect.origin(), scale, animate);
-}
-
-void MagnificationControllerImpl::EnsurePointIsVisibleWithScale(
- const gfx::Point& point,
- float scale,
- bool animate) {
- EnsureRectIsVisibleWithScale(gfx::Rect(point, gfx::Size(0, 0)),
- scale,
- animate);
+ gfx::PointF new_origin = origin_;
+ switch (scroll_direction_) {
+ case SCROLL_NONE:
+ // No need to take action.
+ return;
+ case SCROLL_LEFT:
+ new_origin.Offset(-kMoveOffset, 0);
+ break;
+ case SCROLL_RIGHT:
+ new_origin.Offset(kMoveOffset, 0);
+ break;
+ case SCROLL_UP:
+ new_origin.Offset(0, -kMoveOffset);
+ break;
+ case SCROLL_DOWN:
+ new_origin.Offset(0, kMoveOffset);
+ break;
+ }
+ RedrawDIP(new_origin, scale_, true);
}
void MagnificationControllerImpl::OnMouseMove(const gfx::Point& location) {
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_->GetDispatcher(), mouse);
- }
- }
+ MoveMagnifierWindow(mouse, margin, margin, margin, margin);
}
void MagnificationControllerImpl::AfterAnimationMoveCursorTo(
return;
if (move_cursor_after_animation_) {
- MoveCursorTo(root_window_->GetDispatcher(), position_after_animation_);
+ MoveCursorTo(root_window_->GetHost(), position_after_animation_);
move_cursor_after_animation_ = false;
aura::client::CursorClient* cursor_client =
}
is_on_animation_ = false;
+
+ StartOrStopScrollIfNecessary();
}
void MagnificationControllerImpl::OnWindowDestroying(
return;
ValidateScale(&scale);
- ash::Shell::GetInstance()->accessibility_delegate()->
+ Shell::GetInstance()->accessibility_delegate()->
SaveScreenMagnifierScale(scale);
RedrawKeepingMousePosition(scale, animate);
}
Redraw(point, scale_, animate);
}
-void MagnificationControllerImpl::EnsureRectIsVisible(
- const gfx::Rect& target_rect,
- bool animate) {
- if (!is_enabled_)
- return;
-
- EnsureRectIsVisibleWithScale(target_rect, scale_, animate);
-}
-
-void MagnificationControllerImpl::EnsurePointIsVisible(
- const gfx::Point& point,
- bool animate) {
- if (!is_enabled_)
- return;
-
- EnsurePointIsVisibleWithScale(point, scale_, animate);
+void MagnificationControllerImpl::SetScrollDirection(
+ ScrollDirection direction) {
+ scroll_direction_ = direction;
+ StartOrStopScrollIfNecessary();
}
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 =
- ash::Shell::GetInstance()->accessibility_delegate()->
+ Shell::GetInstance()->accessibility_delegate()->
GetSavedScreenMagnifierScale();
if (scale <= 0.0f)
scale = kInitialMagnifiedScale;
is_enabled_ = enabled;
RedrawKeepingMousePosition(scale, true);
- ash::Shell::GetInstance()->accessibility_delegate()->
- SaveScreenMagnifierScale(scale);
+ shell->accessibility_delegate()->SaveScreenMagnifierScale(scale);
} else {
// Do nothing, if already disabled.
if (!is_enabled_)
return;
+ if (input_method_) {
+ input_method_->RemoveObserver(this);
+ input_method_ = NULL;
+ }
+
RedrawKeepingMousePosition(kNonMagnifiedScale, true);
is_enabled_ = enabled;
}
if (root_bounds.Contains(event->root_location())) {
// This must be before |SwitchTargetRootWindow()|.
- point_of_interest_ = event->root_location();
+ if (event->type() != ui::ET_MOUSE_CAPTURE_CHANGED)
+ point_of_interest_ = event->root_location();
if (current_root != root_window_) {
DCHECK(current_root);
}
}
+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: