Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / ui / wm / core / window_animations.cc
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.
4
5 #include "ui/wm/core/window_animations.h"
6
7 #include <math.h>
8
9 #include <algorithm>
10 #include <vector>
11
12 #include "base/command_line.h"
13 #include "base/compiler_specific.h"
14 #include "base/logging.h"
15 #include "base/message_loop/message_loop.h"
16 #include "base/stl_util.h"
17 #include "base/time/time.h"
18 #include "ui/aura/client/aura_constants.h"
19 #include "ui/aura/window.h"
20 #include "ui/aura/window_delegate.h"
21 #include "ui/aura/window_observer.h"
22 #include "ui/aura/window_property.h"
23 #include "ui/compositor/compositor_observer.h"
24 #include "ui/compositor/layer.h"
25 #include "ui/compositor/layer_animation_observer.h"
26 #include "ui/compositor/layer_animation_sequence.h"
27 #include "ui/compositor/layer_animator.h"
28 #include "ui/compositor/layer_tree_owner.h"
29 #include "ui/compositor/scoped_animation_duration_scale_mode.h"
30 #include "ui/compositor/scoped_layer_animation_settings.h"
31 #include "ui/gfx/animation/animation.h"
32 #include "ui/gfx/interpolated_transform.h"
33 #include "ui/gfx/rect_conversions.h"
34 #include "ui/gfx/screen.h"
35 #include "ui/gfx/vector2d.h"
36 #include "ui/gfx/vector3d_f.h"
37 #include "ui/wm/core/window_util.h"
38 #include "ui/wm/core/wm_core_switches.h"
39 #include "ui/wm/public/animation_host.h"
40
41 DECLARE_WINDOW_PROPERTY_TYPE(int)
42 DECLARE_WINDOW_PROPERTY_TYPE(wm::WindowVisibilityAnimationType)
43 DECLARE_WINDOW_PROPERTY_TYPE(wm::WindowVisibilityAnimationTransition)
44 DECLARE_WINDOW_PROPERTY_TYPE(float)
45 DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(WM_EXPORT, bool)
46
47 namespace wm {
48 namespace {
49 const float kWindowAnimation_Vertical_TranslateY = 15.f;
50
51 // A base class for hiding animation observer which has two roles:
52 // 1) Notifies AnimationHost at the end of hiding animation.
53 // 2) Detaches the window's layers for hiding animation and deletes
54 // them upon completion of the animation. This is necessary to a)
55 // ensure that the animation continues in the event of the window being
56 // deleted, and b) to ensure that the animation is visible even if the
57 // window gets restacked below other windows when focus or activation
58 // changes.
59 // The subclass will determine when the animation is completed.
60 class HidingWindowAnimationObserverBase : public aura::WindowObserver {
61  public:
62   explicit HidingWindowAnimationObserverBase(aura::Window* window)
63       : window_(window) {
64     window_->AddObserver(this);
65   }
66   virtual ~HidingWindowAnimationObserverBase() {
67     if (window_)
68       window_->RemoveObserver(this);
69   }
70
71   // aura::WindowObserver:
72   virtual void OnWindowDestroying(aura::Window* window) OVERRIDE {
73     DCHECK_EQ(window, window_);
74     WindowInvalid();
75   }
76
77   virtual void OnWindowDestroyed(aura::Window* window) OVERRIDE {
78     DCHECK_EQ(window, window_);
79     WindowInvalid();
80   }
81
82   // Detach the current layers and create new layers for |window_|.
83   // Stack the original layers above |window_| and its transient
84   // children.  If the window has transient children, the original
85   // layers will be moved above the top most transient child so that
86   // activation change does not put the window above the animating
87   // layer.
88   void DetachAndRecreateLayers() {
89     layer_owner_ = RecreateLayers(window_);
90     if (window_->parent()) {
91       const aura::Window::Windows& transient_children =
92           GetTransientChildren(window_);
93       aura::Window::Windows::const_iterator iter =
94           std::find(window_->parent()->children().begin(),
95                     window_->parent()->children().end(),
96                     window_);
97       DCHECK(iter != window_->parent()->children().end());
98       aura::Window* topmost_transient_child = NULL;
99       for (++iter; iter != window_->parent()->children().end(); ++iter) {
100         if (std::find(transient_children.begin(),
101                       transient_children.end(),
102                       *iter) != transient_children.end()) {
103           topmost_transient_child = *iter;
104         }
105       }
106       if (topmost_transient_child) {
107         window_->parent()->layer()->StackAbove(
108             layer_owner_->root(), topmost_transient_child->layer());
109       }
110     }
111   }
112
113  protected:
114   // Invoked when the hiding animation is completed.  It will delete
115   // 'this', and no operation should be made on this object after this
116   // point.
117   void OnAnimationCompleted() {
118     // Window may have been destroyed by this point.
119     if (window_) {
120       aura::client::AnimationHost* animation_host =
121           aura::client::GetAnimationHost(window_);
122       if (animation_host)
123         animation_host->OnWindowHidingAnimationCompleted();
124       window_->RemoveObserver(this);
125     }
126     delete this;
127   }
128
129  private:
130   // Invoked when the window is destroyed (or destroying).
131   void WindowInvalid() {
132     layer_owner_->root()->SuppressPaint();
133
134     window_->RemoveObserver(this);
135     window_ = NULL;
136   }
137
138   aura::Window* window_;
139
140   // The owner of detached layers.
141   scoped_ptr<ui::LayerTreeOwner> layer_owner_;
142
143   DISALLOW_COPY_AND_ASSIGN(HidingWindowAnimationObserverBase);
144 };
145
146 }  // namespace
147
148 DEFINE_WINDOW_PROPERTY_KEY(int,
149                            kWindowVisibilityAnimationTypeKey,
150                            WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT);
151 DEFINE_WINDOW_PROPERTY_KEY(int, kWindowVisibilityAnimationDurationKey, 0);
152 DEFINE_WINDOW_PROPERTY_KEY(WindowVisibilityAnimationTransition,
153                            kWindowVisibilityAnimationTransitionKey,
154                            ANIMATE_BOTH);
155 DEFINE_WINDOW_PROPERTY_KEY(float,
156                            kWindowVisibilityAnimationVerticalPositionKey,
157                            kWindowAnimation_Vertical_TranslateY);
158
159 // A HidingWindowAnimationObserver that deletes observer and detached
160 // layers upon the completion of the implicit animation.
161 class ImplicitHidingWindowAnimationObserver
162     : public HidingWindowAnimationObserverBase,
163       public ui::ImplicitAnimationObserver {
164  public:
165   ImplicitHidingWindowAnimationObserver(
166       aura::Window* window,
167       ui::ScopedLayerAnimationSettings* settings);
168   virtual ~ImplicitHidingWindowAnimationObserver() {}
169
170   // ui::ImplicitAnimationObserver:
171   virtual void OnImplicitAnimationsCompleted() OVERRIDE;
172
173  private:
174   DISALLOW_COPY_AND_ASSIGN(ImplicitHidingWindowAnimationObserver);
175 };
176
177 namespace {
178
179 const int kDefaultAnimationDurationForMenuMS = 150;
180
181 const float kWindowAnimation_HideOpacity = 0.f;
182 const float kWindowAnimation_ShowOpacity = 1.f;
183 const float kWindowAnimation_TranslateFactor = 0.5f;
184 const float kWindowAnimation_ScaleFactor = .95f;
185
186 const int kWindowAnimation_Rotate_DurationMS = 180;
187 const int kWindowAnimation_Rotate_OpacityDurationPercent = 90;
188 const float kWindowAnimation_Rotate_TranslateY = -20.f;
189 const float kWindowAnimation_Rotate_PerspectiveDepth = 500.f;
190 const float kWindowAnimation_Rotate_DegreesX = 5.f;
191 const float kWindowAnimation_Rotate_ScaleFactor = .99f;
192
193 const float kWindowAnimation_Bounce_Scale = 1.02f;
194 const int kWindowAnimation_Bounce_DurationMS = 180;
195 const int kWindowAnimation_Bounce_GrowShrinkDurationPercent = 40;
196
197 base::TimeDelta GetWindowVisibilityAnimationDuration(
198     const aura::Window& window) {
199   int duration =
200       window.GetProperty(kWindowVisibilityAnimationDurationKey);
201   if (duration == 0 && window.type() == ui::wm::WINDOW_TYPE_MENU) {
202     return base::TimeDelta::FromMilliseconds(
203         kDefaultAnimationDurationForMenuMS);
204   }
205   return base::TimeDelta::FromInternalValue(duration);
206 }
207
208 // Gets/sets the WindowVisibilityAnimationType associated with a window.
209 // TODO(beng): redundant/fold into method on public api?
210 int GetWindowVisibilityAnimationType(aura::Window* window) {
211   int type = window->GetProperty(kWindowVisibilityAnimationTypeKey);
212   if (type == WINDOW_VISIBILITY_ANIMATION_TYPE_DEFAULT) {
213     return (window->type() == ui::wm::WINDOW_TYPE_MENU ||
214             window->type() == ui::wm::WINDOW_TYPE_TOOLTIP)
215                ? WINDOW_VISIBILITY_ANIMATION_TYPE_FADE
216                : WINDOW_VISIBILITY_ANIMATION_TYPE_DROP;
217   }
218   return type;
219 }
220
221 void GetTransformRelativeToRoot(ui::Layer* layer, gfx::Transform* transform) {
222   const ui::Layer* root = layer;
223   while (root->parent())
224     root = root->parent();
225   layer->GetTargetTransformRelativeTo(root, transform);
226 }
227
228 gfx::Rect GetLayerWorldBoundsAfterTransform(ui::Layer* layer,
229                                             const gfx::Transform& transform) {
230   gfx::Transform in_world = transform;
231   GetTransformRelativeToRoot(layer, &in_world);
232
233   gfx::RectF transformed = layer->bounds();
234   in_world.TransformRect(&transformed);
235
236   return gfx::ToEnclosingRect(transformed);
237 }
238
239 // Augment the host window so that the enclosing bounds of the full
240 // animation will fit inside of it.
241 void AugmentWindowSize(aura::Window* window,
242                        const gfx::Transform& end_transform) {
243   aura::client::AnimationHost* animation_host =
244       aura::client::GetAnimationHost(window);
245   if (!animation_host)
246     return;
247
248   const gfx::Rect& world_at_start = window->bounds();
249   gfx::Rect world_at_end =
250       GetLayerWorldBoundsAfterTransform(window->layer(), end_transform);
251   gfx::Rect union_in_window_space =
252       gfx::UnionRects(world_at_start, world_at_end);
253
254   // Calculate the top left and bottom right deltas to be added to the window
255   // bounds.
256   gfx::Vector2d top_left_delta(world_at_start.x() - union_in_window_space.x(),
257                                world_at_start.y() - union_in_window_space.y());
258
259   gfx::Vector2d bottom_right_delta(
260       union_in_window_space.x() + union_in_window_space.width() -
261           (world_at_start.x() + world_at_start.width()),
262       union_in_window_space.y() + union_in_window_space.height() -
263           (world_at_start.y() + world_at_start.height()));
264
265   DCHECK(top_left_delta.x() >= 0 && top_left_delta.y() >= 0 &&
266          bottom_right_delta.x() >= 0 && bottom_right_delta.y() >= 0);
267
268   animation_host->SetHostTransitionOffsets(top_left_delta, bottom_right_delta);
269 }
270
271 // Shows a window using an animation, animating its opacity from 0.f to 1.f,
272 // its visibility to true, and its transform from |start_transform| to
273 // |end_transform|.
274 void AnimateShowWindowCommon(aura::Window* window,
275                              const gfx::Transform& start_transform,
276                              const gfx::Transform& end_transform) {
277   AugmentWindowSize(window, end_transform);
278
279   window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
280   window->layer()->SetTransform(start_transform);
281   window->layer()->SetVisible(true);
282
283   {
284     // Property sets within this scope will be implicitly animated.
285     ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator());
286     base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window);
287     if (duration.ToInternalValue() > 0)
288       settings.SetTransitionDuration(duration);
289
290     window->layer()->SetTransform(end_transform);
291     window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
292   }
293 }
294
295 // Hides a window using an animation, animating its opacity from 1.f to 0.f,
296 // its visibility to false, and its transform to |end_transform|.
297 void AnimateHideWindowCommon(aura::Window* window,
298                              const gfx::Transform& end_transform) {
299   AugmentWindowSize(window, end_transform);
300
301   // Property sets within this scope will be implicitly animated.
302   ScopedHidingAnimationSettings hiding_settings(window);
303   base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window);
304   if (duration.ToInternalValue() > 0)
305     hiding_settings.layer_animation_settings()->SetTransitionDuration(duration);
306
307   window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
308   window->layer()->SetTransform(end_transform);
309   window->layer()->SetVisible(false);
310 }
311
312 static gfx::Transform GetScaleForWindow(aura::Window* window) {
313   gfx::Rect bounds = window->bounds();
314   gfx::Transform scale = gfx::GetScaleTransform(
315       gfx::Point(kWindowAnimation_TranslateFactor * bounds.width(),
316                  kWindowAnimation_TranslateFactor * bounds.height()),
317       kWindowAnimation_ScaleFactor);
318   return scale;
319 }
320
321 // Show/Hide windows using a shrink animation.
322 void AnimateShowWindow_Drop(aura::Window* window) {
323   AnimateShowWindowCommon(window, GetScaleForWindow(window), gfx::Transform());
324 }
325
326 void AnimateHideWindow_Drop(aura::Window* window) {
327   AnimateHideWindowCommon(window, GetScaleForWindow(window));
328 }
329
330 // Show/Hide windows using a vertical Glenimation.
331 void AnimateShowWindow_Vertical(aura::Window* window) {
332   gfx::Transform transform;
333   transform.Translate(0, window->GetProperty(
334       kWindowVisibilityAnimationVerticalPositionKey));
335   AnimateShowWindowCommon(window, transform, gfx::Transform());
336 }
337
338 void AnimateHideWindow_Vertical(aura::Window* window) {
339   gfx::Transform transform;
340   transform.Translate(0, window->GetProperty(
341       kWindowVisibilityAnimationVerticalPositionKey));
342   AnimateHideWindowCommon(window, transform);
343 }
344
345 // Show/Hide windows using a fade.
346 void AnimateShowWindow_Fade(aura::Window* window) {
347   AnimateShowWindowCommon(window, gfx::Transform(), gfx::Transform());
348 }
349
350 void AnimateHideWindow_Fade(aura::Window* window) {
351   AnimateHideWindowCommon(window, gfx::Transform());
352 }
353
354 ui::LayerAnimationElement* CreateGrowShrinkElement(
355     aura::Window* window, bool grow) {
356   scoped_ptr<ui::InterpolatedTransform> scale(new ui::InterpolatedScale(
357       gfx::Point3F(kWindowAnimation_Bounce_Scale,
358                    kWindowAnimation_Bounce_Scale,
359                    1),
360       gfx::Point3F(1, 1, 1)));
361   scoped_ptr<ui::InterpolatedTransform> scale_about_pivot(
362       new ui::InterpolatedTransformAboutPivot(
363           gfx::Point(window->bounds().width() * 0.5,
364                      window->bounds().height() * 0.5),
365           scale.release()));
366   scale_about_pivot->SetReversed(grow);
367   scoped_ptr<ui::LayerAnimationElement> transition(
368       ui::LayerAnimationElement::CreateInterpolatedTransformElement(
369           scale_about_pivot.release(),
370           base::TimeDelta::FromMilliseconds(
371               kWindowAnimation_Bounce_DurationMS *
372                   kWindowAnimation_Bounce_GrowShrinkDurationPercent / 100)));
373   transition->set_tween_type(grow ? gfx::Tween::EASE_OUT : gfx::Tween::EASE_IN);
374   return transition.release();
375 }
376
377 void AnimateBounce(aura::Window* window) {
378   ui::ScopedLayerAnimationSettings scoped_settings(
379       window->layer()->GetAnimator());
380   scoped_settings.SetPreemptionStrategy(
381       ui::LayerAnimator::REPLACE_QUEUED_ANIMATIONS);
382   scoped_ptr<ui::LayerAnimationSequence> sequence(
383       new ui::LayerAnimationSequence);
384   sequence->AddElement(CreateGrowShrinkElement(window, true));
385   sequence->AddElement(ui::LayerAnimationElement::CreatePauseElement(
386       ui::LayerAnimationElement::BOUNDS,
387       base::TimeDelta::FromMilliseconds(
388         kWindowAnimation_Bounce_DurationMS *
389             (100 - 2 * kWindowAnimation_Bounce_GrowShrinkDurationPercent) /
390             100)));
391   sequence->AddElement(CreateGrowShrinkElement(window, false));
392   window->layer()->GetAnimator()->StartAnimation(sequence.release());
393 }
394
395 // A HidingWindowAnimationObserver that deletes observer and detached
396 // layers when the last_sequence has been completed or aborted.
397 class RotateHidingWindowAnimationObserver
398     : public HidingWindowAnimationObserverBase,
399       public ui::LayerAnimationObserver {
400  public:
401   explicit RotateHidingWindowAnimationObserver(aura::Window* window)
402       : HidingWindowAnimationObserverBase(window) {}
403   virtual ~RotateHidingWindowAnimationObserver() {}
404
405   // Destroys itself after |last_sequence| ends or is aborted. Does not take
406   // ownership of |last_sequence|, which should not be NULL.
407   void SetLastSequence(ui::LayerAnimationSequence* last_sequence) {
408     last_sequence->AddObserver(this);
409   }
410
411   // ui::LayerAnimationObserver:
412   virtual void OnLayerAnimationEnded(
413       ui::LayerAnimationSequence* sequence) OVERRIDE {
414     OnAnimationCompleted();
415   }
416   virtual void OnLayerAnimationAborted(
417       ui::LayerAnimationSequence* sequence) OVERRIDE {
418     OnAnimationCompleted();
419   }
420   virtual void OnLayerAnimationScheduled(
421       ui::LayerAnimationSequence* sequence) OVERRIDE {}
422
423  private:
424   DISALLOW_COPY_AND_ASSIGN(RotateHidingWindowAnimationObserver);
425 };
426
427 void AddLayerAnimationsForRotate(aura::Window* window, bool show) {
428   if (show)
429     window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
430
431   base::TimeDelta duration = base::TimeDelta::FromMilliseconds(
432       kWindowAnimation_Rotate_DurationMS);
433
434   RotateHidingWindowAnimationObserver* observer = NULL;
435
436   if (!show) {
437     observer = new RotateHidingWindowAnimationObserver(window);
438     window->layer()->GetAnimator()->SchedulePauseForProperties(
439         duration * (100 - kWindowAnimation_Rotate_OpacityDurationPercent) / 100,
440         ui::LayerAnimationElement::OPACITY);
441   }
442   scoped_ptr<ui::LayerAnimationElement> opacity(
443       ui::LayerAnimationElement::CreateOpacityElement(
444           show ? kWindowAnimation_ShowOpacity : kWindowAnimation_HideOpacity,
445           duration * kWindowAnimation_Rotate_OpacityDurationPercent / 100));
446   opacity->set_tween_type(gfx::Tween::EASE_IN_OUT);
447   window->layer()->GetAnimator()->ScheduleAnimation(
448       new ui::LayerAnimationSequence(opacity.release()));
449
450   float xcenter = window->bounds().width() * 0.5;
451
452   gfx::Transform transform;
453   transform.Translate(xcenter, 0);
454   transform.ApplyPerspectiveDepth(kWindowAnimation_Rotate_PerspectiveDepth);
455   transform.Translate(-xcenter, 0);
456   scoped_ptr<ui::InterpolatedTransform> perspective(
457       new ui::InterpolatedConstantTransform(transform));
458
459   scoped_ptr<ui::InterpolatedTransform> scale(
460       new ui::InterpolatedScale(1, kWindowAnimation_Rotate_ScaleFactor));
461   scoped_ptr<ui::InterpolatedTransform> scale_about_pivot(
462       new ui::InterpolatedTransformAboutPivot(
463           gfx::Point(xcenter, kWindowAnimation_Rotate_TranslateY),
464           scale.release()));
465
466   scoped_ptr<ui::InterpolatedTransform> translation(
467       new ui::InterpolatedTranslation(gfx::Point(), gfx::Point(
468           0, kWindowAnimation_Rotate_TranslateY)));
469
470   scoped_ptr<ui::InterpolatedTransform> rotation(
471       new ui::InterpolatedAxisAngleRotation(
472           gfx::Vector3dF(1, 0, 0), 0, kWindowAnimation_Rotate_DegreesX));
473
474   scale_about_pivot->SetChild(perspective.release());
475   translation->SetChild(scale_about_pivot.release());
476   rotation->SetChild(translation.release());
477   rotation->SetReversed(show);
478
479   scoped_ptr<ui::LayerAnimationElement> transition(
480       ui::LayerAnimationElement::CreateInterpolatedTransformElement(
481           rotation.release(), duration));
482   ui::LayerAnimationSequence* last_sequence =
483       new ui::LayerAnimationSequence(transition.release());
484   window->layer()->GetAnimator()->ScheduleAnimation(last_sequence);
485
486   if (observer) {
487     observer->SetLastSequence(last_sequence);
488     observer->DetachAndRecreateLayers();
489   }
490 }
491
492 void AnimateShowWindow_Rotate(aura::Window* window) {
493   AddLayerAnimationsForRotate(window, true);
494 }
495
496 void AnimateHideWindow_Rotate(aura::Window* window) {
497   AddLayerAnimationsForRotate(window, false);
498 }
499
500 bool AnimateShowWindow(aura::Window* window) {
501   if (!HasWindowVisibilityAnimationTransition(window, ANIMATE_SHOW)) {
502     if (HasWindowVisibilityAnimationTransition(window, ANIMATE_HIDE)) {
503       // Since hide animation may have changed opacity and transform,
504       // reset them to show the window.
505       window->layer()->SetOpacity(kWindowAnimation_ShowOpacity);
506       window->layer()->SetTransform(gfx::Transform());
507     }
508     return false;
509   }
510
511   switch (GetWindowVisibilityAnimationType(window)) {
512     case WINDOW_VISIBILITY_ANIMATION_TYPE_DROP:
513       AnimateShowWindow_Drop(window);
514       return true;
515     case WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL:
516       AnimateShowWindow_Vertical(window);
517       return true;
518     case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE:
519       AnimateShowWindow_Fade(window);
520       return true;
521     case WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE:
522       AnimateShowWindow_Rotate(window);
523       return true;
524     default:
525       return false;
526   }
527 }
528
529 bool AnimateHideWindow(aura::Window* window) {
530   if (!HasWindowVisibilityAnimationTransition(window, ANIMATE_HIDE)) {
531     if (HasWindowVisibilityAnimationTransition(window, ANIMATE_SHOW)) {
532       // Since show animation may have changed opacity and transform,
533       // reset them, though the change should be hidden.
534       window->layer()->SetOpacity(kWindowAnimation_HideOpacity);
535       window->layer()->SetTransform(gfx::Transform());
536     }
537     return false;
538   }
539
540   switch (GetWindowVisibilityAnimationType(window)) {
541     case WINDOW_VISIBILITY_ANIMATION_TYPE_DROP:
542       AnimateHideWindow_Drop(window);
543       return true;
544     case WINDOW_VISIBILITY_ANIMATION_TYPE_VERTICAL:
545       AnimateHideWindow_Vertical(window);
546       return true;
547     case WINDOW_VISIBILITY_ANIMATION_TYPE_FADE:
548       AnimateHideWindow_Fade(window);
549       return true;
550     case WINDOW_VISIBILITY_ANIMATION_TYPE_ROTATE:
551       AnimateHideWindow_Rotate(window);
552       return true;
553     default:
554       return false;
555   }
556 }
557
558 }  // namespace
559
560 ////////////////////////////////////////////////////////////////////////////////
561 // ImplicitHidingWindowAnimationObserver
562
563 ImplicitHidingWindowAnimationObserver::ImplicitHidingWindowAnimationObserver(
564     aura::Window* window,
565     ui::ScopedLayerAnimationSettings* settings)
566     : HidingWindowAnimationObserverBase(window) {
567   settings->AddObserver(this);
568 }
569
570 void ImplicitHidingWindowAnimationObserver::OnImplicitAnimationsCompleted() {
571   OnAnimationCompleted();
572 }
573
574 ////////////////////////////////////////////////////////////////////////////////
575 // ScopedHidingAnimationSettings
576
577 ScopedHidingAnimationSettings::ScopedHidingAnimationSettings(
578     aura::Window* window)
579     : layer_animation_settings_(window->layer()->GetAnimator()),
580       observer_(new ImplicitHidingWindowAnimationObserver(
581           window,
582           &layer_animation_settings_)) {
583 }
584
585 ScopedHidingAnimationSettings::~ScopedHidingAnimationSettings() {
586   observer_->DetachAndRecreateLayers();
587 }
588
589 ////////////////////////////////////////////////////////////////////////////////
590 // External interface
591
592 void SetWindowVisibilityAnimationType(aura::Window* window, int type) {
593   window->SetProperty(kWindowVisibilityAnimationTypeKey, type);
594 }
595
596 int GetWindowVisibilityAnimationType(aura::Window* window) {
597   return window->GetProperty(kWindowVisibilityAnimationTypeKey);
598 }
599
600 void SetWindowVisibilityAnimationTransition(
601     aura::Window* window,
602     WindowVisibilityAnimationTransition transition) {
603   window->SetProperty(kWindowVisibilityAnimationTransitionKey, transition);
604 }
605
606 bool HasWindowVisibilityAnimationTransition(
607     aura::Window* window,
608     WindowVisibilityAnimationTransition transition) {
609   WindowVisibilityAnimationTransition prop = window->GetProperty(
610       kWindowVisibilityAnimationTransitionKey);
611   return (prop & transition) != 0;
612 }
613
614 void SetWindowVisibilityAnimationDuration(aura::Window* window,
615                                           const base::TimeDelta& duration) {
616   window->SetProperty(kWindowVisibilityAnimationDurationKey,
617                       static_cast<int>(duration.ToInternalValue()));
618 }
619
620 base::TimeDelta GetWindowVisibilityAnimationDuration(
621     const aura::Window& window) {
622   return base::TimeDelta::FromInternalValue(
623       window.GetProperty(kWindowVisibilityAnimationDurationKey));
624 }
625
626 void SetWindowVisibilityAnimationVerticalPosition(aura::Window* window,
627                                                   float position) {
628   window->SetProperty(kWindowVisibilityAnimationVerticalPositionKey, position);
629 }
630
631 bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) {
632   if (WindowAnimationsDisabled(window))
633     return false;
634   if (visible)
635     return AnimateShowWindow(window);
636   // Don't start hiding the window again if it's already being hidden.
637   return window->layer()->GetTargetOpacity() != 0.0f &&
638       AnimateHideWindow(window);
639 }
640
641 bool AnimateWindow(aura::Window* window, WindowAnimationType type) {
642   switch (type) {
643   case WINDOW_ANIMATION_TYPE_BOUNCE:
644     AnimateBounce(window);
645     return true;
646   default:
647     NOTREACHED();
648     return false;
649   }
650 }
651
652 bool WindowAnimationsDisabled(aura::Window* window) {
653   // Individual windows can choose to skip animations.
654   if (window && window->GetProperty(aura::client::kAnimationsDisabledKey))
655     return true;
656
657   // Animations can be disabled globally for testing.
658   if (CommandLine::ForCurrentProcess()->HasSwitch(
659           switches::kWindowAnimationsDisabled))
660     return true;
661
662   // Tests of animations themselves should still run even if the machine is
663   // being accessed via Remote Desktop.
664   if (ui::ScopedAnimationDurationScaleMode::duration_scale_mode() ==
665       ui::ScopedAnimationDurationScaleMode::NON_ZERO_DURATION)
666     return false;
667
668   // Let the user decide whether or not to play the animation.
669   return !gfx::Animation::ShouldRenderRichAnimation();
670 }
671
672 }  // namespace wm