summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorvollick@chromium.org <vollick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-12 17:08:22 +0000
committervollick@chromium.org <vollick@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-09-12 17:08:22 +0000
commit2b3db709cc39aaad01bbc8f43d245cef71ead3dc (patch)
treece576b9a4a2fb0a8b826c251b8cc2c51939e19dc /ui
parent4e7c72293596ed6a855a94fdedbb8bc6d91c583d (diff)
downloadchromium_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.cc6
-rw-r--r--ui/compositor/layer.h2
-rw-r--r--ui/compositor/layer_animation_sequence.cc11
-rw-r--r--ui/compositor/layer_animation_sequence.h6
-rw-r--r--ui/compositor/layer_animator.cc139
-rw-r--r--ui/compositor/layer_animator.h37
-rw-r--r--ui/compositor/layer_animator_unittest.cc292
-rw-r--r--ui/views/view_unittest.cc3
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_;