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_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
    659