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"
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()));
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
{
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
;
98 gfx::Point
GetPointOfInterestForTesting() override
{
99 return point_of_interest_
;
102 bool IsOnAnimationForTesting() const override
{ return is_on_animation_
; }
105 // ui::ImplicitAnimationObserver overrides:
106 void OnImplicitAnimationsCompleted() override
;
108 // aura::WindowObserver overrides:
109 void OnWindowDestroying(aura::Window
* root_window
) override
;
110 void OnWindowBoundsChanged(aura::Window
* window
,
111 const gfx::Rect
& old_bounds
,
112 const gfx::Rect
& new_bounds
) override
;
114 // Redraws the magnification window with the given origin position and the
115 // given scale. Returns true if the window is changed; otherwise, false.
116 // These methods should be called internally just after the scale and/or
117 // the position are changed to redraw the window.
118 bool Redraw(const gfx::PointF
& position
, float scale
, bool animate
);
119 bool RedrawDIP(const gfx::PointF
& position
, float scale
, bool animate
);
121 // 1) If the screen is scrolling (i.e. animating) and should scroll further,
123 // 2) If the screen is scrolling (i.e. animating) and the direction is NONE,
124 // it stops the scrolling animation.
125 // 3) If the direction is set to value other than NONE, it starts the
126 // scrolling/ animation towards that direction.
127 void StartOrStopScrollIfNecessary();
129 // Redraw with the given zoom scale keeping the mouse cursor location. In
130 // other words, zoom (or unzoom) centering around the cursor.
131 void RedrawKeepingMousePosition(float scale
, bool animate
);
133 void OnMouseMove(const gfx::Point
& location
);
135 // Move the mouse cursot to the given point. Actual move will be done when
136 // the animation is completed. This should be called after animation is
138 void AfterAnimationMoveCursorTo(const gfx::Point
& location
);
140 // Switch Magnified RootWindow to |new_root_window|. This does following:
141 // - Unzoom the current root_window.
142 // - Zoom the given new root_window |new_root_window|.
143 // - Switch the target window from current window to |new_root_window|.
144 void SwitchTargetRootWindow(aura::Window
* new_root_window
,
145 bool redraw_original_root_window
);
147 // Returns if the magnification scale is 1.0 or not (larger then 1.0).
148 bool IsMagnified() const;
150 // Returns the rect of the magnification window.
151 gfx::RectF
GetWindowRectDIP(float scale
) const;
152 // Returns the size of the root window.
153 gfx::Size
GetHostSizeDIP() const;
155 // Correct the given scale value if necessary.
156 void ValidateScale(float* scale
);
158 // ui::EventHandler overrides:
159 void OnMouseEvent(ui::MouseEvent
* event
) override
;
160 void OnScrollEvent(ui::ScrollEvent
* event
) override
;
161 void OnTouchEvent(ui::TouchEvent
* event
) override
;
163 // Moves the view port when |point| is located within
164 // |x_panning_margin| and |y_pannin_margin| to the edge of the visible
165 // window region. The view port will be moved so that the |point| will be
166 // moved to the point where it has |x_target_margin| and |y_target_margin|
167 // to the edge of the visible region.
168 void MoveMagnifierWindowFollowPoint(const gfx::Point
& point
,
169 int x_panning_margin
,
170 int y_panning_margin
,
172 int y_target_margin
);
174 // Moves the viewport so that |rect| is fully visible. If |rect| is larger
175 // than the viewport horizontally or vertically, the viewport will be moved
176 // to center the |rect| in that dimension.
177 void MoveMagnifierWindowFollowRect(const gfx::Rect
& rect
);
179 // ui::InputMethodObserver:
180 void OnTextInputTypeChanged(const ui::TextInputClient
* client
) override
{}
181 void OnFocus() override
{}
182 void OnBlur() override
{}
183 void OnTextInputStateChanged(const ui::TextInputClient
* client
) override
{}
184 void OnInputMethodDestroyed(const ui::InputMethod
* input_method
) override
{}
185 void OnShowImeIfNeeded() override
{}
186 void OnCaretBoundsChanged(const ui::TextInputClient
* client
) override
;
188 // Target root window. This must not be NULL.
189 aura::Window
* root_window_
;
191 // True if the magnified window is currently animating a change. Otherwise,
193 bool is_on_animation_
;
197 // True if the cursor needs to move the given position after the animation
198 // will be finished. When using this, set |position_after_animation_| as well.
199 bool move_cursor_after_animation_
;
200 // Stores the position of cursor to be moved after animation.
201 gfx::Point position_after_animation_
;
203 // Stores the last mouse cursor (or last touched) location. This value is
204 // used on zooming to keep this location visible.
205 gfx::Point point_of_interest_
;
207 // Current scale, origin (left-top) position of the magnification window.
211 ScrollDirection scroll_direction_
;
213 ui::InputMethod
* input_method_
; // Not owned.
215 DISALLOW_COPY_AND_ASSIGN(MagnificationControllerImpl
);
218 ////////////////////////////////////////////////////////////////////////////////
219 // MagnificationControllerImpl:
221 MagnificationControllerImpl::MagnificationControllerImpl()
222 : root_window_(Shell::GetPrimaryRootWindow()),
223 is_on_animation_(false),
225 move_cursor_after_animation_(false),
226 scale_(kNonMagnifiedScale
),
227 scroll_direction_(SCROLL_NONE
),
228 input_method_(NULL
) {
229 Shell::GetInstance()->AddPreTargetHandler(this);
230 root_window_
->AddObserver(this);
231 point_of_interest_
= root_window_
->bounds().CenterPoint();
234 MagnificationControllerImpl::~MagnificationControllerImpl() {
236 input_method_
->RemoveObserver(this);
238 root_window_
->RemoveObserver(this);
240 Shell::GetInstance()->RemovePreTargetHandler(this);
243 void MagnificationControllerImpl::RedrawKeepingMousePosition(
244 float scale
, bool animate
) {
245 gfx::Point mouse_in_root
= point_of_interest_
;
247 // mouse_in_root is invalid value when the cursor is hidden.
248 if (!root_window_
->bounds().Contains(mouse_in_root
))
249 mouse_in_root
= root_window_
->bounds().CenterPoint();
251 const gfx::PointF origin
=
252 gfx::PointF(mouse_in_root
.x() -
253 (scale_
/ scale
) * (mouse_in_root
.x() - origin_
.x()),
255 (scale_
/ scale
) * (mouse_in_root
.y() - origin_
.y()));
256 bool changed
= RedrawDIP(origin
, scale
, animate
);
258 AfterAnimationMoveCursorTo(mouse_in_root
);
261 bool MagnificationControllerImpl::Redraw(const gfx::PointF
& position
,
264 const gfx::PointF position_in_dip
=
265 ui::ConvertPointToDIP(root_window_
->layer(), position
);
266 return RedrawDIP(position_in_dip
, scale
, animate
);
269 bool MagnificationControllerImpl::RedrawDIP(const gfx::PointF
& position_in_dip
,
272 DCHECK(root_window_
);
274 float x
= position_in_dip
.x();
275 float y
= position_in_dip
.y();
277 ValidateScale(&scale
);
284 const gfx::Size host_size_in_dip
= GetHostSizeDIP();
285 const gfx::SizeF window_size_in_dip
= GetWindowRectDIP(scale
).size();
286 float max_x
= host_size_in_dip
.width() - window_size_in_dip
.width();
287 float max_y
= host_size_in_dip
.height() - window_size_in_dip
.height();
293 // Does nothing if both the origin and the scale are not changed.
294 if (origin_
.x() == x
&&
304 // Creates transform matrix.
305 gfx::Transform transform
;
306 // Flips the signs intentionally to convert them from the position of the
307 // magnification window.
308 transform
.Scale(scale_
, scale_
);
309 transform
.Translate(-origin_
.x(), -origin_
.y());
311 ui::ScopedLayerAnimationSettings
settings(
312 root_window_
->layer()->GetAnimator());
313 settings
.AddObserver(this);
314 settings
.SetPreemptionStrategy(
315 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET
);
316 settings
.SetTweenType(gfx::Tween::EASE_OUT
);
317 settings
.SetTransitionDuration(
318 base::TimeDelta::FromMilliseconds(animate
? 100 : 0));
320 gfx::Display display
=
321 Shell::GetScreen()->GetDisplayNearestWindow(root_window_
);
322 scoped_ptr
<RootWindowTransformer
> transformer(
323 CreateRootWindowTransformerForDisplay(root_window_
, display
));
324 GetRootWindowController(root_window_
)->ash_host()->SetRootWindowTransformer(
328 is_on_animation_
= true;
333 void MagnificationControllerImpl::StartOrStopScrollIfNecessary() {
334 // This value controls the scrolling speed.
335 const int kMoveOffset
= 40;
336 if (is_on_animation_
) {
337 if (scroll_direction_
== SCROLL_NONE
)
338 root_window_
->layer()->GetAnimator()->StopAnimating();
342 gfx::PointF new_origin
= origin_
;
343 switch (scroll_direction_
) {
345 // No need to take action.
348 new_origin
.Offset(-kMoveOffset
, 0);
351 new_origin
.Offset(kMoveOffset
, 0);
354 new_origin
.Offset(0, -kMoveOffset
);
357 new_origin
.Offset(0, kMoveOffset
);
360 RedrawDIP(new_origin
, scale_
, true);
363 void MagnificationControllerImpl::OnMouseMove(const gfx::Point
& location
) {
364 DCHECK(root_window_
);
366 gfx::Point
mouse(location
);
367 int margin
= kPanningMergin
/ scale_
; // No need to consider DPI.
368 MoveMagnifierWindowFollowPoint(mouse
, margin
, margin
, margin
, margin
);
371 gfx::Rect
MagnificationControllerImpl::GetViewportRect() const {
372 return gfx::ToEnclosingRect(GetWindowRectDIP(scale_
));
375 void MagnificationControllerImpl::HandleFocusedNodeChanged(
376 bool is_editable_node
,
377 const gfx::Rect
& node_bounds_in_screen
) {
378 // The editable node is handled by OnCaretBoundsChanged.
379 if (is_editable_node
)
382 gfx::Rect node_bounds_in_root
=
383 ScreenUtil::ConvertRectFromScreen(root_window_
, node_bounds_in_screen
);
384 if (GetViewportRect().Contains(node_bounds_in_root
))
387 MoveMagnifierWindowFollowRect(node_bounds_in_root
);
390 void MagnificationControllerImpl::AfterAnimationMoveCursorTo(
391 const gfx::Point
& location
) {
392 DCHECK(root_window_
);
394 aura::client::CursorClient
* cursor_client
=
395 aura::client::GetCursorClient(root_window_
);
397 // When cursor is invisible, do not move or show the cursor after the
399 if (!cursor_client
->IsCursorVisible())
401 cursor_client
->DisableMouseEvents();
403 move_cursor_after_animation_
= true;
404 position_after_animation_
= location
;
407 gfx::Size
MagnificationControllerImpl::GetHostSizeDIP() const {
408 return root_window_
->bounds().size();
411 gfx::RectF
MagnificationControllerImpl::GetWindowRectDIP(float scale
) const {
412 const gfx::Size size_in_dip
= root_window_
->bounds().size();
413 const float width
= size_in_dip
.width() / scale
;
414 const float height
= size_in_dip
.height() / scale
;
416 return gfx::RectF(origin_
.x(), origin_
.y(), width
, height
);
419 bool MagnificationControllerImpl::IsMagnified() const {
420 return scale_
>= kMinMagnifiedScaleThreshold
;
423 void MagnificationControllerImpl::ValidateScale(float* scale
) {
424 // Adjust the scale to just |kNonMagnifiedScale| if scale is smaller than
425 // |kMinMagnifiedScaleThreshold|;
426 if (*scale
< kMinMagnifiedScaleThreshold
)
427 *scale
= kNonMagnifiedScale
;
429 // Adjust the scale to just |kMinMagnifiedScale| if scale is bigger than
430 // |kMinMagnifiedScaleThreshold|;
431 if (*scale
> kMaxMagnifiedScaleThreshold
)
432 *scale
= kMaxMagnifiedScale
;
434 DCHECK(kNonMagnifiedScale
<= *scale
&& *scale
<= kMaxMagnifiedScale
);
437 void MagnificationControllerImpl::OnImplicitAnimationsCompleted() {
438 if (!is_on_animation_
)
441 if (move_cursor_after_animation_
) {
442 MoveCursorTo(root_window_
->GetHost(), position_after_animation_
);
443 move_cursor_after_animation_
= false;
445 aura::client::CursorClient
* cursor_client
=
446 aura::client::GetCursorClient(root_window_
);
448 cursor_client
->EnableMouseEvents();
451 is_on_animation_
= false;
453 StartOrStopScrollIfNecessary();
456 void MagnificationControllerImpl::OnWindowDestroying(
457 aura::Window
* root_window
) {
458 if (root_window
== root_window_
) {
459 // There must be at least one root window because this controller is
460 // destroyed before the root windows get destroyed.
463 aura::Window
* target_root_window
= Shell::GetTargetRootWindow();
464 CHECK(target_root_window
);
466 // The destroyed root window must not be target.
467 CHECK_NE(target_root_window
, root_window
);
468 // Don't redraw the old root window as it's being destroyed.
469 SwitchTargetRootWindow(target_root_window
, false);
470 point_of_interest_
= target_root_window
->bounds().CenterPoint();
474 void MagnificationControllerImpl::OnWindowBoundsChanged(
475 aura::Window
* window
,
476 const gfx::Rect
& old_bounds
,
477 const gfx::Rect
& new_bounds
) {
478 // TODO(yoshiki): implement here. crbug.com/230979
481 void MagnificationControllerImpl::SwitchTargetRootWindow(
482 aura::Window
* new_root_window
,
483 bool redraw_original_root_window
) {
484 DCHECK(new_root_window
);
486 if (new_root_window
== root_window_
)
489 // Stores the previous scale.
490 float scale
= GetScale();
492 // Unmagnify the previous root window.
493 root_window_
->RemoveObserver(this);
494 if (redraw_original_root_window
)
495 RedrawKeepingMousePosition(1.0f
, true);
497 root_window_
= new_root_window
;
498 RedrawKeepingMousePosition(scale
, true);
499 root_window_
->AddObserver(this);
502 ////////////////////////////////////////////////////////////////////////////////
503 // MagnificationControllerImpl: MagnificationController implementation
505 void MagnificationControllerImpl::SetScale(float scale
, bool animate
) {
509 ValidateScale(&scale
);
510 Shell::GetInstance()->accessibility_delegate()->
511 SaveScreenMagnifierScale(scale
);
512 RedrawKeepingMousePosition(scale
, animate
);
515 void MagnificationControllerImpl::MoveWindow(int x
, int y
, bool animate
) {
519 Redraw(gfx::Point(x
, y
), scale_
, animate
);
522 void MagnificationControllerImpl::MoveWindow(const gfx::Point
& point
,
527 Redraw(point
, scale_
, animate
);
530 void MagnificationControllerImpl::SetScrollDirection(
531 ScrollDirection direction
) {
532 scroll_direction_
= direction
;
533 StartOrStopScrollIfNecessary();
536 void MagnificationControllerImpl::SetEnabled(bool enabled
) {
537 Shell
* shell
= Shell::GetInstance();
539 if (!input_method_
) {
541 root_window_
->GetProperty(aura::client::kRootWindowInputMethodKey
);
543 input_method_
->AddObserver(this);
547 Shell::GetInstance()->accessibility_delegate()->
548 GetSavedScreenMagnifierScale();
550 scale
= kInitialMagnifiedScale
;
551 ValidateScale(&scale
);
553 // Do nothing, if already enabled with same scale.
554 if (is_enabled_
&& scale
== scale_
)
557 is_enabled_
= enabled
;
558 RedrawKeepingMousePosition(scale
, true);
559 shell
->accessibility_delegate()->SaveScreenMagnifierScale(scale
);
561 // Do nothing, if already disabled.
566 input_method_
->RemoveObserver(this);
567 input_method_
= NULL
;
570 RedrawKeepingMousePosition(kNonMagnifiedScale
, true);
571 is_enabled_
= enabled
;
575 bool MagnificationControllerImpl::IsEnabled() const {
579 ////////////////////////////////////////////////////////////////////////////////
580 // MagnificationControllerImpl: aura::EventFilter implementation
582 void MagnificationControllerImpl::OnMouseEvent(ui::MouseEvent
* event
) {
583 aura::Window
* target
= static_cast<aura::Window
*>(event
->target());
584 aura::Window
* current_root
= target
->GetRootWindow();
585 gfx::Rect root_bounds
= current_root
->bounds();
587 if (root_bounds
.Contains(event
->root_location())) {
588 // This must be before |SwitchTargetRootWindow()|.
589 if (event
->type() != ui::ET_MOUSE_CAPTURE_CHANGED
)
590 point_of_interest_
= event
->root_location();
592 if (current_root
!= root_window_
) {
593 DCHECK(current_root
);
594 SwitchTargetRootWindow(current_root
, true);
597 if (IsMagnified() && event
->type() == ui::ET_MOUSE_MOVED
)
598 OnMouseMove(event
->root_location());
602 void MagnificationControllerImpl::OnScrollEvent(ui::ScrollEvent
* event
) {
603 if (event
->IsAltDown() && event
->IsControlDown()) {
604 if (event
->type() == ui::ET_SCROLL_FLING_START
||
605 event
->type() == ui::ET_SCROLL_FLING_CANCEL
) {
606 event
->StopPropagation();
610 if (event
->type() == ui::ET_SCROLL
) {
611 ui::ScrollEvent
* scroll_event
= static_cast<ui::ScrollEvent
*>(event
);
612 float scale
= GetScale();
613 scale
+= scroll_event
->y_offset() * kScrollScaleChangeFactor
;
614 SetScale(scale
, true);
615 event
->StopPropagation();
621 void MagnificationControllerImpl::OnTouchEvent(ui::TouchEvent
* event
) {
622 aura::Window
* target
= static_cast<aura::Window
*>(event
->target());
623 aura::Window
* current_root
= target
->GetRootWindow();
624 if (current_root
== root_window_
) {
625 gfx::Rect root_bounds
= current_root
->bounds();
626 if (root_bounds
.Contains(event
->root_location()))
627 point_of_interest_
= event
->root_location();
631 void MagnificationControllerImpl::MoveMagnifierWindowFollowPoint(
632 const gfx::Point
& point
,
633 int x_panning_margin
,
634 int y_panning_margin
,
636 int y_target_margin
) {
637 DCHECK(root_window_
);
638 bool start_zoom
= false;
640 const gfx::Rect window_rect
= GetViewportRect();
641 const int left
= window_rect
.x();
642 const int right
= window_rect
.right();
645 if (point
.x() < left
+ x_panning_margin
) {
647 x_diff
= point
.x() - (left
+ x_target_margin
);
649 } else if (right
- x_panning_margin
< point
.x()) {
651 x_diff
= point
.x() - (right
- x_target_margin
);
654 int x
= left
+ x_diff
;
656 const int top
= window_rect
.y();
657 const int bottom
= window_rect
.bottom();
660 if (point
.y() < top
+ y_panning_margin
) {
662 y_diff
= point
.y() - (top
+ y_target_margin
);
664 } else if (bottom
- y_panning_margin
< point
.y()) {
666 y_diff
= point
.y() - (bottom
- y_target_margin
);
669 int y
= top
+ y_diff
;
670 if (start_zoom
&& !is_on_animation_
) {
671 // No animation on panning.
672 bool animate
= false;
673 bool ret
= RedrawDIP(gfx::Point(x
, y
), scale_
, animate
);
676 // If the magnified region is moved, hides the mouse cursor and moves it.
677 if (x_diff
!= 0 || y_diff
!= 0)
678 MoveCursorTo(root_window_
->GetHost(), point
);
683 void MagnificationControllerImpl::MoveMagnifierWindowFollowRect(
684 const gfx::Rect
& rect
) {
685 DCHECK(root_window_
);
686 bool should_pan
= false;
688 const gfx::Rect viewport_rect
= GetViewportRect();
689 const int left
= viewport_rect
.x();
690 const int right
= viewport_rect
.right();
691 const gfx::Point rect_center
= rect
.CenterPoint();
692 const gfx::Point window_center
= viewport_rect
.CenterPoint();
695 if (rect
.x() < left
|| right
< rect
.right()) {
696 // Panning horizontally.
697 x
= rect_center
.x() - viewport_rect
.width() / 2;
701 const int top
= viewport_rect
.y();
702 const int bottom
= viewport_rect
.bottom();
705 if (rect
.y() < top
|| bottom
< rect
.bottom()) {
706 // Panning vertically.
707 y
= rect_center
.y() - viewport_rect
.height() / 2;
712 if (is_on_animation_
) {
713 root_window_
->layer()->GetAnimator()->StopAnimating();
714 is_on_animation_
= false;
716 RedrawDIP(gfx::Point(x
, y
), scale_
, false); // No animation on panning.
720 void MagnificationControllerImpl::OnCaretBoundsChanged(
721 const ui::TextInputClient
* client
) {
722 // caret bounds in screen coordinates.
723 const gfx::Rect caret_bounds
= client
->GetCaretBounds();
724 // Note: OnCaretBoundsChanged could be fired OnTextInputTypeChanged during
725 // which the caret position is not set a meaning position, and we do not
726 // need to adjust the view port position based on the bogus caret position.
727 // This is only a transition period, the caret position will be fixed upon
728 // focusing right after.
729 if (caret_bounds
.width() == 0 && caret_bounds
.height() == 0)
732 gfx::Point caret_origin
= caret_bounds
.origin();
733 // caret_origin in |root_window_| coordinates.
734 wm::ConvertPointFromScreen(root_window_
, &caret_origin
);
736 // Visible window_rect in |root_window_| coordinates.
737 const gfx::Rect visible_window_rect
= GetViewportRect();
739 const int panning_margin
= kCaretPanningMargin
/ scale_
;
740 MoveMagnifierWindowFollowPoint(caret_origin
, panning_margin
, panning_margin
,
741 visible_window_rect
.width() / 2,
742 visible_window_rect
.height() / 2);
745 ////////////////////////////////////////////////////////////////////////////////
746 // MagnificationController:
749 MagnificationController
* MagnificationController::CreateInstance() {
750 return new MagnificationControllerImpl();