Chromium Code Reviews| Index: ui/wm/core/window_animations.cc |
| diff --git a/ui/wm/core/window_animations.cc b/ui/wm/core/window_animations.cc |
| index feccce36c3a3ebb5a0f258bd29866c949b16ca2f..b113ede442d05431670ee4c5dc7f0499e651af7f 100644 |
| --- a/ui/wm/core/window_animations.cc |
| +++ b/ui/wm/core/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" |
| @@ -42,10 +43,6 @@ DECLARE_WINDOW_PROPERTY_TYPE(views::corewm::WindowVisibilityAnimationTransition) |
| DECLARE_WINDOW_PROPERTY_TYPE(float) |
| DECLARE_EXPORTED_WINDOW_PROPERTY_TYPE(WM_CORE_EXPORT, bool) |
| -using aura::Window; |
| -using base::TimeDelta; |
| -using ui::Layer; |
| - |
| namespace views { |
| namespace corewm { |
| namespace { |
| @@ -83,6 +80,11 @@ const float kWindowAnimation_Bounce_Scale = 1.02f; |
| const int kWindowAnimation_Bounce_DurationMS = 180; |
| const int kWindowAnimation_Bounce_GrowShrinkDurationPercent = 40; |
| +class HidingWindowAnimationObserver; |
| +DEFINE_WINDOW_PROPERTY_KEY(HidingWindowAnimationObserver*, |
| + kHidingWindowAnimationObserverKey, |
| + NULL); |
| + |
| base::TimeDelta GetWindowVisibilityAnimationDuration( |
| const aura::Window& window) { |
| int duration = |
| @@ -91,7 +93,7 @@ base::TimeDelta GetWindowVisibilityAnimationDuration( |
| return base::TimeDelta::FromMilliseconds( |
| kDefaultAnimationDurationForMenuMS); |
| } |
| - return TimeDelta::FromInternalValue(duration); |
| + return base::TimeDelta::FromInternalValue(duration); |
| } |
| // Gets/sets the WindowVisibilityAnimationType associated with a window. |
| @@ -119,19 +121,27 @@ int GetWindowVisibilityAnimationType(aura::Window* window) { |
| // 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. |
| +// In addition, a window being hidden can be hidden by a new focused/active |
| +// window, in which case, a user may not see the hiding animation. This class |
| +// also provides a method |DetachAndRecreateLayers| so that the animating |
| +// layer can stay above the new active window while keeping the |
| +// z-order of window and its layer in sync. |
| 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->SetProperty(kHidingWindowAnimationObserverKey, this); |
| + window->AddObserver(this); |
| + if (settings) |
| + settings->AddObserver(this); |
| } |
| + |
| virtual ~HidingWindowAnimationObserver() { |
| - STLDeleteElements(&layers_); |
| } |
| - private: |
| - // Overridden from ui::ImplicitAnimationObserver: |
| + // ui::ImplicitAnimationObserver: |
| virtual void OnImplicitAnimationsCompleted() OVERRIDE { |
| // Window may have been destroyed by this point. |
| if (window_) { |
| @@ -140,15 +150,19 @@ class HidingWindowAnimationObserver : public ui::ImplicitAnimationObserver, |
| if (animation_host) |
| animation_host->OnWindowHidingAnimationCompleted(); |
| window_->RemoveObserver(this); |
| + window_->ClearProperty(kHidingWindowAnimationObserverKey); |
| } |
| delete this; |
| } |
| - // Overridden from aura::WindowObserver: |
| + // aura::WindowObserver: |
| virtual void OnWindowDestroying(aura::Window* window) OVERRIDE { |
| DCHECK_EQ(window, window_); |
| DCHECK(layers_.empty()); |
| - AcquireAllLayers(window_->layer()); |
| + // No need to acquire layers if the animating layers have already |
| + // been detached. |
| + if (!layer_owner_) |
| + AcquireAllLayers(window_->layer()); |
| window_->RemoveObserver(this); |
| window_ = NULL; |
| } |
| @@ -159,19 +173,60 @@ class HidingWindowAnimationObserver : public ui::ImplicitAnimationObserver, |
| DCHECK_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); |
| } |
| + 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()); |
| + } |
| + } |
| + |
| + // TODO(sky): The recreated layer should have the target visibility of |
| + // the original layer. |
| + // Make the new layer invisible immediately. |
| + window_->layer()->SetVisible(false); |
| + window_->layer()->SetOpacity(0); |
| + } |
| + |
| + private: |
| aura::Window* window_; |
| - std::vector<ui::Layer*> layers_; |
| + |
| + // Stores acquired layers upon deletion. |
| + ScopedVector<ui::Layer> layers_; |
| + |
| + // The owner of detached layers. |
| + scoped_ptr<ui::LayerTreeOwner> layer_owner_; |
| DISALLOW_COPY_AND_ASSIGN(HidingWindowAnimationObserver); |
| }; |
| void GetTransformRelativeToRoot(ui::Layer* layer, gfx::Transform* transform) { |
| - const Layer* root = layer; |
| + const ui::Layer* root = layer; |
| while (root->parent()) |
| root = root->parent(); |
| layer->GetTargetTransformRelativeTo(root, transform); |
| @@ -254,12 +309,12 @@ void AnimateHideWindowCommon(aura::Window* window, |
| window->layer()->set_delegate(NULL); |
| // Property sets within this scope will be implicitly animated. |
| - ui::ScopedLayerAnimationSettings settings(window->layer()->GetAnimator()); |
| - settings.AddObserver(new HidingWindowAnimationObserver(window)); |
| + ScopedHidingAnimationSettings hiding_settings(window); |
| + hiding_settings.set_ensure_visible_after_focus_lost(true); |
| base::TimeDelta duration = GetWindowVisibilityAnimationDuration(*window); |
| if (duration.ToInternalValue() > 0) |
| - settings.SetTransitionDuration(duration); |
| + hiding_settings.layer_animation_settings()->SetTransitionDuration(duration); |
| window->layer()->SetOpacity(kWindowAnimation_HideOpacity); |
| window->layer()->SetTransform(end_transform); |
| @@ -358,8 +413,11 @@ void AddLayerAnimationsForRotate(aura::Window* window, bool show) { |
| base::TimeDelta duration = base::TimeDelta::FromMilliseconds( |
| kWindowAnimation_Rotate_DurationMS); |
| + HidingWindowAnimationObserver* observer = NULL; |
| + |
| if (!show) { |
| - new HidingWindowAnimationObserver(window); |
| + // TODO(oshima): Fix observer leak. |
| + observer = new HidingWindowAnimationObserver(window, NULL); |
| window->layer()->GetAnimator()->SchedulePauseForProperties( |
| duration * (100 - kWindowAnimation_Rotate_OpacityDurationPercent) / 100, |
| ui::LayerAnimationElement::OPACITY); |
| @@ -407,6 +465,8 @@ void AddLayerAnimationsForRotate(aura::Window* window, bool show) { |
| window->layer()->GetAnimator()->ScheduleAnimation( |
| new ui::LayerAnimationSequence(transition.release())); |
| + if (observer) |
| + observer->DetachAndRecreateLayers(); |
| } |
| void AnimateShowWindow_Rotate(aura::Window* window) { |
| @@ -479,6 +539,22 @@ bool AnimateHideWindow(aura::Window* window) { |
| } // namespace |
| +ScopedHidingAnimationSettings::ScopedHidingAnimationSettings( |
| + aura::Window* window) |
| + : window_(window), |
| + ensure_visibility_after_focus_lost_(false), |
| + layer_animation_settings_(window->layer()->GetAnimator()) { |
| + new HidingWindowAnimationObserver(window, &layer_animation_settings_); |
| +} |
| + |
| +ScopedHidingAnimationSettings::~ScopedHidingAnimationSettings() { |
| + HidingWindowAnimationObserver* observer = |
|
sky
2014/03/13 22:34:05
Why isn't this a member?
|
| + window_->GetProperty(kHidingWindowAnimationObserverKey); |
| + DCHECK(observer); |
| + if (ensure_visibility_after_focus_lost_) |
| + observer->DetachAndRecreateLayers(); |
| +} |
| + |
| //////////////////////////////////////////////////////////////////////////////// |
| // External interface |
| @@ -505,7 +581,7 @@ bool HasWindowVisibilityAnimationTransition( |
| } |
| void SetWindowVisibilityAnimationDuration(aura::Window* window, |
| - const TimeDelta& duration) { |
| + const base::TimeDelta& duration) { |
| window->SetProperty(kWindowVisibilityAnimationDurationKey, |
| static_cast<int>(duration.ToInternalValue())); |
| } |
| @@ -521,11 +597,6 @@ void SetWindowVisibilityAnimationVerticalPosition(aura::Window* window, |
| window->SetProperty(kWindowVisibilityAnimationVerticalPositionKey, position); |
| } |
| -ui::ImplicitAnimationObserver* CreateHidingWindowAnimationObserver( |
| - aura::Window* window) { |
| - return new HidingWindowAnimationObserver(window); |
| -} |
| - |
| bool AnimateOnChildWindowVisibilityChanged(aura::Window* window, bool visible) { |
| if (WindowAnimationsDisabled(window)) |
| return false; |