diff options
author | vollick@chromium.org <vollick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-12 17:08:22 +0000 |
---|---|---|
committer | vollick@chromium.org <vollick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2012-09-12 17:08:22 +0000 |
commit | 2b3db709cc39aaad01bbc8f43d245cef71ead3dc (patch) | |
tree | ce576b9a4a2fb0a8b826c251b8cc2c51939e19dc /ui | |
parent | 4e7c72293596ed6a855a94fdedbb8bc6d91c583d (diff) | |
download | chromium_src-2b3db709cc39aaad01bbc8f43d245cef71ead3dc.zip chromium_src-2b3db709cc39aaad01bbc8f43d245cef71ead3dc.tar.gz chromium_src-2b3db709cc39aaad01bbc8f43d245cef71ead3dc.tar.bz2 |
I had originally tried to build upon http://codereview.chromium.org/10869066/, but the number of functions that needed to return (or needed to cope with) DestroyedType's was spiralling out of control and it seemed likely that a mistake would be made and bugs introduced. pkotwicz suggested I make the layer animator ref counted, and this seemed to be a much simpler and safer approach. This way, whenever we're in a LayerAnimator function that may notify observers, we create a scoped_refptr<LayerAnimator> for |this|. If the animator's owning layer gets deleted by an observer, then |this| will be safely destroyed when the function exits and the scoped_refptr falls out of scope.
BUG=147435
TEST=LayerAnimatorTest.ObserverDeletesAnimatorAfter[FinishingAnimation|StoppingAnimation|Scheduling|Aborted]
Review URL: https://chromiumcodereview.appspot.com/10919195
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@156318 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/compositor/layer.cc | 6 | ||||
-rw-r--r-- | ui/compositor/layer.h | 2 | ||||
-rw-r--r-- | ui/compositor/layer_animation_sequence.cc | 11 | ||||
-rw-r--r-- | ui/compositor/layer_animation_sequence.h | 6 | ||||
-rw-r--r-- | ui/compositor/layer_animator.cc | 139 | ||||
-rw-r--r-- | ui/compositor/layer_animator.h | 37 | ||||
-rw-r--r-- | ui/compositor/layer_animator_unittest.cc | 292 | ||||
-rw-r--r-- | ui/views/view_unittest.cc | 3 |
8 files changed, 348 insertions, 148 deletions
diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc index 7e79649..71daa33 100644 --- a/ui/compositor/layer.cc +++ b/ui/compositor/layer.cc @@ -95,7 +95,9 @@ Layer::~Layer() { // Destroying the animator may cause observers to use the layer (and // indirectly the WebLayer). Destroy the animator first so that the WebLayer // is still around. - animator_.reset(); + if (animator_) + animator_->SetDelegate(NULL); + animator_ = NULL; if (compositor_) compositor_->SetRootLayer(NULL); if (parent_) @@ -174,7 +176,7 @@ bool Layer::Contains(const Layer* other) const { void Layer::SetAnimator(LayerAnimator* animator) { if (animator) animator->SetDelegate(this); - animator_.reset(animator); + animator_ = animator; } LayerAnimator* Layer::GetAnimator() { diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h index fa2c474..c150fb3 100644 --- a/ui/compositor/layer.h +++ b/ui/compositor/layer.h @@ -375,7 +375,7 @@ class COMPOSITOR_EXPORT Layer LayerDelegate* delegate_; - scoped_ptr<LayerAnimator> animator_; + scoped_refptr<LayerAnimator> animator_; // Ownership of the layer is held through one of the strongly typed layer // pointers, depending on which sort of layer this is. diff --git a/ui/compositor/layer_animation_sequence.cc b/ui/compositor/layer_animation_sequence.cc index 646c5f1..2a58e1f 100644 --- a/ui/compositor/layer_animation_sequence.cc +++ b/ui/compositor/layer_animation_sequence.cc @@ -31,12 +31,12 @@ LayerAnimationSequence::~LayerAnimationSequence() { DetachedFromSequence(this, true)); } -bool LayerAnimationSequence::Progress(base::TimeDelta elapsed, +void LayerAnimationSequence::Progress(base::TimeDelta elapsed, LayerAnimationDelegate* delegate) { bool redraw_required = false; if (elements_.empty()) - return redraw_required; + return; if (is_cyclic_ && duration_ > base::TimeDelta()) { // If delta = elapsed - last_start_ is huge, we can skip ahead by complete @@ -69,13 +69,16 @@ bool LayerAnimationSequence::Progress(base::TimeDelta elapsed, redraw_required = true; } + // Since the delegate may be deleted due to the notifications below, it is + // important that we schedule a draw before sending them. + if (redraw_required) + delegate->ScheduleDrawForAnimation(); + if (!is_cyclic_ && elapsed == duration_) { last_element_ = 0; last_start_ = base::TimeDelta::FromMilliseconds(0); NotifyEnded(); } - - return redraw_required; } void LayerAnimationSequence::GetTargetValue( diff --git a/ui/compositor/layer_animation_sequence.h b/ui/compositor/layer_animation_sequence.h index 998dd9f..abd3694 100644 --- a/ui/compositor/layer_animation_sequence.h +++ b/ui/compositor/layer_animation_sequence.h @@ -36,9 +36,9 @@ class COMPOSITOR_EXPORT LayerAnimationSequence { // Updates the delegate to the appropriate value for |elapsed|, which is in // the range [0, Duration()]. If the animation is not aborted, it is - // guaranteed that Animate will be called with elapsed = Duration(). - // Returns true if a redraw is required. - bool Progress(base::TimeDelta elapsed, LayerAnimationDelegate* delegate); + // guaranteed that Animate will be called with elapsed = Duration(). Requests + // a redraw if it is required. + void Progress(base::TimeDelta elapsed, LayerAnimationDelegate* delegate); // Sets the target value to the value that would have been set had // the sequence completed. Does nothing if the sequence is cyclic. diff --git a/ui/compositor/layer_animator.cc b/ui/compositor/layer_animator.cc index 5dc3230..2cf25dc 100644 --- a/ui/compositor/layer_animator.cc +++ b/ui/compositor/layer_animator.cc @@ -38,32 +38,6 @@ ui::AnimationContainer* GetAnimationContainer() { } // namespace -class LayerAnimator::DestroyedTracker - : public base::RefCounted<LayerAnimator::DestroyedTracker> { - public: - DestroyedTracker() : is_alive_(true) {} - - // Returns true if the animator is still alive. - bool is_alive() const { return is_alive_; } - - // Invoked when the animator is destroyed. - void AnimatorDeleted() { - DCHECK(is_alive_); - is_alive_ = false; - } - - private: - friend class base::RefCounted<DestroyedTracker>; - - ~DestroyedTracker() { - DCHECK(!is_alive_); - } - - bool is_alive_; - - DISALLOW_COPY_AND_ASSIGN(DestroyedTracker); -}; - // static bool LayerAnimator::disable_animations_for_test_ = false; // static @@ -79,15 +53,14 @@ LayerAnimator::LayerAnimator(base::TimeDelta transition_duration) transition_duration_(transition_duration), tween_type_(Tween::LINEAR), is_started_(false), - disable_timer_for_test_(false), - destroyed_tracker_(new DestroyedTracker) { + disable_timer_for_test_(false) { } LayerAnimator::~LayerAnimator() { for (size_t i = 0; i < running_animations_.size(); ++i) running_animations_[i].sequence->OnAnimatorDestroyed(); - ClearAnimations(); - destroyed_tracker_->AnimatorDeleted(); + ClearAnimationsInternal(); + delegate_ = NULL; } // static @@ -186,11 +159,11 @@ float LayerAnimator::GetTargetGrayscale() const { } void LayerAnimator::SetDelegate(LayerAnimationDelegate* delegate) { - DCHECK(delegate); delegate_ = delegate; } void LayerAnimator::StartAnimation(LayerAnimationSequence* animation) { + scoped_refptr<LayerAnimator> retain(this); OnScheduled(animation); if (!StartSequenceImmediately(animation)) { // Attempt to preempt a running animation. @@ -219,6 +192,7 @@ void LayerAnimator::StartAnimation(LayerAnimationSequence* animation) { } void LayerAnimator::ScheduleAnimation(LayerAnimationSequence* animation) { + scoped_refptr<LayerAnimator> retain(this); OnScheduled(animation); if (is_animating()) { animation_queue_.push_back(make_linked_ptr(animation)); @@ -231,6 +205,8 @@ void LayerAnimator::ScheduleAnimation(LayerAnimationSequence* animation) { void LayerAnimator::ScheduleTogether( const std::vector<LayerAnimationSequence*>& animations) { + scoped_refptr<LayerAnimator> retain(this); + // Collect all the affected properties. LayerAnimationElement::AnimatableProperties animated_properties; std::vector<LayerAnimationSequence*>::const_iterator iter; @@ -286,20 +262,19 @@ bool LayerAnimator::IsAnimatingProperty( void LayerAnimator::StopAnimatingProperty( LayerAnimationElement::AnimatableProperty property) { + scoped_refptr<LayerAnimator> retain(this); while (true) { RunningAnimation* running = GetRunningAnimation(property); if (!running) break; - if (FinishAnimation(running->sequence) == DESTROYED) - return; + FinishAnimation(running->sequence); } } void LayerAnimator::StopAnimating() { - while (is_animating()) { - if (FinishAnimation(running_animations_[0].sequence) == DESTROYED) - return; - } + scoped_refptr<LayerAnimator> retain(this); + while (is_animating()) + FinishAnimation(running_animations_[0].sequence); } void LayerAnimator::AddObserver(LayerAnimationObserver* observer) { @@ -318,9 +293,12 @@ void LayerAnimator::RemoveObserver(LayerAnimationObserver* observer) { // LayerAnimator protected ----------------------------------------------------- -bool LayerAnimator::ProgressAnimation(LayerAnimationSequence* sequence, +void LayerAnimator::ProgressAnimation(LayerAnimationSequence* sequence, base::TimeDelta delta) { - return sequence->Progress(delta, delegate()); + if (!delegate()) + return; + + sequence->Progress(delta, delegate()); } @@ -337,6 +315,7 @@ bool LayerAnimator::HasAnimation(LayerAnimationSequence* sequence) const { void LayerAnimator::Step(base::TimeTicks now) { TRACE_EVENT0("ui", "LayerAnimator::Step"); + scoped_refptr<LayerAnimator> retain(this); last_step_time_ = now; @@ -344,7 +323,6 @@ void LayerAnimator::Step(base::TimeTicks now) { // and finishing them may indirectly affect the collection of running // animations. RunningAnimations running_animations_copy = running_animations_; - bool needs_redraw = false; for (size_t i = 0; i < running_animations_copy.size(); ++i) { if (!HasAnimation(running_animations_copy[i].sequence)) continue; @@ -352,22 +330,10 @@ void LayerAnimator::Step(base::TimeTicks now) { base::TimeDelta delta = now - running_animations_copy[i].start_time; if (delta >= running_animations_copy[i].sequence->duration() && !running_animations_copy[i].sequence->is_cyclic()) { - if (FinishAnimation(running_animations_copy[i].sequence) == DESTROYED) - return; - needs_redraw = true; - } else { - scoped_refptr<DestroyedTracker> tracker(destroyed_tracker_); - const bool progress_result = - ProgressAnimation(running_animations_copy[i].sequence, delta); - if (!tracker->is_alive()) - return; - if (progress_result) - needs_redraw = true; - } + FinishAnimation(running_animations_copy[i].sequence); + } else + ProgressAnimation(running_animations_copy[i].sequence, delta); } - - if (needs_redraw && delegate()) - delegate()->ScheduleDrawForAnimation(); } void LayerAnimator::SetStartTime(base::TimeTicks start_time) { @@ -417,21 +383,17 @@ LayerAnimationSequence* LayerAnimator::RemoveAnimation( return to_return.release(); } -LayerAnimator::DestroyedType LayerAnimator::FinishAnimation( - LayerAnimationSequence* sequence) { +void LayerAnimator::FinishAnimation(LayerAnimationSequence* sequence) { + scoped_refptr<LayerAnimator> retain(this); scoped_ptr<LayerAnimationSequence> removed(RemoveAnimation(sequence)); - { - scoped_refptr<DestroyedTracker> tracker(destroyed_tracker_); + if (delegate()) sequence->Progress(sequence->duration(), delegate()); - if (!tracker->is_alive()) - return DESTROYED; - } ProcessQueue(); UpdateAnimationState(); - return NOT_DESTROYED; } void LayerAnimator::FinishAnyAnimationWithZeroDuration() { + scoped_refptr<LayerAnimator> retain(this); // Special case: if we've started a 0 duration animation, just finish it now // and get rid of it. We need to make a copy because Progress may indirectly // cause new animations to start running. @@ -441,8 +403,8 @@ void LayerAnimator::FinishAnyAnimationWithZeroDuration() { continue; if (running_animations_copy[i].sequence->duration() == base::TimeDelta()) { - running_animations_copy[i].sequence->Progress( - running_animations_copy[i].sequence->duration(), delegate()); + ProgressAnimation(running_animations_copy[i].sequence, + running_animations_copy[i].sequence->duration()); scoped_ptr<LayerAnimationSequence> removed( RemoveAnimation(running_animations_copy[i].sequence)); } @@ -452,23 +414,8 @@ void LayerAnimator::FinishAnyAnimationWithZeroDuration() { } void LayerAnimator::ClearAnimations() { - // Abort should never affect the set of running animations, but just in case - // clients are badly behaved, we will use a copy of the running animations. - RunningAnimations running_animations_copy = running_animations_; - for (size_t i = 0; i < running_animations_copy.size(); ++i) { - if (!HasAnimation(running_animations_copy[i].sequence)) - continue; - - scoped_ptr<LayerAnimationSequence> removed( - RemoveAnimation(running_animations_copy[i].sequence)); - if (removed.get()) - removed->Abort(); - } - // This *should* have cleared the list of running animations. - DCHECK(running_animations_.empty()); - running_animations_.clear(); - animation_queue_.clear(); - UpdateAnimationState(); + scoped_refptr<LayerAnimator> retain(this); + ClearAnimationsInternal(); } LayerAnimator::RunningAnimation* LayerAnimator::GetRunningAnimation( @@ -515,8 +462,8 @@ void LayerAnimator::RemoveAllAnimationsWithACommonProperty( if (abort) running_animations_copy[i].sequence->Abort(); else - running_animations_copy[i].sequence->Progress( - running_animations_copy[i].sequence->duration(), delegate()); + ProgressAnimation(running_animations_copy[i].sequence, + running_animations_copy[i].sequence->duration()); } } @@ -537,7 +484,7 @@ void LayerAnimator::RemoveAllAnimationsWithACommonProperty( if (abort) sequences[i]->Abort(); else - sequences[i]->Progress(sequences[i]->duration(), delegate()); + ProgressAnimation(sequences[i], sequences[i]->duration()); } } } @@ -549,7 +496,7 @@ void LayerAnimator::ImmediatelySetNewTarget(LayerAnimationSequence* sequence) { RemoveAllAnimationsWithACommonProperty(sequence, abort); LayerAnimationSequence* removed = RemoveAnimation(sequence); DCHECK(removed == NULL || removed == sequence); - sequence->Progress(sequence->duration(), delegate()); + ProgressAnimation(sequence, sequence->duration()); } void LayerAnimator::ImmediatelyAnimateToNewTarget( @@ -692,4 +639,24 @@ base::TimeDelta LayerAnimator::GetTransitionDuration() const { return transition_duration_; } +void LayerAnimator::ClearAnimationsInternal() { + // Abort should never affect the set of running animations, but just in case + // clients are badly behaved, we will use a copy of the running animations. + RunningAnimations running_animations_copy = running_animations_; + for (size_t i = 0; i < running_animations_copy.size(); ++i) { + if (!HasAnimation(running_animations_copy[i].sequence)) + continue; + + scoped_ptr<LayerAnimationSequence> removed( + RemoveAnimation(running_animations_copy[i].sequence)); + if (removed.get()) + removed->Abort(); + } + // This *should* have cleared the list of running animations. + DCHECK(running_animations_.empty()); + running_animations_.clear(); + animation_queue_.clear(); + UpdateAnimationState(); +} + } // namespace ui diff --git a/ui/compositor/layer_animator.h b/ui/compositor/layer_animator.h index 6de0b92..0c92a81 100644 --- a/ui/compositor/layer_animator.h +++ b/ui/compositor/layer_animator.h @@ -34,8 +34,14 @@ class Transform; // When a property of layer needs to be changed it is set by way of // LayerAnimator. This enables LayerAnimator to animate property changes. // NB: during many tests, set_disable_animations_for_test is used and causes -// all animations to complete immediately. -class COMPOSITOR_EXPORT LayerAnimator : public AnimationContainerElement { +// all animations to complete immediately. The layer animation is ref counted +// so that if its owning layer is deleted (and the owning layer is only other +// class that should ever hold a ref ptr to a LayerAnimator), the animator can +// ensure that it is not disposed of until it finishes executing. It does this +// by holding a reference to itself for the duration of methods for which it +// must guarantee that |this| is valid. +class COMPOSITOR_EXPORT LayerAnimator + : public AnimationContainerElement, public base::RefCounted<LayerAnimator> { public: enum PreemptionStrategy { IMMEDIATELY_SET_NEW_TARGET, @@ -46,7 +52,6 @@ class COMPOSITOR_EXPORT LayerAnimator : public AnimationContainerElement { }; explicit LayerAnimator(base::TimeDelta transition_duration); - virtual ~LayerAnimator(); // No implicit animations when properties are set. static LayerAnimator* CreateDefaultAnimator(); @@ -79,7 +84,9 @@ class COMPOSITOR_EXPORT LayerAnimator : public AnimationContainerElement { float GetTargetGrayscale() const; // Sets the layer animation delegate the animator is associated with. The - // animator does not own the delegate. + // animator does not own the delegate. The layer animator expects a non-NULL + // delegate for most of its operations, so do not call any methods without + // a valid delegate installed. void SetDelegate(LayerAnimationDelegate* delegate); // Sets the animation preemption strategy. This determines the behaviour if @@ -174,27 +181,22 @@ class COMPOSITOR_EXPORT LayerAnimator : public AnimationContainerElement { } protected: + virtual ~LayerAnimator(); + LayerAnimationDelegate* delegate() { return delegate_; } const LayerAnimationDelegate* delegate() const { return delegate_; } // Virtual for testing. - virtual bool ProgressAnimation(LayerAnimationSequence* sequence, + virtual void ProgressAnimation(LayerAnimationSequence* sequence, base::TimeDelta delta); // Returns true if the sequence is owned by this animator. bool HasAnimation(LayerAnimationSequence* sequence) const; private: + friend class base::RefCounted<LayerAnimator>; friend class ScopedLayerAnimationSettings; - class DestroyedTracker; - - // Used by FinishAnimation() to indicate if this has been destroyed. - enum DestroyedType { - DESTROYED, - NOT_DESTROYED, - }; - // We need to keep track of the start time of every running animation. struct RunningAnimation { RunningAnimation(LayerAnimationSequence* sequence, @@ -224,8 +226,7 @@ class COMPOSITOR_EXPORT LayerAnimator : public AnimationContainerElement { LayerAnimationSequence* sequence) WARN_UNUSED_RESULT; // Progresses to the end of the sequence before removing it. - DestroyedType FinishAnimation( - LayerAnimationSequence* sequence) WARN_UNUSED_RESULT; + void FinishAnimation(LayerAnimationSequence* sequence); // Finishes any running animation with zero duration. void FinishAnyAnimationWithZeroDuration(); @@ -282,6 +283,10 @@ class COMPOSITOR_EXPORT LayerAnimator : public AnimationContainerElement { // animation mode if set. base::TimeDelta GetTransitionDuration() const; + // Clears the animation queues and notifies any running animations that they + // have been aborted. + void ClearAnimationsInternal(); + // This is the queue of animations to run. AnimationQueue animation_queue_; @@ -323,8 +328,6 @@ class COMPOSITOR_EXPORT LayerAnimator : public AnimationContainerElement { // aborted. ObserverList<LayerAnimationObserver> observers_; - scoped_refptr<DestroyedTracker> destroyed_tracker_; - DISALLOW_COPY_AND_ASSIGN(LayerAnimator); }; diff --git a/ui/compositor/layer_animator_unittest.cc b/ui/compositor/layer_animator_unittest.cc index b01256b..d60fc319 100644 --- a/ui/compositor/layer_animator_unittest.cc +++ b/ui/compositor/layer_animator_unittest.cc @@ -78,13 +78,14 @@ class DeletingLayerAnimationObserver : public LayerAnimationObserver { class TestLayerAnimator : public LayerAnimator { public: TestLayerAnimator() : LayerAnimator(base::TimeDelta::FromSeconds(0)) {} - virtual ~TestLayerAnimator() {} protected: - virtual bool ProgressAnimation(LayerAnimationSequence* sequence, + virtual ~TestLayerAnimator() {} + + virtual void ProgressAnimation(LayerAnimationSequence* sequence, base::TimeDelta delta) OVERRIDE { EXPECT_TRUE(HasAnimation(sequence)); - return LayerAnimator::ProgressAnimation(sequence, delta); + LayerAnimator::ProgressAnimation(sequence, delta); } private: @@ -117,7 +118,8 @@ class TestLayerAnimationSequence : public LayerAnimationSequence { // Checks that setting a property on an implicit animator causes an animation to // happen. TEST(LayerAnimatorTest, ImplicitAnimation) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateImplicitAnimator()); + scoped_refptr<LayerAnimator> animator( + LayerAnimator::CreateImplicitAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -132,7 +134,7 @@ TEST(LayerAnimatorTest, ImplicitAnimation) { // Checks that if the animator is a default animator, that implicit animations // are not started. TEST(LayerAnimatorTest, NoImplicitAnimation) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; animator->SetDelegate(&delegate); @@ -144,7 +146,8 @@ TEST(LayerAnimatorTest, NoImplicitAnimation) { // Checks that StopAnimatingProperty stops animation for that property, and also // skips the stopped animation to the end. TEST(LayerAnimatorTest, StopAnimatingProperty) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateImplicitAnimator()); + scoped_refptr<LayerAnimator> animator( + LayerAnimator::CreateImplicitAnimator()); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; animator->SetDelegate(&delegate); @@ -163,7 +166,8 @@ TEST(LayerAnimatorTest, StopAnimatingProperty) { // Checks that multiple running animation for separate properties can be stopped // simultaneously and that all animations are advanced to their target values. TEST(LayerAnimatorTest, StopAnimating) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateImplicitAnimator()); + scoped_refptr<LayerAnimator> animator( + LayerAnimator::CreateImplicitAnimator()); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; animator->SetDelegate(&delegate); @@ -181,7 +185,7 @@ TEST(LayerAnimatorTest, StopAnimating) { // Schedule an animation that can run immediately. This is the trivial case and // should result in the animation being started immediately. TEST(LayerAnimatorTest, ScheduleAnimationThatCanRunImmediately) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -218,7 +222,7 @@ TEST(LayerAnimatorTest, ScheduleAnimationThatCanRunImmediately) { // Schedule two animations on separate properties. Both animations should // start immediately and should progress in lock step. TEST(LayerAnimatorTest, ScheduleTwoAnimationsThatCanRunImmediately) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -268,7 +272,7 @@ TEST(LayerAnimatorTest, ScheduleTwoAnimationsThatCanRunImmediately) { // Schedule two animations on the same property. In this case, the two // animations should run one after another. TEST(LayerAnimatorTest, ScheduleTwoAnimationsOnSameProperty) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -320,7 +324,7 @@ TEST(LayerAnimatorTest, ScheduleTwoAnimationsOnSameProperty) { // is, ensure that all animations targetting a particular property are run in // order. TEST(LayerAnimatorTest, ScheduleBlockedAnimation) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -398,7 +402,7 @@ TEST(LayerAnimatorTest, ScheduleBlockedAnimation) { // ScheduleTogether is being used, the bounds animation should not start until // the second opacity animation starts. TEST(LayerAnimatorTest, ScheduleTogether) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -451,7 +455,7 @@ TEST(LayerAnimatorTest, ScheduleTogether) { // Start animation (that can run immediately). This is the trivial case (see // the trival case for ScheduleAnimation). TEST(LayerAnimatorTest, StartAnimationThatCanRunImmediately) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -487,7 +491,7 @@ TEST(LayerAnimatorTest, StartAnimationThatCanRunImmediately) { // Preempt by immediately setting new target. TEST(LayerAnimatorTest, PreemptBySettingNewTarget) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; animator->SetDelegate(&delegate); @@ -515,7 +519,7 @@ TEST(LayerAnimatorTest, PreemptBySettingNewTarget) { // Preempt by animating to new target. TEST(LayerAnimatorTest, PreemptByImmediatelyAnimatingToNewTarget) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -567,7 +571,7 @@ TEST(LayerAnimatorTest, PreemptByImmediatelyAnimatingToNewTarget) { // Preempt by enqueuing the new animation. TEST(LayerAnimatorTest, PreemptEnqueueNewAnimation) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -620,7 +624,7 @@ TEST(LayerAnimatorTest, PreemptEnqueueNewAnimation) { // case, all pending and running animations should be finished, and the new // animation started. TEST(LayerAnimatorTest, PreemptyByReplacingQueuedAnimations) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -675,7 +679,7 @@ TEST(LayerAnimatorTest, PreemptyByReplacingQueuedAnimations) { // Test that cyclic sequences continue to animate. TEST(LayerAnimatorTest, CyclicSequences) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -734,7 +738,7 @@ TEST(LayerAnimatorTest, CyclicSequences) { } TEST(LayerAnimatorTest, AddObserverExplicit) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); TestLayerAnimationObserver observer; @@ -768,7 +772,7 @@ TEST(LayerAnimatorTest, AddObserverExplicit) { animator->StartAnimation(sequence); - animator.reset(); + animator = NULL; EXPECT_EQ(observer.last_aborted_sequence(), sequence); } @@ -776,7 +780,7 @@ TEST(LayerAnimatorTest, AddObserverExplicit) { // Tests that an observer added to a scoped settings object is still notified // when the object goes out of scope. TEST(LayerAnimatorTest, ImplicitAnimationObservers) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); TestImplicitAnimationObserver observer(false); @@ -802,7 +806,7 @@ TEST(LayerAnimatorTest, ImplicitAnimationObservers) { // Tests that an observer added to a scoped settings object is still notified // when the object goes out of scope due to the animation being interrupted. TEST(LayerAnimatorTest, InterruptedImplicitAnimationObservers) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); animator->set_disable_timer_for_test(true); TestImplicitAnimationObserver observer(false); TestLayerAnimationDelegate delegate; @@ -828,7 +832,7 @@ TEST(LayerAnimatorTest, InterruptedImplicitAnimationObservers) { // Tests that an observer added to a scoped settings object is not notified // when the animator is destroyed unless explicitly requested. TEST(LayerAnimatorTest, ImplicitObserversAtAnimatorDestruction) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); animator->set_disable_timer_for_test(true); TestImplicitAnimationObserver observer_notify(true); TestImplicitAnimationObserver observer_do_not_notify(false); @@ -849,14 +853,14 @@ TEST(LayerAnimatorTest, ImplicitObserversAtAnimatorDestruction) { EXPECT_FALSE(observer_notify.animations_completed()); EXPECT_FALSE(observer_do_not_notify.animations_completed()); - animator.reset(NULL); + animator = NULL; EXPECT_TRUE(observer_notify.animations_completed()); EXPECT_FALSE(observer_do_not_notify.animations_completed()); } TEST(LayerAnimatorTest, RemoveObserverShouldRemoveFromSequences) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); TestLayerAnimationObserver observer; @@ -891,7 +895,7 @@ TEST(LayerAnimatorTest, RemoveObserverShouldRemoveFromSequences) { } TEST(LayerAnimatorTest, ObserverReleasedBeforeAnimationSequenceEnds) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); animator->set_disable_timer_for_test(true); scoped_ptr<TestLayerAnimationObserver> observer( @@ -919,7 +923,7 @@ TEST(LayerAnimatorTest, ObserverReleasedBeforeAnimationSequenceEnds) { } TEST(LayerAnimatorTest, ObserverAttachedAfterAnimationStarted) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); @@ -952,7 +956,7 @@ TEST(LayerAnimatorTest, ObserverAttachedAfterAnimationStarted) { } TEST(LayerAnimatorTest, ObserverDetachedBeforeAnimationFinished) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); @@ -989,7 +993,7 @@ TEST(LayerAnimatorTest, ObserverDetachedBeforeAnimationFinished) { // animation. TEST(LayerAnimatorTest, ObserverDeletesAnimations) { LayerAnimator::set_disable_animations_for_test(false); - scoped_ptr<LayerAnimator> animator(new TestLayerAnimator()); + scoped_refptr<LayerAnimator> animator(new TestLayerAnimator()); AnimationContainerElement* element = animator.get(); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -1032,7 +1036,7 @@ TEST(LayerAnimatorTest, ObserverDeletesAnimations) { // Check that setting a property during an animation with a default animator // cancels the original animation. TEST(LayerAnimatorTest, SettingPropertyDuringAnAnimation) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; animator->SetDelegate(&delegate); @@ -1059,7 +1063,7 @@ TEST(LayerAnimatorTest, SettingPropertyDuringAnAnimation) { // Tests that the preemption mode IMMEDIATELY_SET_NEW_TARGET, doesn't cause the // second sequence to be leaked. TEST(LayerAnimatorTest, ImmediatelySettingNewTargetDoesNotLeak) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); animator->set_preemption_strategy(LayerAnimator::IMMEDIATELY_SET_NEW_TARGET); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -1099,7 +1103,7 @@ TEST(LayerAnimatorTest, ImmediatelySettingNewTargetDoesNotLeak) { // Verifies GetTargetOpacity() works when multiple sequences are scheduled. TEST(LayerAnimatorTest, GetTargetOpacity) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -1120,7 +1124,7 @@ TEST(LayerAnimatorTest, GetTargetOpacity) { // Verifies GetTargetBrightness() works when multiple sequences are scheduled. TEST(LayerAnimatorTest, GetTargetBrightness) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -1141,7 +1145,7 @@ TEST(LayerAnimatorTest, GetTargetBrightness) { // Verifies GetTargetGrayscale() works when multiple sequences are scheduled. TEST(LayerAnimatorTest, GetTargetGrayscale) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION); animator->set_disable_timer_for_test(true); TestLayerAnimationDelegate delegate; @@ -1162,7 +1166,7 @@ TEST(LayerAnimatorTest, GetTargetGrayscale) { // Verifies SchedulePauseForProperties(). TEST(LayerAnimatorTest, SchedulePauseForProperties) { - scoped_ptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); + scoped_refptr<LayerAnimator> animator(LayerAnimator::CreateDefaultAnimator()); animator->set_preemption_strategy(LayerAnimator::ENQUEUE_NEW_ANIMATION); animator->SchedulePauseForProperties(base::TimeDelta::FromMilliseconds(100), LayerAnimationElement::TRANSFORM, @@ -1172,4 +1176,222 @@ TEST(LayerAnimatorTest, SchedulePauseForProperties) { EXPECT_FALSE(animator->IsAnimatingProperty(LayerAnimationElement::OPACITY)); } + +class AnimatorOwner { +public: + AnimatorOwner() + : animator_(LayerAnimator::CreateDefaultAnimator()) { + } + + LayerAnimator* animator() { return animator_.get(); } + +private: + scoped_refptr<LayerAnimator> animator_; + + DISALLOW_COPY_AND_ASSIGN(AnimatorOwner); +}; + +class DeletingObserver : public LayerAnimationObserver { +public: + DeletingObserver(bool* was_deleted) + : animator_owner_(new AnimatorOwner), + delete_on_animation_ended_(false), + delete_on_animation_aborted_(false), + delete_on_animation_scheduled_(false), + was_deleted_(was_deleted) { + animator()->AddObserver(this); + } + + ~DeletingObserver() { + animator()->RemoveObserver(this); + *was_deleted_ = true; + } + + LayerAnimator* animator() { return animator_owner_->animator(); } + + bool delete_on_animation_ended() const { + return delete_on_animation_ended_; + } + void set_delete_on_animation_ended(bool enabled) { + delete_on_animation_ended_ = enabled; + } + + bool delete_on_animation_aborted() const { + return delete_on_animation_aborted_; + } + void set_delete_on_animation_aborted(bool enabled) { + delete_on_animation_aborted_ = enabled; + } + + bool delete_on_animation_scheduled() const { + return delete_on_animation_scheduled_; + } + void set_delete_on_animation_scheduled(bool enabled) { + delete_on_animation_scheduled_ = enabled; + } + + // LayerAnimationObserver implementation. + virtual void OnLayerAnimationEnded( + LayerAnimationSequence* sequence) OVERRIDE { + if (delete_on_animation_ended_) + delete this; + } + + virtual void OnLayerAnimationAborted( + LayerAnimationSequence* sequence) OVERRIDE { + if (delete_on_animation_aborted_) + delete this; + } + + virtual void OnLayerAnimationScheduled( + LayerAnimationSequence* sequence) { + if (delete_on_animation_scheduled_) + delete this; + } + +private: + scoped_ptr<AnimatorOwner> animator_owner_; + bool delete_on_animation_ended_; + bool delete_on_animation_aborted_; + bool delete_on_animation_scheduled_; + bool* was_deleted_; + + DISALLOW_COPY_AND_ASSIGN(DeletingObserver); +}; + +TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterFinishingAnimation) { + bool observer_was_deleted = false; + DeletingObserver* observer = new DeletingObserver(&observer_was_deleted); + observer->set_delete_on_animation_ended(true); + observer->set_delete_on_animation_aborted(true); + LayerAnimator* animator = observer->animator(); + AnimationContainerElement* element = observer->animator(); + animator->set_disable_timer_for_test(true); + TestLayerAnimationDelegate delegate; + animator->SetDelegate(&delegate); + + delegate.SetOpacityFromAnimation(0.0f); + + gfx::Rect start_bounds(0, 0, 50, 50); + gfx::Rect target_bounds(10, 10, 100, 100); + + delegate.SetBoundsFromAnimation(start_bounds); + + base::TimeDelta delta = base::TimeDelta::FromSeconds(1); + LayerAnimationSequence* opacity_sequence = new LayerAnimationSequence( + LayerAnimationElement::CreateOpacityElement(1.0f, delta)); + animator->StartAnimation(opacity_sequence); + + delta = base::TimeDelta::FromSeconds(2); + LayerAnimationSequence* bounds_sequence = new LayerAnimationSequence( + LayerAnimationElement::CreateBoundsElement(target_bounds, delta)); + animator->StartAnimation(bounds_sequence); + + base::TimeTicks start_time = animator->last_step_time(); + element->Step(start_time + base::TimeDelta::FromMilliseconds(1500)); + + EXPECT_TRUE(observer_was_deleted); +} + +TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterStoppingAnimating) { + bool observer_was_deleted = false; + DeletingObserver* observer = new DeletingObserver(&observer_was_deleted); + observer->set_delete_on_animation_ended(true); + observer->set_delete_on_animation_aborted(true); + LayerAnimator* animator = observer->animator(); + animator->set_disable_timer_for_test(true); + TestLayerAnimationDelegate delegate; + animator->SetDelegate(&delegate); + + delegate.SetOpacityFromAnimation(0.0f); + + gfx::Rect start_bounds(0, 0, 50, 50); + gfx::Rect target_bounds(10, 10, 100, 100); + + delegate.SetBoundsFromAnimation(start_bounds); + + base::TimeDelta delta = base::TimeDelta::FromSeconds(1); + LayerAnimationSequence* opacity_sequence = new LayerAnimationSequence( + LayerAnimationElement::CreateOpacityElement(1.0f, delta)); + animator->StartAnimation(opacity_sequence); + + delta = base::TimeDelta::FromSeconds(2); + LayerAnimationSequence* bounds_sequence = new LayerAnimationSequence( + LayerAnimationElement::CreateBoundsElement(target_bounds, delta)); + animator->StartAnimation(bounds_sequence); + + animator->StopAnimating(); + + EXPECT_TRUE(observer_was_deleted); +} + +TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterScheduling) { + bool observer_was_deleted = false; + DeletingObserver* observer = new DeletingObserver(&observer_was_deleted); + observer->set_delete_on_animation_scheduled(true); + LayerAnimator* animator = observer->animator(); + animator->set_disable_timer_for_test(true); + TestLayerAnimationDelegate delegate; + animator->SetDelegate(&delegate); + + delegate.SetOpacityFromAnimation(0.0f); + + gfx::Rect start_bounds(0, 0, 50, 50); + gfx::Rect target_bounds(10, 10, 100, 100); + + delegate.SetBoundsFromAnimation(start_bounds); + + std::vector<LayerAnimationSequence*> to_start; + + base::TimeDelta delta = base::TimeDelta::FromSeconds(1); + to_start.push_back(new LayerAnimationSequence( + LayerAnimationElement::CreateOpacityElement(1.0f, delta))); + + delta = base::TimeDelta::FromSeconds(2); + to_start.push_back(new LayerAnimationSequence( + LayerAnimationElement::CreateBoundsElement(target_bounds, delta))); + + animator->ScheduleTogether(to_start); + + EXPECT_TRUE(observer_was_deleted); +} + +TEST(LayerAnimatorTest, ObserverDeletesAnimatorAfterAborted) { + bool observer_was_deleted = false; + DeletingObserver* observer = new DeletingObserver(&observer_was_deleted); + observer->set_delete_on_animation_aborted(true); + LayerAnimator* animator = observer->animator(); + animator->set_preemption_strategy( + LayerAnimator::IMMEDIATELY_ANIMATE_TO_NEW_TARGET); + animator->set_disable_timer_for_test(true); + TestLayerAnimationDelegate delegate; + animator->SetDelegate(&delegate); + + delegate.SetOpacityFromAnimation(0.0f); + + gfx::Rect start_bounds(0, 0, 50, 50); + gfx::Rect target_bounds(10, 10, 100, 100); + + delegate.SetBoundsFromAnimation(start_bounds); + + std::vector<LayerAnimationSequence*> to_start; + + base::TimeDelta delta = base::TimeDelta::FromSeconds(1); + to_start.push_back(new LayerAnimationSequence( + LayerAnimationElement::CreateOpacityElement(1.0f, delta))); + + delta = base::TimeDelta::FromSeconds(2); + to_start.push_back(new LayerAnimationSequence( + LayerAnimationElement::CreateBoundsElement(target_bounds, delta))); + + animator->ScheduleTogether(to_start); + + EXPECT_FALSE(observer_was_deleted); + + animator->StartAnimation(new LayerAnimationSequence( + LayerAnimationElement::CreateOpacityElement(1.0f, delta))); + + EXPECT_TRUE(observer_was_deleted); +} + } // namespace ui diff --git a/ui/views/view_unittest.cc b/ui/views/view_unittest.cc index 5b08793..8f27a49 100644 --- a/ui/views/view_unittest.cc +++ b/ui/views/view_unittest.cc @@ -2873,6 +2873,9 @@ class TestLayerAnimator : public ui::LayerAnimator { // LayerAnimator. virtual void SetBounds(const gfx::Rect& bounds) OVERRIDE; + protected: + ~TestLayerAnimator() { } + private: gfx::Rect last_bounds_; |