blob: b6fcfa7828a5c4295da109659798e08548c49e45 [file] [log] [blame]
Torne (Richard Coles)58218062012-11-14 11:43:16 +00001// 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.
4
5#include "ash/wm/window_animations.h"
6
7#include <math.h>
8
9#include <algorithm>
10#include <vector>
11
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +000012#include "ash/screen_util.h"
13#include "ash/shelf/shelf.h"
Ben Murdochca12bfa2013-07-23 11:17:05 +010014#include "ash/shelf/shelf_layout_manager.h"
15#include "ash/shelf/shelf_widget.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000016#include "ash/shell.h"
17#include "ash/wm/window_util.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010018#include "ash/wm/workspace_controller.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000019#include "base/command_line.h"
20#include "base/compiler_specific.h"
21#include "base/logging.h"
Ben Murdoch7dbb3d52013-07-17 14:55:54 +010022#include "base/message_loop/message_loop.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000023#include "base/stl_util.h"
Ben Murdocheb525c52013-07-10 11:40:50 +010024#include "base/time/time.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000025#include "ui/aura/client/aura_constants.h"
26#include "ui/aura/window.h"
27#include "ui/aura/window_observer.h"
28#include "ui/aura/window_property.h"
29#include "ui/compositor/compositor_observer.h"
30#include "ui/compositor/layer.h"
31#include "ui/compositor/layer_animation_observer.h"
32#include "ui/compositor/layer_animation_sequence.h"
33#include "ui/compositor/layer_animator.h"
Torne (Richard Coles)a1401312014-03-18 10:20:56 +000034#include "ui/compositor/layer_tree_owner.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000035#include "ui/compositor/scoped_layer_animation_settings.h"
36#include "ui/gfx/interpolated_transform.h"
37#include "ui/gfx/screen.h"
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000038#include "ui/gfx/vector3d_f.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000039#include "ui/views/view.h"
40#include "ui/views/widget/widget.h"
Torne (Richard Coles)a1401312014-03-18 10:20:56 +000041#include "ui/wm/core/window_util.h"
Torne (Richard Coles)58218062012-11-14 11:43:16 +000042
Torne (Richard Coles)58218062012-11-14 11:43:16 +000043namespace ash {
Torne (Richard Coles)58218062012-11-14 11:43:16 +000044namespace {
Torne (Richard Coles)58218062012-11-14 11:43:16 +000045const int kLayerAnimationsForMinimizeDurationMS = 200;
46
47// Durations for the cross-fade animation, in milliseconds.
48const float kCrossFadeDurationMinMs = 200.f;
49const float kCrossFadeDurationMaxMs = 400.f;
50
51// Durations for the brightness/grayscale fade animation, in milliseconds.
52const int kBrightnessGrayscaleFadeDurationMs = 1000;
53
54// Brightness/grayscale values for hide/show window animations.
55const float kWindowAnimation_HideBrightnessGrayscale = 1.f;
56const float kWindowAnimation_ShowBrightnessGrayscale = 0.f;
57
58const float kWindowAnimation_HideOpacity = 0.f;
59const float kWindowAnimation_ShowOpacity = 1.f;
Torne (Richard Coles)58218062012-11-14 11:43:16 +000060
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000061// Scales for AshWindow above/below current workspace.
62const float kLayerScaleAboveSize = 1.1f;
63const float kLayerScaleBelowSize = .9f;
64
Torne (Richard Coles)58218062012-11-14 11:43:16 +000065int64 Round64(float f) {
66 return static_cast<int64>(f + 0.5f);
67}
68
Torne (Richard Coles)a1401312014-03-18 10:20:56 +000069base::TimeDelta GetCrossFadeDuration(aura::Window* window,
70 const gfx::Rect& old_bounds,
71 const gfx::Rect& new_bounds) {
72 if (::wm::WindowAnimationsDisabled(window))
73 return base::TimeDelta();
74
75 int old_area = old_bounds.width() * old_bounds.height();
76 int new_area = new_bounds.width() * new_bounds.height();
77 int max_area = std::max(old_area, new_area);
78 // Avoid divide by zero.
79 if (max_area == 0)
80 return base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS);
81
82 int delta_area = std::abs(old_area - new_area);
83 // If the area didn't change, the animation is instantaneous.
84 if (delta_area == 0)
85 return base::TimeDelta::FromMilliseconds(kCrossFadeDurationMS);
86
87 float factor =
88 static_cast<float>(delta_area) / static_cast<float>(max_area);
89 const float kRange = kCrossFadeDurationMaxMs - kCrossFadeDurationMinMs;
90 return base::TimeDelta::FromMilliseconds(
91 Round64(kCrossFadeDurationMinMs + (factor * kRange)));
92}
93
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +000094} // namespace
Torne (Richard Coles)58218062012-11-14 11:43:16 +000095
Ben Murdoch2385ea32013-08-06 11:01:04 +010096const int kCrossFadeDurationMS = 200;
97
Torne (Richard Coles)58218062012-11-14 11:43:16 +000098void AddLayerAnimationsForMinimize(aura::Window* window, bool show) {
99 // Recalculate the transform at restore time since the launcher item may have
100 // moved while the window was minimized.
101 gfx::Rect bounds = window->bounds();
Ben Murdochca12bfa2013-07-23 11:17:05 +0100102 gfx::Rect target_bounds = GetMinimizeAnimationTargetBoundsInScreen(window);
103 target_bounds =
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000104 ScreenUtil::ConvertRectFromScreen(window->parent(), target_bounds);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000105
Ben Murdochca12bfa2013-07-23 11:17:05 +0100106 float scale_x = static_cast<float>(target_bounds.width()) / bounds.width();
107 float scale_y = static_cast<float>(target_bounds.height()) / bounds.height();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000108
109 scoped_ptr<ui::InterpolatedTransform> scale(
110 new ui::InterpolatedScale(gfx::Point3F(1, 1, 1),
111 gfx::Point3F(scale_x, scale_y, 1)));
112
113 scoped_ptr<ui::InterpolatedTransform> translation(
114 new ui::InterpolatedTranslation(
115 gfx::Point(),
116 gfx::Point(target_bounds.x() - bounds.x(),
117 target_bounds.y() - bounds.y())));
118
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000119 scale->SetChild(translation.release());
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000120 scale->SetReversed(show);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000121
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000122 base::TimeDelta duration = window->layer()->GetAnimator()->
123 GetTransitionDuration();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000124
125 scoped_ptr<ui::LayerAnimationElement> transition(
126 ui::LayerAnimationElement::CreateInterpolatedTransformElement(
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000127 scale.release(), duration));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000128
129 transition->set_tween_type(
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100130 show ? gfx::Tween::EASE_IN : gfx::Tween::EASE_IN_OUT);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000131
132 window->layer()->GetAnimator()->ScheduleAnimation(
133 new ui::LayerAnimationSequence(transition.release()));
134
135 // When hiding a window, turn off blending until the animation is 3 / 4 done
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000136 // to save bandwidth and reduce jank.
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000137 if (!show) {
138 window->layer()->GetAnimator()->SchedulePauseForProperties(
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000139 (duration * 3) / 4, ui::LayerAnimationElement::OPACITY);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000140 }
141
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000142 // Fade in and out quickly when the window is small to reduce jank.
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000143 float opacity = show ? 1.0f : 0.0f;
144 window->layer()->GetAnimator()->ScheduleAnimation(
145 new ui::LayerAnimationSequence(
146 ui::LayerAnimationElement::CreateOpacityElement(
147 opacity, duration / 4)));
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000148
149 // Reset the transform to identity when the minimize animation is completed.
150 window->layer()->GetAnimator()->ScheduleAnimation(
151 new ui::LayerAnimationSequence(
152 ui::LayerAnimationElement::CreateTransformElement(
153 gfx::Transform(),
154 base::TimeDelta())));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000155}
156
157void AnimateShowWindow_Minimize(aura::Window* window) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000158 window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000159 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
160 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(
161 kLayerAnimationsForMinimizeDurationMS);
162 settings.SetTransitionDuration(duration);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000163 AddLayerAnimationsForMinimize(window, true);
164
165 // Now that the window has been restored, we need to clear its animation style
166 // to default so that normal animation applies.
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000167 ::wm::SetWindowVisibilityAnimationType(
168 window, ::wm::WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000169}
170
171void AnimateHideWindow_Minimize(aura::Window* window) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000172 // Property sets within this scope will be implicitly animated.
Torne (Richard Coles)23730a62014-03-21 14:25:57 +0000173 ::wm::ScopedHidingAnimationSettings hiding_settings(window);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000174 base::TimeDelta duration = base::TimeDelta::FromMilliseconds(
175 kLayerAnimationsForMinimizeDurationMS);
Torne (Richard Coles)23730a62014-03-21 14:25:57 +0000176 hiding_settings.layer_animation_settings()->SetTransitionDuration(duration);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000177 window->layer()->SetVisible(false);
178
179 AddLayerAnimationsForMinimize(window, false);
180}
181
182void AnimateShowHideWindowCommon_BrightnessGrayscale(aura::Window* window,
183 bool show) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000184 float start_value, end_value;
185 if (show) {
186 start_value = kWindowAnimation_HideBrightnessGrayscale;
187 end_value = kWindowAnimation_ShowBrightnessGrayscale;
188 } else {
189 start_value = kWindowAnimation_ShowBrightnessGrayscale;
190 end_value = kWindowAnimation_HideBrightnessGrayscale;
191 }
192
193 window->layer()->SetLayerBrightness(start_value);
194 window->layer()->SetLayerGrayscale(start_value);
195 if (show) {
196 window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
197 window->layer()->SetVisible(true);
198 }
199
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000200 base::TimeDelta duration =
201 base::TimeDelta::FromMilliseconds(kBrightnessGrayscaleFadeDurationMs);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000202
Torne (Richard Coles)23730a62014-03-21 14:25:57 +0000203 if (show) {
204 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
205 window->layer()->GetAnimator()->
206 ScheduleTogether(
207 CreateBrightnessGrayscaleAnimationSequence(end_value, duration));
208 } else {
209 ::wm::ScopedHidingAnimationSettings hiding_settings(window);
210 window->layer()->GetAnimator()->
211 ScheduleTogether(
212 CreateBrightnessGrayscaleAnimationSequence(end_value, duration));
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000213 window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
214 window->layer()->SetVisible(false);
215 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000216}
217
218void AnimateShowWindow_BrightnessGrayscale(aura::Window* window) {
219 AnimateShowHideWindowCommon_BrightnessGrayscale(window, true);
220}
221
222void AnimateHideWindow_BrightnessGrayscale(aura::Window* window) {
223 AnimateShowHideWindowCommon_BrightnessGrayscale(window, false);
224}
225
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000226bool AnimateShowWindow(aura::Window* window) {
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000227 if (!::wm::HasWindowVisibilityAnimationTransition(
228 window, ::wm::ANIMATE_SHOW)) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000229 return false;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000230 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000231
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000232 switch (::wm::GetWindowVisibilityAnimationType(window)) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000233 case WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE:
234 AnimateShowWindow_Minimize(window);
235 return true;
236 case WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE:
237 AnimateShowWindow_BrightnessGrayscale(window);
238 return true;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000239 default:
240 NOTREACHED();
241 return false;
242 }
243}
244
245bool AnimateHideWindow(aura::Window* window) {
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000246 if (!::wm::HasWindowVisibilityAnimationTransition(
247 window, ::wm::ANIMATE_HIDE)) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000248 return false;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000249 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000250
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000251 switch (::wm::GetWindowVisibilityAnimationType(window)) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000252 case WINDOW_VISIBILITY_ANIMATION_TYPE_MINIMIZE:
253 AnimateHideWindow_Minimize(window);
254 return true;
255 case WINDOW_VISIBILITY_ANIMATION_TYPE_BRIGHTNESS_GRAYSCALE:
256 AnimateHideWindow_BrightnessGrayscale(window);
257 return true;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000258 default:
259 NOTREACHED();
260 return false;
261 }
262}
263
264// Observer for a window cross-fade animation. If either the window closes or
265// the layer's animation completes or compositing is aborted due to GPU crash,
266// it deletes the layer and removes itself as an observer.
267class CrossFadeObserver : public ui::CompositorObserver,
268 public aura::WindowObserver,
269 public ui::ImplicitAnimationObserver {
270 public:
271 // Observes |window| for destruction, but does not take ownership.
272 // Takes ownership of |layer| and its child layers.
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000273 CrossFadeObserver(aura::Window* window,
274 scoped_ptr<ui::LayerTreeOwner> layer_owner)
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000275 : window_(window),
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000276 layer_owner_(layer_owner.Pass()) {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000277 window_->AddObserver(this);
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000278 layer_owner_->root()->GetCompositor()->AddObserver(this);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000279 }
280 virtual ~CrossFadeObserver() {
281 window_->RemoveObserver(this);
282 window_ = NULL;
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000283 layer_owner_->root()->GetCompositor()->RemoveObserver(this);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000284 }
285
286 // ui::CompositorObserver overrides:
287 virtual void OnCompositingDidCommit(ui::Compositor* compositor) OVERRIDE {
288 }
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000289 virtual void OnCompositingStarted(ui::Compositor* compositor,
290 base::TimeTicks start_time) OVERRIDE {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000291 }
292 virtual void OnCompositingEnded(ui::Compositor* compositor) OVERRIDE {
293 }
294 virtual void OnCompositingAborted(ui::Compositor* compositor) OVERRIDE {
295 // Triggers OnImplicitAnimationsCompleted() to be called and deletes us.
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000296 layer_owner_->root()->GetAnimator()->StopAnimating();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000297 }
298 virtual void OnCompositingLockStateChanged(
299 ui::Compositor* compositor) OVERRIDE {
300 }
301
302 // aura::WindowObserver overrides:
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000303 virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000304 // Triggers OnImplicitAnimationsCompleted() to be called and deletes us.
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000305 layer_owner_->root()->GetAnimator()->StopAnimating();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000306 }
Ben Murdocheffb81e2014-03-31 11:51:25 +0100307 virtual void OnWindowRemovingFromRootWindow(aura::Window* window,
308 aura::Window* new_root) OVERRIDE {
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000309 layer_owner_->root()->GetAnimator()->StopAnimating();
Torne (Richard Coles)424c4d72013-08-30 15:14:49 +0100310 }
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000311
312 // ui::ImplicitAnimationObserver overrides:
313 virtual void OnImplicitAnimationsCompleted() OVERRIDE {
314 delete this;
315 }
316
317 private:
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000318 aura::Window* window_; // not owned
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000319 scoped_ptr<ui::LayerTreeOwner> layer_owner_;
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000320
321 DISALLOW_COPY_AND_ASSIGN(CrossFadeObserver);
322};
323
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000324base::TimeDelta CrossFadeAnimation(
325 aura::Window* window,
326 scoped_ptr<ui::LayerTreeOwner> old_layer_owner,
327 gfx::Tween::Type tween_type) {
328 DCHECK(old_layer_owner->root());
329 const gfx::Rect old_bounds(old_layer_owner->root()->bounds());
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000330 const gfx::Rect new_bounds(window->bounds());
331 const bool old_on_top = (old_bounds.width() > new_bounds.width());
332
333 // Shorten the animation if there's not much visual movement.
Torne (Richard Coles)a3f6a492013-12-18 16:25:09 +0000334 const base::TimeDelta duration = GetCrossFadeDuration(window,
335 old_bounds, new_bounds);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000336
337 // Scale up the old layer while translating to new position.
338 {
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000339 ui::Layer* old_layer = old_layer_owner->root();
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000340 old_layer->GetAnimator()->StopAnimating();
341 ui::ScopedLayerAnimationSettings settings(old_layer->GetAnimator());
342
343 // Animation observer owns the old layer and deletes itself.
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000344 settings.AddObserver(new CrossFadeObserver(window, old_layer_owner.Pass()));
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000345 settings.SetTransitionDuration(duration);
346 settings.SetTweenType(tween_type);
347 gfx::Transform out_transform;
348 float scale_x = static_cast<float>(new_bounds.width()) /
349 static_cast<float>(old_bounds.width());
350 float scale_y = static_cast<float>(new_bounds.height()) /
351 static_cast<float>(old_bounds.height());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000352 out_transform.Translate(new_bounds.x() - old_bounds.x(),
353 new_bounds.y() - old_bounds.y());
354 out_transform.Scale(scale_x, scale_y);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000355 old_layer->SetTransform(out_transform);
356 if (old_on_top) {
357 // The old layer is on top, and should fade out. The new layer below will
358 // stay opaque to block the desktop.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000359 old_layer->SetOpacity(kWindowAnimation_HideOpacity);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000360 }
361 // In tests |old_layer| is deleted here, as animations have zero duration.
362 old_layer = NULL;
363 }
364
365 // Set the new layer's current transform, such that the user sees a scaled
366 // version of the window with the original bounds at the original position.
367 gfx::Transform in_transform;
368 const float scale_x = static_cast<float>(old_bounds.width()) /
369 static_cast<float>(new_bounds.width());
370 const float scale_y = static_cast<float>(old_bounds.height()) /
371 static_cast<float>(new_bounds.height());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000372 in_transform.Translate(old_bounds.x() - new_bounds.x(),
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000373 old_bounds.y() - new_bounds.y());
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000374 in_transform.Scale(scale_x, scale_y);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000375 window->layer()->SetTransform(in_transform);
376 if (!old_on_top) {
377 // The new layer is on top and should fade in. The old layer below will
378 // stay opaque and block the desktop.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000379 window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000380 }
381 {
382 // Animate the new layer to the identity transform, so the window goes to
383 // its newly set bounds.
384 ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
385 settings.SetTransitionDuration(duration);
386 settings.SetTweenType(tween_type);
387 window->layer()->SetTransform(gfx::Transform());
388 if (!old_on_top) {
389 // New layer is on top, fade it in.
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000390 window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000391 }
392 }
393 return duration;
394}
395
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000396bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) {
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000397 if (::wm::WindowAnimationsDisabled(window))
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000398 return false;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000399
400 // Attempt to run CoreWm supplied animation types.
Torne (Richard Coles)a1401312014-03-18 10:20:56 +0000401 if (::wm::AnimateOnChildWindowVisibilityChanged(window, visible))
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000402 return true;
403
404 // Otherwise try to run an Ash-specific animation.
405 if (visible)
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000406 return AnimateShowWindow(window);
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000407 // Don't start hiding the window again if it's already being hidden.
408 return window->layer()->GetTargetOpacity() != 0.0f &&
409 AnimateHideWindow(window);
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000410}
411
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000412std::vector<ui::LayerAnimationSequence*>
413CreateBrightnessGrayscaleAnimationSequence(float target_value,
414 base::TimeDelta duration) {
Torne (Richard Coles)d0247b12013-09-19 22:36:51 +0100415 gfx::Tween::Type animation_type = gfx::Tween::EASE_OUT;
Torne (Richard Coles)2a99a7e2013-03-28 15:31:22 +0000416 scoped_ptr<ui::LayerAnimationSequence> brightness_sequence(
417 new ui::LayerAnimationSequence());
418 scoped_ptr<ui::LayerAnimationSequence> grayscale_sequence(
419 new ui::LayerAnimationSequence());
420
421 scoped_ptr<ui::LayerAnimationElement> brightness_element(
422 ui::LayerAnimationElement::CreateBrightnessElement(
423 target_value, duration));
424 brightness_element->set_tween_type(animation_type);
425 brightness_sequence->AddElement(brightness_element.release());
426
427 scoped_ptr<ui::LayerAnimationElement> grayscale_element(
428 ui::LayerAnimationElement::CreateGrayscaleElement(
429 target_value, duration));
430 grayscale_element->set_tween_type(animation_type);
431 grayscale_sequence->AddElement(grayscale_element.release());
432
433 std::vector<ui::LayerAnimationSequence*> animations;
434 animations.push_back(brightness_sequence.release());
435 animations.push_back(grayscale_sequence.release());
436
437 return animations;
438}
439
440// Returns scale related to the specified AshWindowScaleType.
441void SetTransformForScaleAnimation(ui::Layer* layer,
442 LayerScaleAnimationDirection type) {
443 const float scale =
444 type == LAYER_SCALE_ANIMATION_ABOVE ? kLayerScaleAboveSize :
445 kLayerScaleBelowSize;
446 gfx::Transform transform;
447 transform.Translate(-layer->bounds().width() * (scale - 1.0f) / 2,
448 -layer->bounds().height() * (scale - 1.0f) / 2);
449 transform.Scale(scale, scale);
450 layer->SetTransform(transform);
451}
452
Ben Murdochca12bfa2013-07-23 11:17:05 +0100453gfx::Rect GetMinimizeAnimationTargetBoundsInScreen(aura::Window* window) {
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000454 Shelf* shelf = Shelf::ForWindow(window);
Torne (Richard Coles)f2477e02013-11-28 11:55:43 +0000455 // Shelf is created lazily and can be NULL.
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000456 if (!shelf)
Ben Murdochca12bfa2013-07-23 11:17:05 +0100457 return gfx::Rect();
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000458 gfx::Rect item_rect = shelf->GetScreenBoundsOfItemIconForWindow(window);
Ben Murdochca12bfa2013-07-23 11:17:05 +0100459
460 // The launcher item is visible and has an icon.
461 if (!item_rect.IsEmpty())
462 return item_rect;
463
464 // If both the icon width and height are 0, then there is no icon in the
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100465 // launcher for |window|. If the launcher is auto hidden, one of the height or
466 // width will be 0 but the position in the launcher and the major dimension
467 // are still reported correctly and the window can be animated to the launcher
468 // item's light bar.
469 ShelfLayoutManager* layout_manager = ShelfLayoutManager::ForShelf(window);
Ben Murdochca12bfa2013-07-23 11:17:05 +0100470 if (item_rect.width() != 0 || item_rect.height() != 0) {
Ben Murdochca12bfa2013-07-23 11:17:05 +0100471 if (layout_manager->visibility_state() == SHELF_AUTO_HIDE) {
Torne (Richard Coles)5d1f7b12014-02-21 12:16:55 +0000472 gfx::Rect shelf_bounds = shelf->shelf_widget()->GetWindowBoundsInScreen();
Ben Murdochca12bfa2013-07-23 11:17:05 +0100473 switch (layout_manager->GetAlignment()) {
474 case SHELF_ALIGNMENT_BOTTOM:
475 item_rect.set_y(shelf_bounds.y());
476 break;
477 case SHELF_ALIGNMENT_LEFT:
478 item_rect.set_x(shelf_bounds.right());
479 break;
480 case SHELF_ALIGNMENT_RIGHT:
481 item_rect.set_x(shelf_bounds.x());
482 break;
483 case SHELF_ALIGNMENT_TOP:
484 item_rect.set_y(shelf_bounds.bottom());
485 break;
486 }
487 return item_rect;
488 }
489 }
490
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100491 // Coming here, there is no visible icon of that shelf item and we zoom back
492 // to the location of the application launcher (which is fixed as first item
493 // of the shelf).
Ben Murdochca12bfa2013-07-23 11:17:05 +0100494 gfx::Rect work_area =
495 Shell::GetScreen()->GetDisplayNearestWindow(window).work_area();
Torne (Richard Coles)cedac222014-06-03 10:58:34 +0100496 int ltr_adjusted_x = base::i18n::IsRTL() ? work_area.right() : work_area.x();
497 switch (layout_manager->GetAlignment()) {
498 case SHELF_ALIGNMENT_BOTTOM:
499 return gfx::Rect(ltr_adjusted_x, work_area.bottom(), 0, 0);
500 case SHELF_ALIGNMENT_TOP:
501 return gfx::Rect(ltr_adjusted_x, work_area.y(), 0, 0);
502 case SHELF_ALIGNMENT_LEFT:
503 return gfx::Rect(work_area.x(), work_area.y(), 0, 0);
504 case SHELF_ALIGNMENT_RIGHT:
505 return gfx::Rect(work_area.right(), work_area.y(), 0, 0);
506 }
507 NOTREACHED();
508 return gfx::Rect();
Ben Murdochca12bfa2013-07-23 11:17:05 +0100509}
510
Torne (Richard Coles)58218062012-11-14 11:43:16 +0000511} // namespace ash