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); | |
sky
2012/06/20 03:54:16
Don't you need to remove this in the destructor?
yoshiki
2012/06/20 04:23:12
Thanks, Done.
On 2012/06/20 03:54:16, sky wrote:
| |
121 } | |
122 | |
123 bool MagnificationControllerImpl::Redraw(const gfx::Point& position, | |
124 float scale, | |
125 bool animate) { | |
126 const gfx::Point position_in_dip = | |
127 ui::ConvertPointToDIP(root_window_->layer(), position); | |
128 return RedrawDIP(position_in_dip, scale, animate); | |
129 } | |
130 | |
131 bool MagnificationControllerImpl::RedrawDIP(const gfx::Point& position_in_dip, | |
132 float scale, | |
133 bool animate) { | |
134 int x = position_in_dip.x(); | |
135 int y = position_in_dip.y(); | |
136 | |
137 ValidateScale(&scale); | |
138 | |
139 if (x < 0) | |
140 x = 0; | |
141 if (y < 0) | |
142 y = 0; | |
143 | |
144 const gfx::Size host_size_in_dip = GetHostSizeDIP(); | |
145 const gfx::Size window_size_in_dip = GetWindowRectDIP(scale).size(); | |
146 int max_x = host_size_in_dip.width() - window_size_in_dip.width(); | |
147 int max_y = host_size_in_dip.height() - window_size_in_dip.height(); | |
148 if (x > max_x) | |
149 x = max_x; | |
150 if (y > max_y) | |
151 y = max_y; | |
152 | |
153 // Ignores 1 px diffirence because it may be error on calculation. | |
154 if (std::abs(origin_.x() - x) <= 1 && | |
155 std::abs(origin_.y() - y) <= 1 && | |
156 scale == scale_) | |
157 return false; | |
158 | |
159 origin_.set_x(x); | |
160 origin_.set_y(y); | |
32 scale_ = scale; | 161 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 | 162 |
101 // Creates transform matrix. | 163 // Creates transform matrix. |
102 ui::Transform transform; | 164 ui::Transform transform; |
103 // Flips the signs intentionally to convert them from the position of the | 165 // Flips the signs intentionally to convert them from the position of the |
104 // magnification window. | 166 // magnification window. |
105 transform.ConcatTranslate(-x, -y); | 167 transform.ConcatTranslate(-origin_.x(), -origin_.y()); |
106 transform.ConcatScale(scale, scale); | 168 transform.ConcatScale(scale_, scale_); |
107 | 169 |
108 if (animation) { | 170 ui::ScopedLayerAnimationSettings settings( |
109 ui::ScopedLayerAnimationSettings settings( | 171 root_window_->layer()->GetAnimator()); |
110 root_window_->layer()->GetAnimator()); | 172 settings.AddObserver(this); |
111 settings.SetPreemptionStrategy( | 173 settings.SetPreemptionStrategy( |
112 ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS); | 174 ui::LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); |
113 settings.SetTweenType(ui::Tween::EASE_IN_OUT); | 175 settings.SetTweenType(ui::Tween::EASE_OUT); |
114 settings.SetTransitionDuration(base::TimeDelta::FromMilliseconds(100)); | 176 settings.SetTransitionDuration( |
177 base::TimeDelta::FromMilliseconds(animate ? 100 : 0)); | |
178 | |
179 root_window_->layer()->SetTransform(transform); | |
180 | |
181 return true; | |
182 } | |
183 | |
184 void MagnificationControllerImpl::EnsureRectIsVisibleWithScale( | |
185 const gfx::Rect& target_rect, | |
186 float scale, | |
187 bool animate) { | |
188 const gfx::Rect target_rect_in_dip = | |
189 ui::ConvertRectToDIP(root_window_->layer(), target_rect); | |
190 EnsureRectIsVisibleDIP(target_rect_in_dip, scale, animate); | |
191 } | |
192 | |
193 void MagnificationControllerImpl::EnsureRectIsVisibleDIP( | |
194 const gfx::Rect& target_rect, | |
195 float scale, | |
196 bool animate) { | |
197 ValidateScale(&scale); | |
198 | |
199 const gfx::Rect window_rect = GetWindowRectDIP(scale); | |
200 if (scale == scale_ && window_rect.Contains(target_rect)) | |
201 return; | |
202 | |
203 // TODO(yoshiki): Un-zoom and change the scale if the magnification window | |
204 // can't contain the whole given rect. | |
205 | |
206 gfx::Rect rect = window_rect; | |
207 if (target_rect.width() > rect.width()) | |
208 rect.set_x(target_rect.CenterPoint().x() - rect.x() / 2); | |
209 else if (target_rect.right() < rect.x()) | |
210 rect.set_x(target_rect.right()); | |
211 else if (rect.right() < target_rect.x()) | |
212 rect.set_x(target_rect.x() - rect.width()); | |
213 | |
214 if (rect.height() > window_rect.height()) | |
215 rect.set_y(target_rect.CenterPoint().y() - rect.y() / 2); | |
216 else if (target_rect.bottom() < rect.y()) | |
217 rect.set_y(target_rect.bottom()); | |
218 else if (rect.bottom() < target_rect.y()) | |
219 rect.set_y(target_rect.y() - rect.height()); | |
220 | |
221 RedrawDIP(rect.origin(), scale, animate); | |
222 } | |
223 | |
224 void MagnificationControllerImpl::EnsurePointIsVisibleWithScale( | |
225 const gfx::Point& point, | |
226 float scale, | |
227 bool animate) { | |
228 EnsureRectIsVisibleWithScale(gfx::Rect(point, gfx::Size(0, 0)), | |
229 scale, | |
230 animate); | |
231 } | |
232 | |
233 void MagnificationControllerImpl::OnMouseMove(const gfx::Point& location) { | |
234 gfx::Point mouse(location); | |
235 | |
236 int x = origin_.x(); | |
237 int y = origin_.y(); | |
238 bool start_zoom = false; | |
239 | |
240 const gfx::Rect window_rect = GetWindowRectDIP(scale_); | |
241 const int left = window_rect.x(); | |
242 const int right = window_rect.right(); | |
243 const int width_margin = static_cast<int>(0.1f * window_rect.width()); | |
244 const int width_offset = static_cast<int>(0.5f * window_rect.width()); | |
245 | |
246 if (mouse.x() < left + width_margin) { | |
247 x -= width_offset; | |
248 start_zoom = true; | |
249 } else if (right - width_margin < mouse.x()) { | |
250 x += width_offset; | |
251 start_zoom = true; | |
115 } | 252 } |
116 | 253 |
117 root_window_->layer()->SetTransform(transform); | 254 const int top = window_rect.y(); |
118 } | 255 const int bottom = window_rect.bottom(); |
119 | 256 // Uses same margin with x-axis's one. |
120 gfx::Rect MagnificationController::GetWindowRect() { | 257 const int height_margin = width_margin; |
121 gfx::Size size = root_window_->GetHostSize(); | 258 const int height_offset = static_cast<int>(0.5f * window_rect.height()); |
122 int width = size.width() / scale_; | 259 |
123 int height = size.height() / scale_; | 260 if (mouse.y() < top + height_margin) { |
124 | 261 y -= height_offset; |
125 return gfx::Rect(x_, y_, width, height); | 262 start_zoom = true; |
263 } else if (bottom - height_margin < mouse.y()) { | |
264 y += height_offset; | |
265 start_zoom = true; | |
266 } | |
267 | |
268 if (start_zoom && !is_on_zooming_) { | |
269 bool ret = Redraw(gfx::Point(x, y), scale_, true); | |
270 | |
271 if (ret) { | |
272 is_on_zooming_ = true; | |
273 | |
274 int x_diff = origin_.x() - window_rect.x(); | |
275 int y_diff = origin_.y() - window_rect.y(); | |
276 // If the magnified region is moved, hides the mouse cursor and moves it. | |
277 if (x_diff != 0 || y_diff != 0) { | |
278 ash::Shell::GetInstance()-> | |
279 env_filter()->set_update_cursor_visibility(false); | |
280 root_window_->ShowCursor(false); | |
281 mouse.set_x(mouse.x() - (origin_.x() - window_rect.x())); | |
282 mouse.set_y(mouse.y() - (origin_.y() - window_rect.y())); | |
283 root_window_->MoveCursorTo(mouse); | |
284 } | |
285 } | |
286 } | |
287 } | |
288 | |
289 gfx::Size MagnificationControllerImpl::GetHostSizeDIP() const { | |
290 return ui::ConvertSizeToDIP(root_window_->layer(), | |
291 root_window_->GetHostSize()); | |
292 } | |
293 | |
294 gfx::Rect MagnificationControllerImpl::GetWindowRectDIP(float scale) const { | |
295 const gfx::Size size_in_dip = | |
296 ui::ConvertSizeToDIP(root_window_->layer(), | |
297 root_window_->GetHostSize()); | |
298 const int width = size_in_dip.width() / scale; | |
299 const int height = size_in_dip.height() / scale; | |
300 | |
301 return gfx::Rect(origin_.x(), origin_.y(), width, height); | |
302 } | |
303 | |
304 bool MagnificationControllerImpl::IsMagnified() const { | |
305 return scale_ >= kMinimumMagnifiScaleThreshold; | |
306 } | |
307 | |
308 void MagnificationControllerImpl::ValidateScale(float* scale) { | |
309 // Adjust the scale to just |kMinimumMagnifiScale| if scale is smaller than | |
310 // |kMinimumMagnifiScaleThreshold|; | |
311 if (*scale < kMinimumMagnifiScaleThreshold) | |
312 *scale = kMinimumMagnifiScale; | |
313 | |
314 // Adjust the scale to just |kMinimumMagnifiScale| if scale is bigger than | |
315 // |kMinimumMagnifiScaleThreshold|; | |
316 if (*scale > kMaximumMagnifiScaleThreshold) | |
317 *scale = kMaximumMagnifiScale; | |
318 } | |
319 | |
320 void MagnificationControllerImpl::OnImplicitAnimationsCompleted() { | |
321 root_window_->ShowCursor(true); | |
322 is_on_zooming_ = false; | |
323 } | |
324 | |
325 //////////////////////////////////////////////////////////////////////////////// | |
326 // MagnificationControllerImpl: MagnificationController implementation | |
327 | |
328 void MagnificationControllerImpl::SetScale(float scale, bool animate) { | |
329 ValidateScale(&scale); | |
330 | |
331 // Try not to change the point which the mouse cursor indicates to. | |
332 const gfx::Rect window_rect = GetWindowRectDIP(scale); | |
333 const gfx::Point mouse = root_window_->last_mouse_location(); | |
334 const gfx::Point origin = gfx::Point(mouse.x() * (1.0f - 1.0f / scale), | |
335 mouse.y() * (1.0f - 1.0f / scale)); | |
336 Redraw(origin, scale, animate); | |
337 } | |
338 | |
339 void MagnificationControllerImpl::MoveWindow(int x, int y, bool animate) { | |
340 Redraw(gfx::Point(x, y), scale_, animate); | |
341 } | |
342 | |
343 void MagnificationControllerImpl::MoveWindow(const gfx::Point& point, | |
344 bool animate) { | |
345 Redraw(point, scale_, animate); | |
346 } | |
347 | |
348 void MagnificationControllerImpl::EnsureRectIsVisible( | |
349 const gfx::Rect& target_rect, | |
350 bool animate) { | |
351 EnsureRectIsVisibleWithScale(target_rect, scale_, animate); | |
352 } | |
353 | |
354 void MagnificationControllerImpl::EnsurePointIsVisible( | |
355 const gfx::Point& point, | |
356 bool animate) { | |
357 EnsurePointIsVisibleWithScale(point, scale_, animate); | |
358 } | |
359 | |
360 //////////////////////////////////////////////////////////////////////////////// | |
361 // MagnificationControllerImpl: aura::EventFilter implementation | |
362 | |
363 bool MagnificationControllerImpl::PreHandleKeyEvent(aura::Window* target, | |
364 aura::KeyEvent* event) { | |
365 return false; | |
366 } | |
367 | |
368 bool MagnificationControllerImpl::PreHandleMouseEvent(aura::Window* target, | |
369 aura::MouseEvent* event) { | |
370 if (IsMagnified()) | |
371 OnMouseMove(event->root_location()); | |
372 return false; | |
373 } | |
374 | |
375 ui::TouchStatus MagnificationControllerImpl::PreHandleTouchEvent( | |
376 aura::Window* target, | |
377 aura::TouchEvent* event) { | |
378 return ui::TOUCH_STATUS_UNKNOWN; | |
379 } | |
380 | |
381 ui::GestureStatus MagnificationControllerImpl::PreHandleGestureEvent( | |
382 aura::Window* target, | |
383 aura::GestureEvent* event) { | |
384 return ui::GESTURE_STATUS_UNKNOWN; | |
385 } | |
386 | |
387 //////////////////////////////////////////////////////////////////////////////// | |
388 // MagnificationController: | |
389 | |
390 // static | |
391 MagnificationController* MagnificationController::CreateInstance() { | |
392 return new MagnificationControllerImpl(); | |
126 } | 393 } |
127 | 394 |
128 } // namespace internal | 395 } // namespace internal |
129 } // namespace ash | 396 } // namespace ash |
OLD | NEW |