diff options
author | varkha@chromium.org <varkha@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-01 02:30:20 +0000 |
---|---|---|
committer | varkha@chromium.org <varkha@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-10-01 02:30:20 +0000 |
commit | 9f82d60d7fcbfcef74d32fe5c752a70caf21895c (patch) | |
tree | b26e85543303b91bda7ad5ee638baa4208ac3cfc | |
parent | f88755cb9883731087b639c631ecfefeb913815d (diff) | |
download | chromium_src-9f82d60d7fcbfcef74d32fe5c752a70caf21895c.zip chromium_src-9f82d60d7fcbfcef74d32fe5c752a70caf21895c.tar.gz chromium_src-9f82d60d7fcbfcef74d32fe5c752a70caf21895c.tar.bz2 |
Protect reentrant animations when IMMEDIATELY_ANIMATE_TO_NEW_TARGET is used.
BUG=297974
TEST=TBD
Review URL: https://codereview.chromium.org/25107002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@226111 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r-- | ui/compositor/layer_animation_element.cc | 12 | ||||
-rw-r--r-- | ui/compositor/layer_animation_element.h | 3 | ||||
-rw-r--r-- | ui/compositor/layer_animation_sequence.cc | 9 | ||||
-rw-r--r-- | ui/compositor/layer_animation_sequence.h | 2 | ||||
-rw-r--r-- | ui/compositor/layer_animator_unittest.cc | 62 |
5 files changed, 84 insertions, 4 deletions
diff --git a/ui/compositor/layer_animation_element.cc b/ui/compositor/layer_animation_element.cc index 1448660..c19e750 100644 --- a/ui/compositor/layer_animation_element.cc +++ b/ui/compositor/layer_animation_element.cc @@ -725,7 +725,8 @@ LayerAnimationElement::LayerAnimationElement( tween_type_(gfx::Tween::LINEAR), animation_id_(cc::AnimationIdProvider::NextAnimationId()), animation_group_id_(0), - last_progressed_fraction_(0.0) { + last_progressed_fraction_(0.0), + weak_ptr_factory_(this) { } LayerAnimationElement::LayerAnimationElement( @@ -736,7 +737,8 @@ LayerAnimationElement::LayerAnimationElement( tween_type_(element.tween_type_), animation_id_(cc::AnimationIdProvider::NextAnimationId()), animation_group_id_(element.animation_group_id_), - last_progressed_fraction_(element.last_progressed_fraction_) { + last_progressed_fraction_(element.last_progressed_fraction_), + weak_ptr_factory_(this) { } LayerAnimationElement::~LayerAnimationElement() { @@ -772,7 +774,10 @@ bool LayerAnimationElement::Progress(base::TimeTicks now, base::TimeDelta elapsed = now - effective_start_time_; if ((duration_ > base::TimeDelta()) && (elapsed < duration_)) t = elapsed.InMillisecondsF() / duration_.InMillisecondsF(); + base::WeakPtr<LayerAnimationElement> alive(weak_ptr_factory_.GetWeakPtr()); need_draw = OnProgress(gfx::Tween::CalculateValue(tween_type_, t), delegate); + if (!alive) + return need_draw; first_frame_ = t == 1.0; last_progressed_fraction_ = t; return need_draw; @@ -801,7 +806,10 @@ bool LayerAnimationElement::IsFinished(base::TimeTicks time, bool LayerAnimationElement::ProgressToEnd(LayerAnimationDelegate* delegate) { if (first_frame_) OnStart(delegate); + base::WeakPtr<LayerAnimationElement> alive(weak_ptr_factory_.GetWeakPtr()); bool need_draw = OnProgress(1.0, delegate); + if (!alive) + return need_draw; last_progressed_fraction_ = 1.0; first_frame_ = true; return need_draw; diff --git a/ui/compositor/layer_animation_element.h b/ui/compositor/layer_animation_element.h index 0c8a075..1127424 100644 --- a/ui/compositor/layer_animation_element.h +++ b/ui/compositor/layer_animation_element.h @@ -7,6 +7,7 @@ #include <set> +#include "base/memory/weak_ptr.h" #include "base/time/time.h" #include "cc/animation/animation.h" #include "cc/animation/animation_events.h" @@ -231,6 +232,8 @@ class COMPOSITOR_EXPORT LayerAnimationElement { double last_progressed_fraction_; + base::WeakPtrFactory<LayerAnimationElement> weak_ptr_factory_; + DISALLOW_ASSIGN(LayerAnimationElement); }; diff --git a/ui/compositor/layer_animation_sequence.cc b/ui/compositor/layer_animation_sequence.cc index f336035..9ebf1e0 100644 --- a/ui/compositor/layer_animation_sequence.cc +++ b/ui/compositor/layer_animation_sequence.cc @@ -20,7 +20,8 @@ LayerAnimationSequence::LayerAnimationSequence() last_element_(0), waiting_for_group_start_(false), animation_group_id_(0), - last_progressed_fraction_(0.0) { + last_progressed_fraction_(0.0), + weak_ptr_factory_(this) { } LayerAnimationSequence::LayerAnimationSequence(LayerAnimationElement* element) @@ -28,7 +29,8 @@ LayerAnimationSequence::LayerAnimationSequence(LayerAnimationElement* element) last_element_(0), waiting_for_group_start_(false), animation_group_id_(0), - last_progressed_fraction_(0.0) { + last_progressed_fraction_(0.0), + weak_ptr_factory_(this) { AddElement(element); } @@ -81,8 +83,11 @@ void LayerAnimationSequence::Progress(base::TimeTicks now, animation_group_id_ = cc::AnimationIdProvider::NextGroupId(); elements_[current_index]->Start(delegate, animation_group_id_); } + base::WeakPtr<LayerAnimationSequence> alive(weak_ptr_factory_.GetWeakPtr()); if (elements_[current_index]->Progress(now, delegate)) redraw_required = true; + if (!alive) + return; last_progressed_fraction_ = elements_[current_index]->last_progressed_fraction(); } diff --git a/ui/compositor/layer_animation_sequence.h b/ui/compositor/layer_animation_sequence.h index 854785a..53ce8d6 100644 --- a/ui/compositor/layer_animation_sequence.h +++ b/ui/compositor/layer_animation_sequence.h @@ -182,6 +182,8 @@ class COMPOSITOR_EXPORT LayerAnimationSequence // element. double last_progressed_fraction_; + base::WeakPtrFactory<LayerAnimationSequence> weak_ptr_factory_; + DISALLOW_COPY_AND_ASSIGN(LayerAnimationSequence); }; diff --git a/ui/compositor/layer_animator_unittest.cc b/ui/compositor/layer_animator_unittest.cc index b01a1c3..23052d7 100644 --- a/ui/compositor/layer_animator_unittest.cc +++ b/ui/compositor/layer_animator_unittest.cc @@ -1899,6 +1899,68 @@ TEST(LayerAnimatorTest, ObserverDeletesAnimationsOnEnd) { animator->RemoveObserver(observer.get()); } +// Ensure that stopping animation in a bounds change does not crash and that +// animation gets stopped correctly. +// This scenario is possible when animation is restarted from inside a +// callback triggered by the animation progress. +TEST(LayerAnimatorTest, CallbackDeletesAnimationInProgress) { + + class TestLayerAnimationDeletingDelegate : public TestLayerAnimationDelegate { + public: + TestLayerAnimationDeletingDelegate(LayerAnimator* animator, int max_width) + : animator_(animator), + max_width_(max_width) { + } + + virtual void SetBoundsFromAnimation(const gfx::Rect& bounds) OVERRIDE { + TestLayerAnimationDelegate::SetBoundsFromAnimation(bounds); + if (bounds.width() > max_width_) + animator_->StopAnimating(); + } + private: + LayerAnimator* animator_; + int max_width_; + // Allow copy and assign. + }; + + ScopedAnimationDurationScaleMode normal_duration_mode( + ScopedAnimationDurationScaleMode::NORMAL_DURATION); + scoped_refptr<LayerAnimator> animator(new TestLayerAnimator()); + AnimationContainerElement* element = animator.get(); + animator->set_disable_timer_for_test(true); + TestLayerAnimationDeletingDelegate delegate(animator.get(), 30); + animator->SetDelegate(&delegate); + + gfx::Rect start_bounds(0, 0, 0, 0); + gfx::Rect target_bounds(5, 5, 50, 50); + + delegate.SetBoundsFromAnimation(start_bounds); + + base::TimeDelta bounds_delta1 = base::TimeDelta::FromMilliseconds(333); + base::TimeDelta bounds_delta2 = base::TimeDelta::FromMilliseconds(666); + base::TimeDelta bounds_delta = base::TimeDelta::FromMilliseconds(1000); + base::TimeDelta final_delta = base::TimeDelta::FromMilliseconds(1500); + + animator->StartAnimation(new LayerAnimationSequence( + LayerAnimationElement::CreateBoundsElement( + target_bounds, bounds_delta))); + ASSERT_TRUE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS)); + + base::TimeTicks start_time = animator->last_step_time(); + ASSERT_NO_FATAL_FAILURE(element->Step(start_time + bounds_delta1)); + ASSERT_TRUE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS)); + + // The next step should change the animated bounds past the threshold and + // cause the animaton to stop. + ASSERT_NO_FATAL_FAILURE(element->Step(start_time + bounds_delta2)); + ASSERT_FALSE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS)); + ASSERT_NO_FATAL_FAILURE(element->Step(start_time + final_delta)); + + // Completing the animation should have stopped the bounds + // animation. + ASSERT_FALSE(animator->IsAnimatingProperty(LayerAnimationElement::BOUNDS)); +} + // Similar to the ObserverDeletesAnimationsOnEnd test above except that it // tests the behavior when the OnLayerAnimationAborted() callback causes // all of the animator's other animations to be deleted. |