summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorvarkha@chromium.org <varkha@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-01 02:30:20 +0000
committervarkha@chromium.org <varkha@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-10-01 02:30:20 +0000
commit9f82d60d7fcbfcef74d32fe5c752a70caf21895c (patch)
treeb26e85543303b91bda7ad5ee638baa4208ac3cfc
parentf88755cb9883731087b639c631ecfefeb913815d (diff)
downloadchromium_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.cc12
-rw-r--r--ui/compositor/layer_animation_element.h3
-rw-r--r--ui/compositor/layer_animation_sequence.cc9
-rw-r--r--ui/compositor/layer_animation_sequence.h2
-rw-r--r--ui/compositor/layer_animator_unittest.cc62
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.