Home | History | Annotate | Download | only in core
      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
    673