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