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
;
96 void SwitchTargetRootWindow(aura::Window
* new_root_window
,
97 bool redraw_original_root_window
) override
;
100 gfx::Point
GetPointOfInterestForTesting() override
{
101 return point_of_interest_
;
104 bool IsOnAnimationForTesting() const override
{ return is_on_animation_
; }
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,
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
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
,
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,
188 bool is_on_animation_
;
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.
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),
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() {
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()),
250 (scale_
/ scale
) * (mouse_in_root
.y() - origin_
.y()));
251 bool changed
= RedrawDIP(origin
, scale
, animate
);
253 AfterAnimationMoveCursorTo(mouse_in_root
);
256 bool MagnificationControllerImpl::Redraw(const gfx::PointF
& position
,
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
,
267 DCHECK(root_window_
);
269 float x
= position_in_dip
.x();
270 float y
= position_in_dip
.y();
272 ValidateScale(&scale
);
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();
288 // Does nothing if both the origin and the scale are not changed.
289 if (origin_
.x() == x
&&
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(
323 is_on_animation_
= 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();
337 gfx::PointF new_origin
= origin_
;
338 switch (scroll_direction_
) {
340 // No need to take action.
343 new_origin
.Offset(-kMoveOffset
, 0);
346 new_origin
.Offset(kMoveOffset
, 0);
349 new_origin
.Offset(0, -kMoveOffset
);
352 new_origin
.Offset(0, kMoveOffset
);
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
)
377 gfx::Rect node_bounds_in_root
=
378 ScreenUtil::ConvertRectFromScreen(root_window_
, node_bounds_in_screen
);
379 if (GetViewportRect().Contains(node_bounds_in_root
))
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_
)
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_
);
412 // When cursor is invisible, do not move or show the cursor after the
414 if (!cursor_client
->IsCursorVisible())
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_
)
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_
);
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.
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
) {
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
) {
513 Redraw(gfx::Point(x
, y
), scale_
, animate
);
516 void MagnificationControllerImpl::MoveWindow(const gfx::Point
& point
,
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();
533 if (!input_method_
) {
535 root_window_
->GetProperty(aura::client::kRootWindowInputMethodKey
);
537 input_method_
->AddObserver(this);
541 Shell::GetInstance()->accessibility_delegate()->
542 GetSavedScreenMagnifierScale();
544 scale
= kInitialMagnifiedScale
;
545 ValidateScale(&scale
);
547 // Do nothing, if already enabled with same scale.
548 if (is_enabled_
&& scale
== scale_
)
551 is_enabled_
= enabled
;
552 RedrawKeepingMousePosition(scale
, true);
553 shell
->accessibility_delegate()->SaveScreenMagnifierScale(scale
);
555 // Do nothing, if already disabled.
560 input_method_
->RemoveObserver(this);
561 input_method_
= NULL
;
564 RedrawKeepingMousePosition(kNonMagnifiedScale
, true);
565 is_enabled_
= enabled
;
569 bool MagnificationControllerImpl::IsEnabled() const {
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();
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();
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
,
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();
639 if (point
.x() < left
+ x_panning_margin
) {
641 x_diff
= point
.x() - (left
+ x_target_margin
);
643 } else if (right
- x_panning_margin
< point
.x()) {
645 x_diff
= point
.x() - (right
- x_target_margin
);
648 int x
= left
+ x_diff
;
650 const int top
= window_rect
.y();
651 const int bottom
= window_rect
.bottom();
654 if (point
.y() < top
+ y_panning_margin
) {
656 y_diff
= point
.y() - (top
+ y_target_margin
);
658 } else if (bottom
- y_panning_margin
< point
.y()) {
660 y_diff
= point
.y() - (bottom
- y_target_margin
);
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
);
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();
689 if (rect
.x() < left
|| right
< rect
.right()) {
690 // Panning horizontally.
691 x
= rect_center
.x() - viewport_rect
.width() / 2;
695 const int top
= viewport_rect
.y();
696 const int bottom
= viewport_rect
.bottom();
699 if (rect
.y() < top
|| bottom
< rect
.bottom()) {
700 // Panning vertically.
701 y
= rect_center
.y() - viewport_rect
.height() / 2;
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)
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:
743 MagnificationController
* MagnificationController::CreateInstance() {
744 return new MagnificationControllerImpl();