OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "ash/magnifier/magnification_controller.h" | 5 #include "ash/magnifier/magnification_controller.h" |
6 | 6 |
7 #include "ash/shell.h" | 7 #include "ash/shell.h" |
| 8 #include "ui/aura/event.h" |
| 9 #include "ui/aura/event_filter.h" |
8 #include "ui/aura/root_window.h" | 10 #include "ui/aura/root_window.h" |
| 11 #include "ui/aura/shared/compound_event_filter.h" |
9 #include "ui/aura/window.h" | 12 #include "ui/aura/window.h" |
10 #include "ui/aura/window_property.h" | 13 #include "ui/aura/window_property.h" |
| 14 #include "ui/gfx/point3.h" |
| 15 #include "ui/compositor/dip_util.h" |
11 #include "ui/compositor/layer.h" | 16 #include "ui/compositor/layer.h" |
| 17 #include "ui/compositor/layer_animation_observer.h" |
12 #include "ui/compositor/scoped_layer_animation_settings.h" | 18 #include "ui/compositor/scoped_layer_animation_settings.h" |
13 | 19 |
14 namespace { | 20 namespace { |
15 | 21 |
16 const float kMaximumMagnifiScale = 4.0f; | 22 const float kMaximumMagnifiScale = 4.0f; |
17 const float kMaximumMagnifiScaleThreshold = 4.0f; | 23 const float kMaximumMagnifiScaleThreshold = 4.0f; |
18 const float kMinimumMagnifiScale = 1.0f; | 24 const float kMinimumMagnifiScale = 1.0f; |
19 const float kMinimumMagnifiScaleThreshold = 1.1f; | 25 const float kMinimumMagnifiScaleThreshold = 1.1f; |
20 | 26 |
21 } // namespace | 27 } // namespace |
22 | 28 |
23 namespace ash { | 29 namespace ash { |
24 namespace internal { | 30 namespace internal { |
25 | 31 |
26 MagnificationController::MagnificationController() | 32 //////////////////////////////////////////////////////////////////////////////// |
27 : scale_(1.0f), x_(0), y_(0) { | 33 // MagnificationControllerImpl: |
28 root_window_ = ash::Shell::GetPrimaryRootWindow(); | 34 |
29 } | 35 class MagnificationControllerImpl : virtual public MagnificationController, |
30 | 36 public aura::EventFilter, |
31 void MagnificationController::SetScale(float scale) { | 37 public ui::ImplicitAnimationObserver { |
| 38 public: |
| 39 MagnificationControllerImpl(); |
| 40 virtual ~MagnificationControllerImpl(); |
| 41 |
| 42 // MagnificationController overrides: |
| 43 virtual void SetScale(float scale, bool animate) OVERRIDE; |
| 44 virtual float GetScale() const OVERRIDE { return scale_; } |
| 45 virtual void MoveWindow(int x, int y, bool animate) OVERRIDE; |
| 46 virtual void MoveWindow(const gfx::Point& point, bool animate) OVERRIDE; |
| 47 virtual gfx::Point GetWindowPosition() const OVERRIDE { return origin_; } |
| 48 virtual void EnsureRectIsVisible(const gfx::Rect& rect, |
| 49 bool animate) OVERRIDE; |
| 50 virtual void EnsurePointIsVisible(const gfx::Point& point, |
| 51 bool animate) OVERRIDE; |
| 52 |
| 53 private: |
| 54 // ui::ImplicitAnimationObserver overrides: |
| 55 virtual void OnImplicitAnimationsCompleted() OVERRIDE; |
| 56 |
| 57 // Redraws the magnification window with the given origin position and the |
| 58 // given scale. Returns true if the window is changed; otherwise, false. |
| 59 // These methods should be called internally just after the scale and/or |
| 60 // the position are changed to redraw the window. |
| 61 bool Redraw(const gfx::Point& position, float scale, bool animate); |
| 62 bool RedrawDIP(const gfx::Point& position, float scale, bool animate); |
| 63 |
| 64 // Ensures that the given point, rect or last mouse location is inside |
| 65 // magnification window. If not, the controller moves the window to contain |
| 66 // the given point/rect. |
| 67 void EnsureRectIsVisibleWithScale(const gfx::Rect& target_rect, |
| 68 float scale, |
| 69 bool animate); |
| 70 void EnsureRectIsVisibleDIP(const gfx::Rect& target_rect_in_dip, |
| 71 float scale, |
| 72 bool animate); |
| 73 void EnsurePointIsVisibleWithScale(const gfx::Point& point, |
| 74 float scale, |
| 75 bool animate); |
| 76 void OnMouseMove(const gfx::Point& location); |
| 77 |
| 78 // Returns if the magnification scale is 1.0 or not (larger then 1.0). |
| 79 bool IsMagnified() const; |
| 80 |
| 81 // Returns the rect of the magnification window. |
| 82 gfx::Rect GetWindowRectDIP(float scale) const; |
| 83 // Returns the size of the root window. |
| 84 gfx::Size GetHostSizeDIP() const; |
| 85 |
| 86 // Correct the givin scale value if nessesary. |
| 87 void ValidateScale(float* scale); |
| 88 |
| 89 // aura::EventFilter overrides: |
| 90 virtual bool PreHandleKeyEvent(aura::Window* target, |
| 91 aura::KeyEvent* event) OVERRIDE; |
| 92 virtual bool PreHandleMouseEvent(aura::Window* target, |
| 93 aura::MouseEvent* event) OVERRIDE; |
| 94 virtual ui::TouchStatus PreHandleTouchEvent(aura::Window* target, |
| 95 aura::TouchEvent* event) OVERRIDE; |
| 96 virtual ui::GestureStatus PreHandleGestureEvent( |
| 97 aura::Window* target, |
| 98 aura::GestureEvent* event) OVERRIDE; |
| 99 |
| 100 aura::RootWindow* root_window_; |
| 101 |
| 102 // True if the magnified window is in motion of zooming or un-zooming effect. |
| 103 // Otherwise, false. |
| 104 bool is_on_zooming_; |
| 105 |
| 106 // Current scale, origin (left-top) position of the magnification window. |
| 107 float scale_; |
| 108 gfx::Point origin_; |
| 109 |
| 110 DISALLOW_COPY_AND_ASSIGN(MagnificationControllerImpl); |
| 111 }; |
| 112 |
| 113 //////////////////////////////////////////////////////////////////////////////// |
| 114 // MagnificationControllerImpl: |
| 115 |
| 116 MagnificationControllerImpl::MagnificationControllerImpl() |
| 117 : root_window_(ash::Shell::GetPrimaryRootWindow()), |
| 118 is_on_zooming_(false), |
| 119 scale_(1.0f) { |
| 120 Shell::GetInstance()->AddEnvEventFilter(this); |
| 121 } |
| 122 |
| 123 MagnificationControllerImpl::~MagnificationControllerImpl() { |
| 124 Shell::GetInstance()->RemoveEnvEventFilter(this); |
| 125 } |
| 126 |
| 127 bool MagnificationControllerImpl::Redraw(const gfx::Point& position, |
| 128 float scale, |
| 129 bool animate) { |
| 130 const gfx::Point position_in_dip = |
| 131 ui::ConvertPointToDIP(root_window_->layer(), position); |
| 132 return RedrawDIP(position_in_dip, scale, animate); |
| 133 } |
| 134 |
| 135 bool MagnificationControllerImpl::RedrawDIP(const gfx::Point& position_in_dip, |
| 136 float scale, |
| 137 bool animate) { |
| 138 int x = position_in_dip.x(); |
| 139 int y = position_in_dip.y(); |
| 140 |
| 141 ValidateScale(&scale); |
| 142 |
| 143 if (x < 0) |
| 144 x = 0; |
| 145 if (y < 0) |
| 146 y = 0; |
| 147 |
| 148 const gfx::Size host_size_in_dip = GetHostSizeDIP(); |
| 149 const gfx::Size window_size_in_dip = GetWindowRectDIP(scale).size(); |
| 150 int max_x = host_size_in_dip.width() - window_size_in_dip.width(); |
| 151 int max_y = host_size_in_dip.height() - window_size_in_dip.height(); |
| 152 if (x > max_x) |
| 153 x = max_x; |
| 154 if (y > max_y) |
| 155 y = max_y; |
| 156 |
| 157 // Ignores 1 px diffirence because it may be error on calculation. |
| 158 if (std::abs(origin_.x() - x) <= 1 && |
| 159 std::abs(origin_.y() - y) <= 1 && |
| 160 scale == scale_) |
| 161 return false; |
| 162 |
| 163 origin_.set_x(x); |
| 164 origin_.set_y(y); |
32 scale_ = scale; | 165 scale_ = scale; |
33 RedrawScreen(true); | |
34 } | |
35 | |
36 void MagnificationController::MoveWindow(int x, int y) { | |
37 y_ = y; | |
38 x_ = x; | |
39 RedrawScreen(true); | |
40 } | |
41 | |
42 void MagnificationController::MoveWindow(const gfx::Point& point) { | |
43 MoveWindow(point.x(), point.y()); | |
44 } | |
45 | |
46 void MagnificationController::EnsureShowRect(const gfx::Rect& target_rect) { | |
47 gfx::Rect rect = GetWindowRect().AdjustToFit(target_rect); | |
48 MoveWindow(rect.x(), rect.y()); | |
49 } | |
50 | |
51 void MagnificationController::EnsureShowPoint(const gfx::Point& point, | |
52 bool animation) { | |
53 gfx::Rect rect = GetWindowRect(); | |
54 | |
55 if (rect.Contains(point)) | |
56 return; | |
57 | |
58 if (point.x() < rect.x()) | |
59 x_ = point.x(); | |
60 else if(rect.right() < point.x()) | |
61 x_ = point.x() - rect.width(); | |
62 | |
63 if (point.y() < rect.y()) | |
64 y_ = point.y(); | |
65 else if(rect.bottom() < point.y()) | |
66 y_ = point.y() - rect.height(); | |
67 | |
68 RedrawScreen(animation); | |
69 } | |
70 | |
71 void MagnificationController::RedrawScreen(bool animation) { | |
72 | |
73 // Adjust the scale to just |kMinimumMagnifiScale| if scale is smaller than | |
74 // |kMinimumMagnifiScaleThreshold|; | |
75 if (scale_ < kMinimumMagnifiScaleThreshold) | |
76 scale_ = kMinimumMagnifiScale; | |
77 // Adjust the scale to just |kMinimumMagnifiScale| if scale is bigger than | |
78 // |kMinimumMagnifiScaleThreshold|; | |
79 if (scale_ > kMaximumMagnifiScaleThreshold) | |
80 scale_ = kMaximumMagnifiScale; | |
81 | |
82 if (x_ < 0) | |
83 x_ = 0; | |
84 if (y_ < 0) | |
85 y_ = 0; | |
86 | |
87 gfx::Size host_size = root_window_->GetHostSize(); | |
88 gfx::Size window_size = GetWindowRect().size(); | |
89 int max_x = host_size.width() - window_size.width(); | |
90 int max_y = host_size.height() - window_size.height(); | |
91 if (x_ > max_x) | |
92 x_ = max_x; | |
93 if (y_ > max_y) | |
94 y_ = max_y; | |
95 | |
96 | |
97 float scale = scale_; | |
98 int x = x_; | |
99 int y = y_; | |
100 | 166 |
101 // Creates transform matrix. | 167 // Creates transform matrix. |
102 ui::Transform transform; | 168 ui::Transform transform; |
103 // Flips the signs intentionally to convert them from the position of the | 169 // Flips the signs intentionally to convert them from the position of the |
104 // magnification window. | 170 // magnification window. |
105 transform.ConcatTranslate(-x, -y); | 171 transform.ConcatTranslate(-origin_.x(), -origin_.y()); |
106 transform.ConcatScale(scale, scale); | 172 transform.ConcatScale(scale_, scale_); |
107 | 173 |
108 if (animation) { | 174 ui::ScopedLayerAnimationSettings settings( |
109 ui::ScopedLayerAnimationSettings settings( | 175 root_window_->layer()->GetAnimator()); |
110 root_window_->layer()->GetAnimator()); | 176 settings.AddObserver(this); |
111 settings.SetPreemptionStrategy( | 177 settings.SetPreemptionStrategy( |
112 ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); | 178 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
113 settings.SetTweenType(ui::Tween::EASE_IN_OUT); | 179 settings.SetTweenType(ui::Tween::EASE_OUT); |
114 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(100)); | 180 settings.SetTransitionDuration( |
| 181 base::TimeDelta::FromMilliseconds(animate ? 100 : 0)); |
| 182 |
| 183 root_window_->layer()->SetTransform(transform); |
| 184 |
| 185 return true; |
| 186 } |
| 187 |
| 188 void MagnificationControllerImpl::EnsureRectIsVisibleWithScale( |
| 189 const gfx::Rect& target_rect, |
| 190 float scale, |
| 191 bool animate) { |
| 192 const gfx::Rect target_rect_in_dip = |
| 193 ui::ConvertRectToDIP(root_window_->layer(), target_rect); |
| 194 EnsureRectIsVisibleDIP(target_rect_in_dip, scale, animate); |
| 195 } |
| 196 |
| 197 void MagnificationControllerImpl::EnsureRectIsVisibleDIP( |
| 198 const gfx::Rect& target_rect, |
| 199 float scale, |
| 200 bool animate) { |
| 201 ValidateScale(&scale); |
| 202 |
| 203 const gfx::Rect window_rect = GetWindowRectDIP(scale); |
| 204 if (scale == scale_ && window_rect.Contains(target_rect)) |
| 205 return; |
| 206 |
| 207 // TODO(yoshiki): Un-zoom and change the scale if the magnification window |
| 208 // can't contain the whole given rect. |
| 209 |
| 210 gfx::Rect rect = window_rect; |
| 211 if (target_rect.width() > rect.width()) |
| 212 rect.set_x(target_rect.CenterPoint().x() - rect.x() / 2); |
| 213 else if (target_rect.right() < rect.x()) |
| 214 rect.set_x(target_rect.right()); |
| 215 else if (rect.right() < target_rect.x()) |
| 216 rect.set_x(target_rect.x() - rect.width()); |
| 217 |
| 218 if (rect.height() > window_rect.height()) |
| 219 rect.set_y(target_rect.CenterPoint().y() - rect.y() / 2); |
| 220 else if (target_rect.bottom() < rect.y()) |
| 221 rect.set_y(target_rect.bottom()); |
| 222 else if (rect.bottom() < target_rect.y()) |
| 223 rect.set_y(target_rect.y() - rect.height()); |
| 224 |
| 225 RedrawDIP(rect.origin(), scale, animate); |
| 226 } |
| 227 |
| 228 void MagnificationControllerImpl::EnsurePointIsVisibleWithScale( |
| 229 const gfx::Point& point, |
| 230 float scale, |
| 231 bool animate) { |
| 232 EnsureRectIsVisibleWithScale(gfx::Rect(point, gfx::Size(0, 0)), |
| 233 scale, |
| 234 animate); |
| 235 } |
| 236 |
| 237 void MagnificationControllerImpl::OnMouseMove(const gfx::Point& location) { |
| 238 gfx::Point mouse(location); |
| 239 |
| 240 int x = origin_.x(); |
| 241 int y = origin_.y(); |
| 242 bool start_zoom = false; |
| 243 |
| 244 const gfx::Rect window_rect = GetWindowRectDIP(scale_); |
| 245 const int left = window_rect.x(); |
| 246 const int right = window_rect.right(); |
| 247 const int width_margin = static_cast<int>(0.1f * window_rect.width()); |
| 248 const int width_offset = static_cast<int>(0.5f * window_rect.width()); |
| 249 |
| 250 if (mouse.x() < left + width_margin) { |
| 251 x -= width_offset; |
| 252 start_zoom = true; |
| 253 } else if (right - width_margin < mouse.x()) { |
| 254 x += width_offset; |
| 255 start_zoom = true; |
115 } | 256 } |
116 | 257 |
117 root_window_->layer()->SetTransform(transform); | 258 const int top = window_rect.y(); |
118 } | 259 const int bottom = window_rect.bottom(); |
119 | 260 // Uses same margin with x-axis's one. |
120 gfx::Rect MagnificationController::GetWindowRect() { | 261 const int height_margin = width_margin; |
121 gfx::Size size = root_window_->GetHostSize(); | 262 const int height_offset = static_cast<int>(0.5f * window_rect.height()); |
122 int width = size.width() / scale_; | 263 |
123 int height = size.height() / scale_; | 264 if (mouse.y() < top + height_margin) { |
124 | 265 y -= height_offset; |
125 return gfx::Rect(x_, y_, width, height); | 266 start_zoom = true; |
| 267 } else if (bottom - height_margin < mouse.y()) { |
| 268 y += height_offset; |
| 269 start_zoom = true; |
| 270 } |
| 271 |
| 272 if (start_zoom && !is_on_zooming_) { |
| 273 bool ret = Redraw(gfx::Point(x, y), scale_, true); |
| 274 |
| 275 if (ret) { |
| 276 is_on_zooming_ = true; |
| 277 |
| 278 int x_diff = origin_.x() - window_rect.x(); |
| 279 int y_diff = origin_.y() - window_rect.y(); |
| 280 // If the magnified region is moved, hides the mouse cursor and moves it. |
| 281 if (x_diff != 0 || y_diff != 0) { |
| 282 ash::Shell::GetInstance()-> |
| 283 env_filter()->set_update_cursor_visibility(false); |
| 284 root_window_->ShowCursor(false); |
| 285 mouse.set_x(mouse.x() - (origin_.x() - window_rect.x())); |
| 286 mouse.set_y(mouse.y() - (origin_.y() - window_rect.y())); |
| 287 root_window_->MoveCursorTo(mouse); |
| 288 } |
| 289 } |
| 290 } |
| 291 } |
| 292 |
| 293 gfx::Size MagnificationControllerImpl::GetHostSizeDIP() const { |
| 294 return ui::ConvertSizeToDIP(root_window_->layer(), |
| 295 root_window_->GetHostSize()); |
| 296 } |
| 297 |
| 298 gfx::Rect MagnificationControllerImpl::GetWindowRectDIP(float scale) const { |
| 299 const gfx::Size size_in_dip = |
| 300 ui::ConvertSizeToDIP(root_window_->layer(), |
| 301 root_window_->GetHostSize()); |
| 302 const int width = size_in_dip.width() / scale; |
| 303 const int height = size_in_dip.height() / scale; |
| 304 |
| 305 return gfx::Rect(origin_.x(), origin_.y(), width, height); |
| 306 } |
| 307 |
| 308 bool MagnificationControllerImpl::IsMagnified() const { |
| 309 return scale_ >= kMinimumMagnifiScaleThreshold; |
| 310 } |
| 311 |
| 312 void MagnificationControllerImpl::ValidateScale(float* scale) { |
| 313 // Adjust the scale to just |kMinimumMagnifiScale| if scale is smaller than |
| 314 // |kMinimumMagnifiScaleThreshold|; |
| 315 if (*scale < kMinimumMagnifiScaleThreshold) |
| 316 *scale = kMinimumMagnifiScale; |
| 317 |
| 318 // Adjust the scale to just |kMinimumMagnifiScale| if scale is bigger than |
| 319 // |kMinimumMagnifiScaleThreshold|; |
| 320 if (*scale > kMaximumMagnifiScaleThreshold) |
| 321 *scale = kMaximumMagnifiScale; |
| 322 } |
| 323 |
| 324 void MagnificationControllerImpl::OnImplicitAnimationsCompleted() { |
| 325 root_window_->ShowCursor(true); |
| 326 is_on_zooming_ = false; |
| 327 } |
| 328 |
| 329 //////////////////////////////////////////////////////////////////////////////// |
| 330 // MagnificationControllerImpl: MagnificationController implementation |
| 331 |
| 332 void MagnificationControllerImpl::SetScale(float scale, bool animate) { |
| 333 ValidateScale(&scale); |
| 334 |
| 335 // Try not to change the point which the mouse cursor indicates to. |
| 336 const gfx::Rect window_rect = GetWindowRectDIP(scale); |
| 337 const gfx::Point mouse = root_window_->last_mouse_location(); |
| 338 const gfx::Point origin = gfx::Point(mouse.x() * (1.0f - 1.0f / scale), |
| 339 mouse.y() * (1.0f - 1.0f / scale)); |
| 340 Redraw(origin, scale, animate); |
| 341 } |
| 342 |
| 343 void MagnificationControllerImpl::MoveWindow(int x, int y, bool animate) { |
| 344 Redraw(gfx::Point(x, y), scale_, animate); |
| 345 } |
| 346 |
| 347 void MagnificationControllerImpl::MoveWindow(const gfx::Point& point, |
| 348 bool animate) { |
| 349 Redraw(point, scale_, animate); |
| 350 } |
| 351 |
| 352 void MagnificationControllerImpl::EnsureRectIsVisible( |
| 353 const gfx::Rect& target_rect, |
| 354 bool animate) { |
| 355 EnsureRectIsVisibleWithScale(target_rect, scale_, animate); |
| 356 } |
| 357 |
| 358 void MagnificationControllerImpl::EnsurePointIsVisible( |
| 359 const gfx::Point& point, |
| 360 bool animate) { |
| 361 EnsurePointIsVisibleWithScale(point, scale_, animate); |
| 362 } |
| 363 |
| 364 //////////////////////////////////////////////////////////////////////////////// |
| 365 // MagnificationControllerImpl: aura::EventFilter implementation |
| 366 |
| 367 bool MagnificationControllerImpl::PreHandleKeyEvent(aura::Window* target, |
| 368 aura::KeyEvent* event) { |
| 369 return false; |
| 370 } |
| 371 |
| 372 bool MagnificationControllerImpl::PreHandleMouseEvent(aura::Window* target, |
| 373 aura::MouseEvent* event) { |
| 374 if (IsMagnified()) |
| 375 OnMouseMove(event->root_location()); |
| 376 return false; |
| 377 } |
| 378 |
| 379 ui::TouchStatus MagnificationControllerImpl::PreHandleTouchEvent( |
| 380 aura::Window* target, |
| 381 aura::TouchEvent* event) { |
| 382 return ui::TOUCH_STATUS_UNKNOWN; |
| 383 } |
| 384 |
| 385 ui::GestureStatus MagnificationControllerImpl::PreHandleGestureEvent( |
| 386 aura::Window* target, |
| 387 aura::GestureEvent* event) { |
| 388 return ui::GESTURE_STATUS_UNKNOWN; |
| 389 } |
| 390 |
| 391 //////////////////////////////////////////////////////////////////////////////// |
| 392 // MagnificationController: |
| 393 |
| 394 // static |
| 395 MagnificationController* MagnificationController::CreateInstance() { |
| 396 return new MagnificationControllerImpl(); |
126 } | 397 } |
127 | 398 |
128 } // namespace internal | 399 } // namespace internal |
129 } // namespace ash | 400 } // namespace ash |
OLD | NEW |