Update V8 to version 4.5.15.
[chromium-blink-merge.git] / ash / magnifier / magnification_controller.cc
bloba6ad0a1a1ad601877d8aa578781503fb3acfbffa
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "ash/magnifier/magnification_controller.h"
7 #include "ash/accelerators/accelerator_controller.h"
8 #include "ash/accessibility_delegate.h"
9 #include "ash/ash_switches.h"
10 #include "ash/display/root_window_transformers.h"
11 #include "ash/host/ash_window_tree_host.h"
12 #include "ash/host/root_window_transformer.h"
13 #include "ash/root_window_controller.h"
14 #include "ash/screen_util.h"
15 #include "ash/shell.h"
16 #include "ash/system/tray/system_tray_delegate.h"
17 #include "base/command_line.h"
18 #include "base/synchronization/waitable_event.h"
19 #include "ui/aura/client/aura_constants.h"
20 #include "ui/aura/client/cursor_client.h"
21 #include "ui/aura/window.h"
22 #include "ui/aura/window_tree_host.h"
23 #include "ui/base/ime/input_method.h"
24 #include "ui/base/ime/input_method_observer.h"
25 #include "ui/base/ime/text_input_client.h"
26 #include "ui/compositor/dip_util.h"
27 #include "ui/compositor/layer.h"
28 #include "ui/compositor/layer_animation_observer.h"
29 #include "ui/compositor/scoped_layer_animation_settings.h"
30 #include "ui/events/event.h"
31 #include "ui/events/event_handler.h"
32 #include "ui/gfx/geometry/point3_f.h"
33 #include "ui/gfx/geometry/point_conversions.h"
34 #include "ui/gfx/geometry/point_f.h"
35 #include "ui/gfx/geometry/rect_conversions.h"
36 #include "ui/gfx/screen.h"
37 #include "ui/wm/core/compound_event_filter.h"
38 #include "ui/wm/core/coordinate_conversion.h"
40 namespace {
42 const float kMaxMagnifiedScale = 4.0f;
43 const float kMaxMagnifiedScaleThreshold = 4.0f;
44 const float kMinMagnifiedScaleThreshold = 1.1f;
45 const float kNonMagnifiedScale = 1.0f;
47 const float kInitialMagnifiedScale = 2.0f;
48 const float kScrollScaleChangeFactor = 0.05f;
50 // Threadshold of panning. If the cursor moves to within pixels (in DIP) of
51 // |kPanningMergin| from the edge, the view-port moves.
52 const int kPanningMergin = 100;
54 // Gives a little panning margin for following caret, so that we will move the
55 // view-port before the caret is completely out of sight.
56 const int kCaretPanningMargin = 10;
58 void MoveCursorTo(aura::WindowTreeHost* host, const gfx::Point& root_location) {
59 gfx::Point3F host_location_3f(root_location);
60 host->GetRootTransform().TransformPoint(&host_location_3f);
61 host->MoveCursorToHostLocation(
62 gfx::ToCeiledPoint(host_location_3f.AsPointF()));
65 } // namespace
67 namespace ash {
69 ////////////////////////////////////////////////////////////////////////////////
70 // MagnificationControllerImpl:
72 class MagnificationControllerImpl : virtual public MagnificationController,
73 public ui::EventHandler,
74 public ui::ImplicitAnimationObserver,
75 public aura::WindowObserver,
76 public ui::InputMethodObserver {
77 public:
78 MagnificationControllerImpl();
79 ~MagnificationControllerImpl() override;
81 // MagnificationController overrides:
82 void SetEnabled(bool enabled) override;
83 bool IsEnabled() const override;
84 void SetScale(float scale, bool animate) override;
85 float GetScale() const override { return scale_; }
86 void MoveWindow(int x, int y, bool animate) override;
87 void MoveWindow(const gfx::Point& point, bool animate) override;
88 gfx::Point GetWindowPosition() const override {
89 return gfx::ToFlooredPoint(origin_);
91 void SetScrollDirection(ScrollDirection direction) override;
92 gfx::Rect GetViewportRect() const override;
93 void HandleFocusedNodeChanged(
94 bool is_editable_node,
95 const gfx::Rect& node_bounds_in_screen) override;
96 void SwitchTargetRootWindow(aura::Window* new_root_window,
97 bool redraw_original_root_window) override;
99 // For test
100 gfx::Point GetPointOfInterestForTesting() override {
101 return point_of_interest_;
104 bool IsOnAnimationForTesting() const override { return is_on_animation_; }
106 private:
107 // ui::ImplicitAnimationObserver overrides:
108 void OnImplicitAnimationsCompleted() override;
110 // aura::WindowObserver overrides:
111 void OnWindowDestroying(aura::Window* root_window) override;
112 void OnWindowBoundsChanged(aura::Window* window,
113 const gfx::Rect& old_bounds,
114 const gfx::Rect& new_bounds) override;
116 // Redraws the magnification window with the given origin position and the
117 // given scale. Returns true if the window is changed; otherwise, false.
118 // These methods should be called internally just after the scale and/or
119 // the position are changed to redraw the window.
120 bool Redraw(const gfx::PointF& position, float scale, bool animate);
121 bool RedrawDIP(const gfx::PointF& position, float scale, bool animate);
123 // 1) If the screen is scrolling (i.e. animating) and should scroll further,
124 // it does nothing.
125 // 2) If the screen is scrolling (i.e. animating) and the direction is NONE,
126 // it stops the scrolling animation.
127 // 3) If the direction is set to value other than NONE, it starts the
128 // scrolling/ animation towards that direction.
129 void StartOrStopScrollIfNecessary();
131 // Redraw with the given zoom scale keeping the mouse cursor location. In
132 // other words, zoom (or unzoom) centering around the cursor.
133 void RedrawKeepingMousePosition(float scale, bool animate);
135 void OnMouseMove(const gfx::Point& location);
137 // Move the mouse cursot to the given point. Actual move will be done when
138 // the animation is completed. This should be called after animation is
139 // started.
140 void AfterAnimationMoveCursorTo(const gfx::Point& location);
142 // Returns if the magnification scale is 1.0 or not (larger then 1.0).
143 bool IsMagnified() const;
145 // Returns the rect of the magnification window.
146 gfx::RectF GetWindowRectDIP(float scale) const;
147 // Returns the size of the root window.
148 gfx::Size GetHostSizeDIP() const;
150 // Correct the given scale value if necessary.
151 void ValidateScale(float* scale);
153 // ui::EventHandler overrides:
154 void OnMouseEvent(ui::MouseEvent* event) override;
155 void OnScrollEvent(ui::ScrollEvent* event) override;
156 void OnTouchEvent(ui::TouchEvent* event) override;
158 // Moves the view port when |point| is located within
159 // |x_panning_margin| and |y_pannin_margin| to the edge of the visible
160 // window region. The view port will be moved so that the |point| will be
161 // moved to the point where it has |x_target_margin| and |y_target_margin|
162 // to the edge of the visible region.
163 void MoveMagnifierWindowFollowPoint(const gfx::Point& point,
164 int x_panning_margin,
165 int y_panning_margin,
166 int x_target_margin,
167 int y_target_margin);
169 // Moves the viewport so that |rect| is fully visible. If |rect| is larger
170 // than the viewport horizontally or vertically, the viewport will be moved
171 // to center the |rect| in that dimension.
172 void MoveMagnifierWindowFollowRect(const gfx::Rect& rect);
174 // ui::InputMethodObserver:
175 void OnTextInputTypeChanged(const ui::TextInputClient* client) override {}
176 void OnFocus() override {}
177 void OnBlur() override {}
178 void OnTextInputStateChanged(const ui::TextInputClient* client) override {}
179 void OnInputMethodDestroyed(const ui::InputMethod* input_method) override {}
180 void OnShowImeIfNeeded() override {}
181 void OnCaretBoundsChanged(const ui::TextInputClient* client) override;
183 // Target root window. This must not be NULL.
184 aura::Window* root_window_;
186 // True if the magnified window is currently animating a change. Otherwise,
187 // false.
188 bool is_on_animation_;
190 bool is_enabled_;
192 // True if the cursor needs to move the given position after the animation
193 // will be finished. When using this, set |position_after_animation_| as well.
194 bool move_cursor_after_animation_;
195 // Stores the position of cursor to be moved after animation.
196 gfx::Point position_after_animation_;
198 // Stores the last mouse cursor (or last touched) location. This value is
199 // used on zooming to keep this location visible.
200 gfx::Point point_of_interest_;
202 // Current scale, origin (left-top) position of the magnification window.
203 float scale_;
204 gfx::PointF origin_;
206 ScrollDirection scroll_direction_;
208 ui::InputMethod* input_method_; // Not owned.
210 DISALLOW_COPY_AND_ASSIGN(MagnificationControllerImpl);
213 ////////////////////////////////////////////////////////////////////////////////
214 // MagnificationControllerImpl:
216 MagnificationControllerImpl::MagnificationControllerImpl()
217 : root_window_(Shell::GetPrimaryRootWindow()),
218 is_on_animation_(false),
219 is_enabled_(false),
220 move_cursor_after_animation_(false),
221 scale_(kNonMagnifiedScale),
222 scroll_direction_(SCROLL_NONE),
223 input_method_(NULL) {
224 Shell::GetInstance()->AddPreTargetHandler(this);
225 root_window_->AddObserver(this);
226 point_of_interest_ = root_window_->bounds().CenterPoint();
229 MagnificationControllerImpl::~MagnificationControllerImpl() {
230 if (input_method_)
231 input_method_->RemoveObserver(this);
233 root_window_->RemoveObserver(this);
235 Shell::GetInstance()->RemovePreTargetHandler(this);
238 void MagnificationControllerImpl::RedrawKeepingMousePosition(
239 float scale, bool animate) {
240 gfx::Point mouse_in_root = point_of_interest_;
242 // mouse_in_root is invalid value when the cursor is hidden.
243 if (!root_window_->bounds().Contains(mouse_in_root))
244 mouse_in_root = root_window_->bounds().CenterPoint();
246 const gfx::PointF origin =
247 gfx::PointF(mouse_in_root.x() -
248 (scale_ / scale) * (mouse_in_root.x() - origin_.x()),
249 mouse_in_root.y() -
250 (scale_ / scale) * (mouse_in_root.y() - origin_.y()));
251 bool changed = RedrawDIP(origin, scale, animate);
252 if (changed)
253 AfterAnimationMoveCursorTo(mouse_in_root);
256 bool MagnificationControllerImpl::Redraw(const gfx::PointF& position,
257 float scale,
258 bool animate) {
259 const gfx::PointF position_in_dip =
260 ui::ConvertPointToDIP(root_window_->layer(), position);
261 return RedrawDIP(position_in_dip, scale, animate);
264 bool MagnificationControllerImpl::RedrawDIP(const gfx::PointF& position_in_dip,
265 float scale,
266 bool animate) {
267 DCHECK(root_window_);
269 float x = position_in_dip.x();
270 float y = position_in_dip.y();
272 ValidateScale(&scale);
274 if (x < 0)
275 x = 0;
276 if (y < 0)
277 y = 0;
279 const gfx::Size host_size_in_dip = GetHostSizeDIP();
280 const gfx::SizeF window_size_in_dip = GetWindowRectDIP(scale).size();
281 float max_x = host_size_in_dip.width() - window_size_in_dip.width();
282 float max_y = host_size_in_dip.height() - window_size_in_dip.height();
283 if (x > max_x)
284 x = max_x;
285 if (y > max_y)
286 y = max_y;
288 // Does nothing if both the origin and the scale are not changed.
289 if (origin_.x() == x &&
290 origin_.y() == y &&
291 scale == scale_) {
292 return false;
295 origin_.set_x(x);
296 origin_.set_y(y);
297 scale_ = scale;
299 // Creates transform matrix.
300 gfx::Transform transform;
301 // Flips the signs intentionally to convert them from the position of the
302 // magnification window.
303 transform.Scale(scale_, scale_);
304 transform.Translate(-origin_.x(), -origin_.y());
306 ui::ScopedLayerAnimationSettings settings(
307 root_window_->layer()->GetAnimator());
308 settings.AddObserver(this);
309 settings.SetPreemptionStrategy(
310 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET);
311 settings.SetTweenType(gfx::Tween::EASE_OUT);
312 settings.SetTransitionDuration(
313 base::TimeDelta::FromMilliseconds(animate ? 100 : 0));
315 gfx::Display display =
316 Shell::GetScreen()->GetDisplayNearestWindow(root_window_);
317 scoped_ptr<RootWindowTransformer> transformer(
318 CreateRootWindowTransformerForDisplay(root_window_, display));
319 GetRootWindowController(root_window_)->ash_host()->SetRootWindowTransformer(
320 transformer.Pass());
322 if (animate)
323 is_on_animation_ = true;
325 return true;
328 void MagnificationControllerImpl::StartOrStopScrollIfNecessary() {
329 // This value controls the scrolling speed.
330 const int kMoveOffset = 40;
331 if (is_on_animation_) {
332 if (scroll_direction_ == SCROLL_NONE)
333 root_window_->layer()->GetAnimator()->StopAnimating();
334 return;
337 gfx::PointF new_origin = origin_;
338 switch (scroll_direction_) {
339 case SCROLL_NONE:
340 // No need to take action.
341 return;
342 case SCROLL_LEFT:
343 new_origin.Offset(-kMoveOffset, 0);
344 break;
345 case SCROLL_RIGHT:
346 new_origin.Offset(kMoveOffset, 0);
347 break;
348 case SCROLL_UP:
349 new_origin.Offset(0, -kMoveOffset);
350 break;
351 case SCROLL_DOWN:
352 new_origin.Offset(0, kMoveOffset);
353 break;
355 RedrawDIP(new_origin, scale_, true);
358 void MagnificationControllerImpl::OnMouseMove(const gfx::Point& location) {
359 DCHECK(root_window_);
361 gfx::Point mouse(location);
362 int margin = kPanningMergin / scale_; // No need to consider DPI.
363 MoveMagnifierWindowFollowPoint(mouse, margin, margin, margin, margin);
366 gfx::Rect MagnificationControllerImpl::GetViewportRect() const {
367 return gfx::ToEnclosingRect(GetWindowRectDIP(scale_));
370 void MagnificationControllerImpl::HandleFocusedNodeChanged(
371 bool is_editable_node,
372 const gfx::Rect& node_bounds_in_screen) {
373 // The editable node is handled by OnCaretBoundsChanged.
374 if (is_editable_node)
375 return;
377 gfx::Rect node_bounds_in_root =
378 ScreenUtil::ConvertRectFromScreen(root_window_, node_bounds_in_screen);
379 if (GetViewportRect().Contains(node_bounds_in_root))
380 return;
382 MoveMagnifierWindowFollowRect(node_bounds_in_root);
385 void MagnificationControllerImpl::SwitchTargetRootWindow(
386 aura::Window* new_root_window,
387 bool redraw_original_root_window) {
388 DCHECK(new_root_window);
390 if (new_root_window == root_window_)
391 return;
393 // Stores the previous scale.
394 float scale = GetScale();
396 // Unmagnify the previous root window.
397 root_window_->RemoveObserver(this);
398 if (redraw_original_root_window)
399 RedrawKeepingMousePosition(1.0f, true);
400 root_window_ = new_root_window;
401 RedrawKeepingMousePosition(scale, true);
402 root_window_->AddObserver(this);
405 void MagnificationControllerImpl::AfterAnimationMoveCursorTo(
406 const gfx::Point& location) {
407 DCHECK(root_window_);
409 aura::client::CursorClient* cursor_client =
410 aura::client::GetCursorClient(root_window_);
411 if (cursor_client) {
412 // When cursor is invisible, do not move or show the cursor after the
413 // animation.
414 if (!cursor_client->IsCursorVisible())
415 return;
416 cursor_client->DisableMouseEvents();
418 move_cursor_after_animation_ = true;
419 position_after_animation_ = location;
422 gfx::Size MagnificationControllerImpl::GetHostSizeDIP() const {
423 return root_window_->bounds().size();
426 gfx::RectF MagnificationControllerImpl::GetWindowRectDIP(float scale) const {
427 const gfx::Size size_in_dip = root_window_->bounds().size();
428 const float width = size_in_dip.width() / scale;
429 const float height = size_in_dip.height() / scale;
431 return gfx::RectF(origin_.x(), origin_.y(), width, height);
434 bool MagnificationControllerImpl::IsMagnified() const {
435 return scale_ >= kMinMagnifiedScaleThreshold;
438 void MagnificationControllerImpl::ValidateScale(float* scale) {
439 // Adjust the scale to just |kNonMagnifiedScale| if scale is smaller than
440 // |kMinMagnifiedScaleThreshold|;
441 if (*scale < kMinMagnifiedScaleThreshold)
442 *scale = kNonMagnifiedScale;
444 // Adjust the scale to just |kMinMagnifiedScale| if scale is bigger than
445 // |kMinMagnifiedScaleThreshold|;
446 if (*scale > kMaxMagnifiedScaleThreshold)
447 *scale = kMaxMagnifiedScale;
449 DCHECK(kNonMagnifiedScale <= *scale && *scale <= kMaxMagnifiedScale);
452 void MagnificationControllerImpl::OnImplicitAnimationsCompleted() {
453 if (!is_on_animation_)
454 return;
456 if (move_cursor_after_animation_) {
457 MoveCursorTo(root_window_->GetHost(), position_after_animation_);
458 move_cursor_after_animation_ = false;
460 aura::client::CursorClient* cursor_client =
461 aura::client::GetCursorClient(root_window_);
462 if (cursor_client)
463 cursor_client->EnableMouseEvents();
466 is_on_animation_ = false;
468 StartOrStopScrollIfNecessary();
471 void MagnificationControllerImpl::OnWindowDestroying(
472 aura::Window* root_window) {
473 if (root_window == root_window_) {
474 // There must be at least one root window because this controller is
475 // destroyed before the root windows get destroyed.
476 DCHECK(root_window);
478 aura::Window* target_root_window = Shell::GetTargetRootWindow();
479 CHECK(target_root_window);
481 // The destroyed root window must not be target.
482 CHECK_NE(target_root_window, root_window);
483 // Don't redraw the old root window as it's being destroyed.
484 SwitchTargetRootWindow(target_root_window, false);
485 point_of_interest_ = target_root_window->bounds().CenterPoint();
489 void MagnificationControllerImpl::OnWindowBoundsChanged(
490 aura::Window* window,
491 const gfx::Rect& old_bounds,
492 const gfx::Rect& new_bounds) {
493 // TODO(yoshiki): implement here. crbug.com/230979
496 ////////////////////////////////////////////////////////////////////////////////
497 // MagnificationControllerImpl: MagnificationController implementation
499 void MagnificationControllerImpl::SetScale(float scale, bool animate) {
500 if (!is_enabled_)
501 return;
503 ValidateScale(&scale);
504 Shell::GetInstance()->accessibility_delegate()->
505 SaveScreenMagnifierScale(scale);
506 RedrawKeepingMousePosition(scale, animate);
509 void MagnificationControllerImpl::MoveWindow(int x, int y, bool animate) {
510 if (!is_enabled_)
511 return;
513 Redraw(gfx::Point(x, y), scale_, animate);
516 void MagnificationControllerImpl::MoveWindow(const gfx::Point& point,
517 bool animate) {
518 if (!is_enabled_)
519 return;
521 Redraw(point, scale_, animate);
524 void MagnificationControllerImpl::SetScrollDirection(
525 ScrollDirection direction) {
526 scroll_direction_ = direction;
527 StartOrStopScrollIfNecessary();
530 void MagnificationControllerImpl::SetEnabled(bool enabled) {
531 Shell* shell = Shell::GetInstance();
532 if (enabled) {
533 if (!input_method_) {
534 input_method_ =
535 root_window_->GetProperty(aura::client::kRootWindowInputMethodKey);
536 if (input_method_)
537 input_method_->AddObserver(this);
540 float scale =
541 Shell::GetInstance()->accessibility_delegate()->
542 GetSavedScreenMagnifierScale();
543 if (scale <= 0.0f)
544 scale = kInitialMagnifiedScale;
545 ValidateScale(&scale);
547 // Do nothing, if already enabled with same scale.
548 if (is_enabled_ && scale == scale_)
549 return;
551 is_enabled_ = enabled;
552 RedrawKeepingMousePosition(scale, true);
553 shell->accessibility_delegate()->SaveScreenMagnifierScale(scale);
554 } else {
555 // Do nothing, if already disabled.
556 if (!is_enabled_)
557 return;
559 if (input_method_) {
560 input_method_->RemoveObserver(this);
561 input_method_ = NULL;
564 RedrawKeepingMousePosition(kNonMagnifiedScale, true);
565 is_enabled_ = enabled;
569 bool MagnificationControllerImpl::IsEnabled() const {
570 return is_enabled_;
573 ////////////////////////////////////////////////////////////////////////////////
574 // MagnificationControllerImpl: aura::EventFilter implementation
576 void MagnificationControllerImpl::OnMouseEvent(ui::MouseEvent* event) {
577 aura::Window* target = static_cast<aura::Window*>(event->target());
578 aura::Window* current_root = target->GetRootWindow();
579 gfx::Rect root_bounds = current_root->bounds();
581 if (root_bounds.Contains(event->root_location())) {
582 // This must be before |SwitchTargetRootWindow()|.
583 if (event->type() != ui::ET_MOUSE_CAPTURE_CHANGED)
584 point_of_interest_ = event->root_location();
586 if (current_root != root_window_) {
587 DCHECK(current_root);
588 SwitchTargetRootWindow(current_root, true);
591 if (IsMagnified() && event->type() == ui::ET_MOUSE_MOVED)
592 OnMouseMove(event->root_location());
596 void MagnificationControllerImpl::OnScrollEvent(ui::ScrollEvent* event) {
597 if (event->IsAltDown() && event->IsControlDown()) {
598 if (event->type() == ui::ET_SCROLL_FLING_START ||
599 event->type() == ui::ET_SCROLL_FLING_CANCEL) {
600 event->StopPropagation();
601 return;
604 if (event->type() == ui::ET_SCROLL) {
605 ui::ScrollEvent* scroll_event = static_cast<ui::ScrollEvent*>(event);
606 float scale = GetScale();
607 scale += scroll_event->y_offset() * kScrollScaleChangeFactor;
608 SetScale(scale, true);
609 event->StopPropagation();
610 return;
615 void MagnificationControllerImpl::OnTouchEvent(ui::TouchEvent* event) {
616 aura::Window* target = static_cast<aura::Window*>(event->target());
617 aura::Window* current_root = target->GetRootWindow();
618 if (current_root == root_window_) {
619 gfx::Rect root_bounds = current_root->bounds();
620 if (root_bounds.Contains(event->root_location()))
621 point_of_interest_ = event->root_location();
625 void MagnificationControllerImpl::MoveMagnifierWindowFollowPoint(
626 const gfx::Point& point,
627 int x_panning_margin,
628 int y_panning_margin,
629 int x_target_margin,
630 int y_target_margin) {
631 DCHECK(root_window_);
632 bool start_zoom = false;
634 const gfx::Rect window_rect = GetViewportRect();
635 const int left = window_rect.x();
636 const int right = window_rect.right();
638 int x_diff = 0;
639 if (point.x() < left + x_panning_margin) {
640 // Panning left.
641 x_diff = point.x() - (left + x_target_margin);
642 start_zoom = true;
643 } else if (right - x_panning_margin < point.x()) {
644 // Panning right.
645 x_diff = point.x() - (right - x_target_margin);
646 start_zoom = true;
648 int x = left + x_diff;
650 const int top = window_rect.y();
651 const int bottom = window_rect.bottom();
653 int y_diff = 0;
654 if (point.y() < top + y_panning_margin) {
655 // Panning up.
656 y_diff = point.y() - (top + y_target_margin);
657 start_zoom = true;
658 } else if (bottom - y_panning_margin < point.y()) {
659 // Panning down.
660 y_diff = point.y() - (bottom - y_target_margin);
661 start_zoom = true;
663 int y = top + y_diff;
664 if (start_zoom && !is_on_animation_) {
665 // No animation on panning.
666 bool animate = false;
667 bool ret = RedrawDIP(gfx::Point(x, y), scale_, animate);
669 if (ret) {
670 // If the magnified region is moved, hides the mouse cursor and moves it.
671 if (x_diff != 0 || y_diff != 0)
672 MoveCursorTo(root_window_->GetHost(), point);
677 void MagnificationControllerImpl::MoveMagnifierWindowFollowRect(
678 const gfx::Rect& rect) {
679 DCHECK(root_window_);
680 bool should_pan = false;
682 const gfx::Rect viewport_rect = GetViewportRect();
683 const int left = viewport_rect.x();
684 const int right = viewport_rect.right();
685 const gfx::Point rect_center = rect.CenterPoint();
686 const gfx::Point window_center = viewport_rect.CenterPoint();
688 int x = left;
689 if (rect.x() < left || right < rect.right()) {
690 // Panning horizontally.
691 x = rect_center.x() - viewport_rect.width() / 2;
692 should_pan = true;
695 const int top = viewport_rect.y();
696 const int bottom = viewport_rect.bottom();
698 int y = top;
699 if (rect.y() < top || bottom < rect.bottom()) {
700 // Panning vertically.
701 y = rect_center.y() - viewport_rect.height() / 2;
702 should_pan = true;
705 if (should_pan) {
706 if (is_on_animation_) {
707 root_window_->layer()->GetAnimator()->StopAnimating();
708 is_on_animation_ = false;
710 RedrawDIP(gfx::Point(x, y), scale_, false); // No animation on panning.
714 void MagnificationControllerImpl::OnCaretBoundsChanged(
715 const ui::TextInputClient* client) {
716 // caret bounds in screen coordinates.
717 const gfx::Rect caret_bounds = client->GetCaretBounds();
718 // Note: OnCaretBoundsChanged could be fired OnTextInputTypeChanged during
719 // which the caret position is not set a meaning position, and we do not
720 // need to adjust the view port position based on the bogus caret position.
721 // This is only a transition period, the caret position will be fixed upon
722 // focusing right after.
723 if (caret_bounds.width() == 0 && caret_bounds.height() == 0)
724 return;
726 gfx::Point caret_origin = caret_bounds.origin();
727 // caret_origin in |root_window_| coordinates.
728 wm::ConvertPointFromScreen(root_window_, &caret_origin);
730 // Visible window_rect in |root_window_| coordinates.
731 const gfx::Rect visible_window_rect = GetViewportRect();
733 const int panning_margin = kCaretPanningMargin / scale_;
734 MoveMagnifierWindowFollowPoint(caret_origin, panning_margin, panning_margin,
735 visible_window_rect.width() / 2,
736 visible_window_rect.height() / 2);
739 ////////////////////////////////////////////////////////////////////////////////
740 // MagnificationController:
742 // static
743 MagnificationController* MagnificationController::CreateInstance() {
744 return new MagnificationControllerImpl();
747 } // namespace ash