Chromium Code Reviews| Index: ui/views/corewm/window_animations.cc |
| diff --git a/ui/views/corewm/window_animations.cc b/ui/views/corewm/window_animations.cc |
| index 42b26413129abdd166b339cd15de902c2393946e..4db45f78bc15edd90eb7ef442a2b31e6cdc53f75 100644 |
| --- a/ui/views/corewm/window_animations.cc |
| +++ b/ui/views/corewm/window_animations.cc |
| @@ -26,6 +26,7 @@ |
| #include "ui/compositor/layer_animation_observer.h" |
| #include "ui/compositor/layer_animation_sequence.h" |
| #include "ui/compositor/layer_animator.h" |
| +#include "ui/compositor/layer_tree_owner.h" |
| #include "ui/compositor/scoped_layer_animation_settings.h" |
| #include "ui/gfx/animation/animation.h" |
| #include "ui/gfx/interpolated_transform.h" |
| @@ -107,31 +108,22 @@ int GetWindowVisibilityAnimationType(aura::Window* window) { |
| return type; |
| } |
| -// Observes a hide animation. |
| -// A window can be hidden for a variety of reasons. Sometimes, Hide() will be |
| -// called and life is simple. Sometimes, the window is actually bound to a |
| -// views::Widget and that Widget is closed, and life is a little more |
| -// complicated. When a Widget is closed the aura::Window* is actually not |
| -// destroyed immediately - it is actually just immediately hidden and then |
| -// destroyed when the stack unwinds. To handle this case, we start the hide |
| -// animation immediately when the window is hidden, then when the window is |
| -// subsequently destroyed this object acquires ownership of the window's layer, |
| -// so that it can continue animating it until the animation completes. |
| -// Regardless of whether or not the window is destroyed, this object deletes |
| -// itself when the animation completes. |
| +// A base class for hiding animation observer. This calls |
| +// AnimationHost::OnWindowHidingAnimationCompleted upon completion. |
| class HidingWindowAnimationObserver : public ui::ImplicitAnimationObserver, |
| public aura::WindowObserver { |
| public: |
| - explicit HidingWindowAnimationObserver(aura::Window* window) |
| + HidingWindowAnimationObserver(aura::Window* window, |
| + ui::ScopedLayerAnimationSettings* settings) |
| : window_(window) { |
| - window_->AddObserver(this); |
| + window->AddObserver(this); |
| + if (settings) |
| + settings->AddObserver(this); |
| } |
| + |
| virtual ~HidingWindowAnimationObserver() { |
| - STLDeleteElements(&layers_); |
| } |
| - private: |
| - // Overridden from ui::ImplicitAnimationObserver: |
| virtual void OnImplicitAnimationsCompleted() OVERRIDE { |
| // Window may have been destroyed by this point. |
| if (window_) { |
| @@ -144,30 +136,66 @@ class HidingWindowAnimationObserver : public ui::ImplicitAnimationObserver, |
| delete this; |
| } |
| + virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { |
| + DCHECK_EQ(window, window_); |
| + window_->RemoveObserver(this); |
| + window_ = NULL; |
| + } |
| + |
| + protected: |
| + aura::Window* window_; |
| + |
| + private: |
| + DISALLOW_COPY_AND_ASSIGN(HidingWindowAnimationObserver); |
| +}; |
| + |
| +// A window can be hidden for a variety of reasons. Sometimes, Hide() will be |
| +// called and life is simple. Sometimes, the window is actually bound to a |
| +// views::Widget and that Widget is closed, and life is a little more |
| +// complicated. When a Widget is closed the aura::Window* is actually not |
| +// destroyed immediately - it is actually just immediately hidden and then |
| +// destroyed when the stack unwinds. To handle this case, we start the hide |
| +// animation immediately when the window is hidden, then when the window is |
| +// subsequently destroyed this object acquires ownership of the window's layer, |
| +// so that it can continue animating it until the animation completes. |
| +// Regardless of whether or not the window is destroyed, this object deletes |
| +// itself when the animation completes. |
| +class DetachLayersWhenDestroyedAnimationObserver |
| + : public HidingWindowAnimationObserver { |
| + public: |
| + DetachLayersWhenDestroyedAnimationObserver( |
| + aura::Window* window, |
| + ui::ScopedLayerAnimationSettings* settings) |
| + : HidingWindowAnimationObserver(window, settings) { |
| + } |
| + |
| + virtual ~DetachLayersWhenDestroyedAnimationObserver() { |
| + STLDeleteElements(&layers_); |
| + } |
| + |
| + private: |
| // Overridden from aura::WindowObserver: |
| virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { |
| DCHECK_EQ(window, window_); |
| DCHECK(layers_.empty()); |
| AcquireAllLayers(window_->layer()); |
| - window_->RemoveObserver(this); |
| - window_ = NULL; |
| + HidingWindowAnimationObserver::OnWindowDestroying(window); |
| } |
| void AcquireAllLayers(ui::Layer* layer) { |
| if (layer->owner()) { |
| ui::Layer* released = layer->owner()->AcquireLayer(); |
| - DCHECK_EQ(layer, released); |
| + CHECK_EQ(layer, released); |
| layers_.push_back(released); |
| } |
| - std::vector<Layer*>::const_iterator it = layer->children().begin(); |
| + std::vector<ui::Layer*>::const_iterator it = layer->children().begin(); |
| for (; it != layer->children().end(); ++it) |
| AcquireAllLayers(*it); |
| } |
| - aura::Window* window_; |
| std::vector<ui::Layer*> layers_; |
|
sky
2014/03/11 19:16:23
Used a ScopedVector here?
|
| - DISALLOW_COPY_AND_ASSIGN(HidingWindowAnimationObserver); |
| + DISALLOW_COPY_AND_ASSIGN(DetachLayersWhenDestroyedAnimationObserver); |
| }; |
| void GetTransformRelativeToRoot(ui::Layer* layer, gfx::Transform* transform) { |
| @@ -255,7 +283,8 @@ void AnimateHideWindowCommon(aura::Window* window, |
| // Property sets within this scope will be implicitly animated. |
| ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); |
| - settings.AddObserver(new HidingWindowAnimationObserver(window)); |
| + scoped_ptr<LayerDetacherForHidingAnimation> detacher = |
| + DetachAndRecreateLayersForHidingAnimation(window, &settings); |
| base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window); |
| if (duration.ToInternalValue() > 0) |
| @@ -358,8 +387,11 @@ void AddLayerAnimationsForRotate(aura::Window* window, bool show) { |
| base::TimeDelta duration = base::TimeDelta::FromMilliseconds( |
| kWindowAnimation_Rotate_DurationMS); |
| + scoped_ptr<LayerDetacherForHidingAnimation> layer_detacher; |
| if (!show) { |
| - new HidingWindowAnimationObserver(window); |
| + // TODO(oshima): Fix observer leak. |
| + layer_detacher = |
| + DetachAndRecreateLayersForHidingAnimation(window, NULL).Pass(); |
| window->layer()->GetAnimator()->SchedulePauseForProperties( |
| duration * (100 - kWindowAnimation_Rotate_OpacityDurationPercent) / 100, |
| ui::LayerAnimationElement::OPACITY); |
| @@ -479,6 +511,72 @@ bool AnimateHideWindow(aura::Window* window) { |
| } // namespace |
| +// When hiding an active window, the animating layer can be hidden by |
| +// new active window's layer. This class detaches the layers for |
| +// hiding animation, creates new layers for the window and stacks them |
| +// above the window and its transient children so that the layer for |
| +// new active window will not hide the hiding animation. |
| +class DetachAndRecreateLayersAnimationObserver |
| + : HidingWindowAnimationObserver { |
| + public: |
| + DetachAndRecreateLayersAnimationObserver( |
| + aura::Window* window, |
| + ui::ScopedLayerAnimationSettings* settings) |
| + : HidingWindowAnimationObserver(window, settings) { |
| + } |
| + |
| + virtual ~DetachAndRecreateLayersAnimationObserver() { |
| + } |
| + |
| + void DetachAndRecreateLayers() { |
| + layer_owner_ = RecreateLayers(window_); |
| + // If the window has transient children, move above the top most |
| + // transient child so that activation change does not put the |
| + // window above the animating layer. |
| + if(window_->parent()) { |
| + const aura::Window::Windows& transient_children = |
| + GetTransientChildren(window_); |
| + aura::Window::Windows::const_iterator iter = |
| + std::find(window_->parent()->children().begin(), |
| + window_->parent()->children().end(), |
| + window_); |
| + DCHECK(iter != window_->parent()->children().end()); |
| + aura::Window* topmost_transient_child = NULL; |
| + for (++iter; iter != window_->parent()->children().end(); ++iter) { |
| + if (std::find(transient_children.begin(), |
| + transient_children.end(), |
| + *iter) != |
| + transient_children.end()) { |
| + topmost_transient_child = *iter; |
| + } |
| + } |
| + if (topmost_transient_child) { |
| + window_->parent()->layer()->StackAbove( |
| + layer_owner_->root(), topmost_transient_child->layer()); |
| + } |
| + } |
| + // Make the new layer invisible immediately. |
| + window_->layer()->SetVisible(false); |
| + window_->layer()->SetOpacity(0); |
|
sky
2014/03/11 19:16:23
These two calls make me nervous. I think they shou
|
| + } |
| + |
| + private: |
| + scoped_ptr<ui::LayerTreeOwner> layer_owner_; |
| + |
| + DISALLOW_COPY_AND_ASSIGN(DetachAndRecreateLayersAnimationObserver); |
| +}; |
| + |
| +LayerDetacherForHidingAnimation::LayerDetacherForHidingAnimation( |
| + aura::Window* window, |
| + ui::ScopedLayerAnimationSettings* settings) |
| + : observer_( |
| + new DetachAndRecreateLayersAnimationObserver(window, settings)) { |
| +} |
| + |
| +LayerDetacherForHidingAnimation::~LayerDetacherForHidingAnimation() { |
| + observer_->DetachAndRecreateLayers(); |
| +} |
| + |
| //////////////////////////////////////////////////////////////////////////////// |
| // External interface |
| @@ -521,9 +619,18 @@ void SetWindowVisibilityAnimationVerticalPosition(aura::Window* window, |
| window->SetProperty(kWindowVisibilityAnimationVerticalPositionKey, position); |
| } |
| -ui::ImplicitAnimationObserver* CreateHidingWindowAnimationObserver( |
| - aura::Window* window) { |
| - return new HidingWindowAnimationObserver(window); |
| +scoped_ptr<LayerDetacherForHidingAnimation> |
| +DetachAndRecreateLayersForHidingAnimation( |
| + aura::Window* window, |
| + ui::ScopedLayerAnimationSettings* settings) { |
| + return scoped_ptr<LayerDetacherForHidingAnimation>( |
| + new LayerDetacherForHidingAnimation(window, settings)).Pass(); |
| +} |
| + |
| +void DetachLayersForHidingAnimationWhenDestroyed( |
| + aura::Window* window, |
| + ui::ScopedLayerAnimationSettings* settings) { |
| + new DetachLayersWhenDestroyedAnimationObserver(window, settings); |
| } |
| bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) { |