diff options
Diffstat (limited to 'ui/gfx')
-rw-r--r-- | ui/gfx/compositor/layer_animation_element.cc | 10 | ||||
-rw-r--r-- | ui/gfx/compositor/layer_animation_element.h | 4 | ||||
-rw-r--r-- | ui/gfx/compositor/layer_animation_element_unittest.cc | 6 | ||||
-rw-r--r-- | ui/gfx/compositor/layer_animation_observer.h | 3 | ||||
-rw-r--r-- | ui/gfx/compositor/layer_animation_sequence.cc | 4 | ||||
-rw-r--r-- | ui/gfx/compositor/layer_animation_sequence_unittest.cc | 2 | ||||
-rw-r--r-- | ui/gfx/compositor/layer_animator.cc | 180 | ||||
-rw-r--r-- | ui/gfx/compositor/layer_animator.h | 7 | ||||
-rw-r--r-- | ui/gfx/compositor/layer_animator_unittest.cc | 31 | ||||
-rw-r--r-- | ui/gfx/compositor/layer_unittest.cc | 2 |
10 files changed, 150 insertions, 99 deletions
diff --git a/ui/gfx/compositor/layer_animation_element.cc b/ui/gfx/compositor/layer_animation_element.cc index abff5f6..8aca397 100644 --- a/ui/gfx/compositor/layer_animation_element.cc +++ b/ui/gfx/compositor/layer_animation_element.cc @@ -150,7 +150,15 @@ class OpacityTransition : public LayerAnimationElement { // LayerAnimationElement::TargetValue ------------------------------------------ -LayerAnimationElement::TargetValue::TargetValue() : opacity(0.0f) { +LayerAnimationElement::TargetValue::TargetValue() + : opacity(0.0f) { +} + +LayerAnimationElement::TargetValue::TargetValue( + const LayerAnimationDelegate* delegate) + : bounds(delegate ? delegate->GetBoundsForAnimation() : gfx::Rect()), + transform(delegate ? delegate->GetTransformForAnimation() : Transform()), + opacity(delegate ? delegate->GetOpacityForAnimation() : 0.0f) { } // LayerAnimationElement ------------------------------------------------------- diff --git a/ui/gfx/compositor/layer_animation_element.h b/ui/gfx/compositor/layer_animation_element.h index d38bc42..c059f16 100644 --- a/ui/gfx/compositor/layer_animation_element.h +++ b/ui/gfx/compositor/layer_animation_element.h @@ -30,8 +30,10 @@ class COMPOSITOR_EXPORT LayerAnimationElement { }; struct TargetValue { - public: TargetValue(); + // Initializes the target value to match the delegate. NULL may be supplied. + explicit TargetValue(const LayerAnimationDelegate* delegate); + gfx::Rect bounds; Transform transform; float opacity; diff --git a/ui/gfx/compositor/layer_animation_element_unittest.cc b/ui/gfx/compositor/layer_animation_element_unittest.cc index 27940d4..4637e92 100644 --- a/ui/gfx/compositor/layer_animation_element_unittest.cc +++ b/ui/gfx/compositor/layer_animation_element_unittest.cc @@ -44,7 +44,7 @@ TEST(LayerAnimationElementTest, TransformElement) { delegate.GetTransformForAnimation()); } - LayerAnimationElement::TargetValue target_value; + LayerAnimationElement::TargetValue target_value(&delegate); element->GetTargetValue(&target_value); CheckApproximatelyEqual(target_transform, target_value.transform); @@ -74,7 +74,7 @@ TEST(LayerAnimationElementTest, BoundsElement) { CheckApproximatelyEqual(target, delegate.GetBoundsForAnimation()); } - LayerAnimationElement::TargetValue target_value; + LayerAnimationElement::TargetValue target_value(&delegate); element->GetTargetValue(&target_value); CheckApproximatelyEqual(target, target_value.bounds); @@ -102,7 +102,7 @@ TEST(LayerAnimationElementTest, OpacityElement) { EXPECT_FLOAT_EQ(target, delegate.GetOpacityForAnimation()); } - LayerAnimationElement::TargetValue target_value; + LayerAnimationElement::TargetValue target_value(&delegate); element->GetTargetValue(&target_value); EXPECT_FLOAT_EQ(target, target_value.opacity); diff --git a/ui/gfx/compositor/layer_animation_observer.h b/ui/gfx/compositor/layer_animation_observer.h index 1fe031e..e737345 100644 --- a/ui/gfx/compositor/layer_animation_observer.h +++ b/ui/gfx/compositor/layer_animation_observer.h @@ -19,7 +19,8 @@ class COMPOSITOR_EXPORT LayerAnimationObserver { virtual void OnLayerAnimationEnded( const LayerAnimationSequence* sequence) = 0; - // Called if |sequence| is aborted for any reason. + // Called if |sequence| is aborted for any reason. Should never do anything + // that may cause another animation to be started. virtual void OnLayerAnimationAborted( const LayerAnimationSequence* sequence) = 0; diff --git a/ui/gfx/compositor/layer_animation_sequence.cc b/ui/gfx/compositor/layer_animation_sequence.cc index f2e362b..1b408bc 100644 --- a/ui/gfx/compositor/layer_animation_sequence.cc +++ b/ui/gfx/compositor/layer_animation_sequence.cc @@ -30,10 +30,10 @@ LayerAnimationSequence::~LayerAnimationSequence() { void LayerAnimationSequence::Progress(base::TimeDelta elapsed, LayerAnimationDelegate* delegate) { - if (elements_.size() == 0 || duration_ == base::TimeDelta()) + if (elements_.empty()) return; - if (is_cyclic_) { + if (is_cyclic_ && duration_ > base::TimeDelta()) { // If delta = elapsed - last_start_ is huge, we can skip ahead by complete // loops to save time. base::TimeDelta delta = elapsed - last_start_; diff --git a/ui/gfx/compositor/layer_animation_sequence_unittest.cc b/ui/gfx/compositor/layer_animation_sequence_unittest.cc index ff44b58..11c1e8b 100644 --- a/ui/gfx/compositor/layer_animation_sequence_unittest.cc +++ b/ui/gfx/compositor/layer_animation_sequence_unittest.cc @@ -165,7 +165,7 @@ TEST(LayerAnimationSequenceTest, SetTarget) { sequence.AddElement( LayerAnimationElement::CreateOpacityElement(target_opacity, delta)); - LayerAnimationElement::TargetValue target_value; + LayerAnimationElement::TargetValue target_value(&delegate); target_value.opacity = start_opacity; sequence.GetTargetValue(&target_value); EXPECT_FLOAT_EQ(target_opacity, target_value.opacity); diff --git a/ui/gfx/compositor/layer_animator.cc b/ui/gfx/compositor/layer_animator.cc index 14a4bf98..1ec2b78 100644 --- a/ui/gfx/compositor/layer_animator.cc +++ b/ui/gfx/compositor/layer_animator.cc @@ -53,46 +53,37 @@ LayerAnimator* LayerAnimator::CreateImplicitAnimator() { } void LayerAnimator::SetTransform(const Transform& transform) { - if (transition_duration_ == base::TimeDelta()) - delegate_->SetTransformFromAnimation(transform); - else - StartAnimation(new LayerAnimationSequence( - LayerAnimationElement::CreateTransformElement( - transform, transition_duration_))); + StartAnimation(new LayerAnimationSequence( + LayerAnimationElement::CreateTransformElement( + transform, transition_duration_))); } Transform LayerAnimator::GetTargetTransform() const { - LayerAnimationElement::TargetValue target; + LayerAnimationElement::TargetValue target(delegate()); GetTargetValue(&target); return target.transform; } void LayerAnimator::SetBounds(const gfx::Rect& bounds) { - if (transition_duration_ == base::TimeDelta()) - delegate_->SetBoundsFromAnimation(bounds); - else - StartAnimation(new LayerAnimationSequence( - LayerAnimationElement::CreateBoundsElement( - bounds, transition_duration_))); + StartAnimation(new LayerAnimationSequence( + LayerAnimationElement::CreateBoundsElement( + bounds, transition_duration_))); } gfx::Rect LayerAnimator::GetTargetBounds() const { - LayerAnimationElement::TargetValue target; + LayerAnimationElement::TargetValue target(delegate()); GetTargetValue(&target); return target.bounds; } void LayerAnimator::SetOpacity(float opacity) { - if (transition_duration_ == base::TimeDelta()) - delegate_->SetOpacityFromAnimation(opacity); - else - StartAnimation(new LayerAnimationSequence( - LayerAnimationElement::CreateOpacityElement( - opacity, transition_duration_))); + StartAnimation(new LayerAnimationSequence( + LayerAnimationElement::CreateOpacityElement( + opacity, transition_duration_))); } float LayerAnimator::GetTargetOpacity() const { - LayerAnimationElement::TargetValue target; + LayerAnimationElement::TargetValue target(delegate()); GetTargetValue(&target); return target.opacity; } @@ -232,24 +223,23 @@ void LayerAnimator::ScopedSettings::SetTransitionDuration( void LayerAnimator::Step(base::TimeTicks now) { last_step_time_ = now; - std::vector<LayerAnimationSequence*> to_finish; - for (RunningAnimations::iterator iter = running_animations_.begin(); - iter != running_animations_.end(); ++iter) { - base::TimeDelta delta = now - (*iter).start_time; - if (delta >= (*iter).sequence->duration() && - !(*iter).sequence->is_cyclic()) { - to_finish.push_back((*iter).sequence); + // We need to make a copy of the running animations because progressing them + // and finishing them may indirectly affect the collection of running + // animations. + RunningAnimations running_animations_copy = running_animations_; + for (size_t i = 0; i < running_animations_copy.size(); ++i) { + 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()) { + FinishAnimation(running_animations_copy[i].sequence); } else { - (*iter).sequence->Progress(delta, delegate()); + running_animations_copy[i].sequence->Progress(delta, delegate()); } } - for (std::vector<LayerAnimationSequence*>::iterator iter = to_finish.begin(); - iter != to_finish.end(); ++iter) { - FinishAnimation(*iter); - } } void LayerAnimator::SetStartTime(base::TimeTicks start_time) { + // Do nothing. } base::TimeDelta LayerAnimator::GetTimerInterval() const { @@ -275,8 +265,11 @@ void LayerAnimator::UpdateAnimationState() { is_started_ = should_start; } -void LayerAnimator::RemoveAnimation(LayerAnimationSequence* sequence) { - // First remove from running animations +LayerAnimationSequence* LayerAnimator::RemoveAnimation( + LayerAnimationSequence* sequence) { + linked_ptr<LayerAnimationSequence> to_return; + + // First remove from running animations for (RunningAnimations::iterator iter = running_animations_.begin(); iter != running_animations_.end(); ++iter) { if ((*iter).sequence == sequence) { @@ -289,32 +282,32 @@ void LayerAnimator::RemoveAnimation(LayerAnimationSequence* sequence) { for (AnimationQueue::iterator queue_iter = animation_queue_.begin(); queue_iter != animation_queue_.end(); ++queue_iter) { if ((*queue_iter) == sequence) { + to_return = *queue_iter; animation_queue_.erase(queue_iter); break; } } + + return to_return.release(); } void LayerAnimator::FinishAnimation(LayerAnimationSequence* sequence) { + scoped_ptr<LayerAnimationSequence> removed(RemoveAnimation(sequence)); sequence->Progress(sequence->duration(), delegate()); - RemoveAnimation(sequence); ProcessQueue(); UpdateAnimationState(); } void LayerAnimator::FinishAnyAnimationWithZeroDuration() { - // Special case: if we've started a 0 duration animation, just finish it now - // and get rid of it. Note at each iteration of the loop, we either increment - // i or remove an element from running_animations_, so - // running_animations_.size() - i is always decreasing and we are always - // progressing towards the termination of the loop. - for (size_t i = 0; i < running_animations_.size();) { - if (running_animations_[i].sequence->duration() == base::TimeDelta()) { - running_animations_[i].sequence->Progress( - running_animations_[i].sequence->duration(), delegate()); - RemoveAnimation(running_animations_[i].sequence); - } else { - ++i; + // We need to make a copy because Progress may indirectly cause new animations + // to start running. + RunningAnimations running_animations_copy = running_animations_; + for (size_t i = 0; i < running_animations_copy.size(); ++i) { + if (running_animations_copy[i].sequence->duration() == base::TimeDelta()) { + running_animations_copy[i].sequence->Progress( + running_animations_copy[i].sequence->duration(), delegate()); + scoped_ptr<LayerAnimationSequence> removed( + RemoveAnimation(running_animations_copy[i].sequence)); } } ProcessQueue(); @@ -322,10 +315,17 @@ void LayerAnimator::FinishAnyAnimationWithZeroDuration() { } void LayerAnimator::ClearAnimations() { - for (RunningAnimations::iterator iter = running_animations_.begin(); - iter != running_animations_.end(); ++iter) { - (*iter).sequence->Abort(); + // 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) { + 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(); @@ -358,41 +358,40 @@ void LayerAnimator::AddToQueueIfNotPresent(LayerAnimationSequence* animation) { } void LayerAnimator::RemoveAllAnimationsWithACommonProperty( - LayerAnimationSequence* sequence, - bool abort) { + LayerAnimationSequence* sequence, bool abort) { // For all the running animations, if they animate the same property, - // progress them to the end and remove them. Note: at each iteration i is - // incremented or an element is removed from the queue, so - // animation_queue_.size() - i is always decreasing and we are always making - // progress towards the loop terminating. - for (size_t i = 0; i < running_animations_.size();) { - if (running_animations_[i].sequence->HasCommonProperty( + // progress them to the end and remove them. Note, Aborting or Progressing + // animations may affect the collection of running animations, so we need to + // operate on a copy. + RunningAnimations running_animations_copy = running_animations_; + for (size_t i = 0; i < running_animations_copy.size(); ++i) { + if (running_animations_copy[i].sequence->HasCommonProperty( sequence->properties())) { - // Finish the animation. - if (abort){ - running_animations_[i].sequence->Abort(); - } else { - running_animations_[i].sequence->Progress( - running_animations_[i].sequence->duration(), delegate()); - } - RemoveAnimation(running_animations_[i].sequence); - } else { - ++i; + scoped_ptr<LayerAnimationSequence> removed( + RemoveAnimation(running_animations_copy[i].sequence)); + if (abort) + running_animations_copy[i].sequence->Abort(); + else + running_animations_copy[i].sequence->Progress( + running_animations_copy[i].sequence->duration(), delegate()); } } - // Same for the queued animations. See comment above about loop termination. - for (size_t i = 0; i < animation_queue_.size();) { - if (animation_queue_[i]->HasCommonProperty(sequence->properties())) { - // Finish the animation. + // Same for the queued animations that haven't been started. Again, we'll + // need to operate on a copy. + std::vector<LayerAnimationSequence*> sequences; + for (AnimationQueue::iterator queue_iter = animation_queue_.begin(); + queue_iter != animation_queue_.end(); ++queue_iter) + sequences.push_back((*queue_iter).get()); + + for (size_t i = 0; i < sequences.size(); ++i) { + if (sequences[i]->HasCommonProperty(sequence->properties())) { + scoped_ptr<LayerAnimationSequence> removed( + RemoveAnimation(sequences[i])); if (abort) - animation_queue_[i]->Abort(); + sequences[i]->Abort(); else - animation_queue_[i]->Progress(animation_queue_[i]->duration(), - delegate()); - RemoveAnimation(animation_queue_[i].get()); - } else { - ++i; + sequences[i]->Progress(sequences[i]->duration(), delegate()); } } } @@ -400,8 +399,8 @@ void LayerAnimator::RemoveAllAnimationsWithACommonProperty( void LayerAnimator::ImmediatelySetNewTarget(LayerAnimationSequence* sequence) { const bool abort = false; RemoveAllAnimationsWithACommonProperty(sequence, abort); + scoped_ptr<LayerAnimationSequence> removed(RemoveAnimation(sequence)); sequence->Progress(sequence->duration(), delegate()); - RemoveAnimation(sequence); } void LayerAnimator::ImmediatelyAnimateToNewTarget( @@ -435,7 +434,8 @@ void LayerAnimator::ReplaceQueuedAnimations(LayerAnimationSequence* sequence) { } } if (!is_running) - RemoveAnimation(animation_queue_[i].get()); + scoped_ptr<LayerAnimationSequence>( + RemoveAnimation(animation_queue_[i].get())); else ++i; } @@ -456,11 +456,17 @@ void LayerAnimator::ProcessQueue() { } // Try to find an animation that doesn't conflict with an animated - // property or a property that will be animated before it. + // property or a property that will be animated before it. Note: starting + // the animation may indirectly cause more animations to be started, so we + // need to operate on a copy. + std::vector<LayerAnimationSequence*> sequences; for (AnimationQueue::iterator queue_iter = animation_queue_.begin(); - queue_iter != animation_queue_.end(); ++queue_iter) { - if (!(*queue_iter)->HasCommonProperty(animated)) { - StartSequenceImmediately((*queue_iter).get()); + queue_iter != animation_queue_.end(); ++queue_iter) + sequences.push_back((*queue_iter).get()); + + for (size_t i = 0; i < sequences.size(); ++i) { + if (!sequences[i]->HasCommonProperty(animated)) { + StartSequenceImmediately(sequences[i]); started_sequence = true; break; } @@ -473,8 +479,8 @@ void LayerAnimator::ProcessQueue() { // the first element because it animates the transform, too. We cannot // start the second element, either, because the first element animates // bounds too, and needs to go first. - animated.insert((*queue_iter)->properties().begin(), - (*queue_iter)->properties().end()); + animated.insert(sequences[i]->properties().begin(), + sequences[i]->properties().end()); } // If we started a sequence, try again. We may be able to start several. diff --git a/ui/gfx/compositor/layer_animator.h b/ui/gfx/compositor/layer_animator.h index c7286b5..4b7de40 100644 --- a/ui/gfx/compositor/layer_animator.h +++ b/ui/gfx/compositor/layer_animator.h @@ -10,6 +10,7 @@ #include <set> #include <vector> +#include "base/compiler_specific.h" #include "base/memory/linked_ptr.h" #include "base/memory/scoped_ptr.h" #include "base/observer_list.h" @@ -140,6 +141,7 @@ class COMPOSITOR_EXPORT LayerAnimator : public AnimationContainerElement { protected: LayerAnimationDelegate* delegate() { return delegate_; } + const LayerAnimationDelegate* delegate() const { return delegate_; } private: friend class ScopedSettings; @@ -167,7 +169,10 @@ class COMPOSITOR_EXPORT LayerAnimator : public AnimationContainerElement { void UpdateAnimationState(); // Removes the sequences from both the running animations and the queue. - void RemoveAnimation(LayerAnimationSequence* sequence); + // Returns a pointer to the removed animation, if any. NOTE: the caller is + // responsible for deleting the returned pointer. + LayerAnimationSequence* RemoveAnimation( + LayerAnimationSequence* sequence) WARN_UNUSED_RESULT; // Progresses to the end of the sequence before removing it. void FinishAnimation(LayerAnimationSequence* sequence); diff --git a/ui/gfx/compositor/layer_animator_unittest.cc b/ui/gfx/compositor/layer_animator_unittest.cc index 7d957cf..762a3b2 100644 --- a/ui/gfx/compositor/layer_animator_unittest.cc +++ b/ui/gfx/compositor/layer_animator_unittest.cc @@ -692,12 +692,12 @@ TEST(LayerAnimatorTest, AddObserverImplicit) { animator->SetDelegate(&delegate); animator->AddObserver(&observer); - // Should not end a sequence with the default animator. + // Should end a sequence with the default animator. EXPECT_TRUE(!observer.last_ended_sequence()); animator->SetOpacity(1.0f); base::TimeTicks start_time = base::TimeTicks::Now(); element->Step(start_time + base::TimeDelta::FromMilliseconds(1000)); - EXPECT_TRUE(!observer.last_ended_sequence()); + EXPECT_TRUE(observer.last_ended_sequence()); TestLayerAnimationObserver scoped_observer; { @@ -722,6 +722,33 @@ TEST(LayerAnimatorTest, AddObserverImplicit) { EXPECT_TRUE(!scoped_observer.last_ended_sequence()); } +// 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()); + animator->set_disable_timer_for_test(true); + TestLayerAnimationDelegate delegate; + animator->SetDelegate(&delegate); + + double start_opacity(0.0); + double target_opacity(1.0); + + base::TimeDelta delta = base::TimeDelta::FromSeconds(1); + + delegate.SetOpacityFromAnimation(start_opacity); + + scoped_ptr<LayerAnimationSequence> sequence( + new LayerAnimationSequence( + LayerAnimationElement::CreateOpacityElement(target_opacity, delta))); + + animator->StartAnimation(sequence.release()); + + animator->SetOpacity(0.5); + + EXPECT_FALSE(animator->is_animating()); + EXPECT_EQ(0.5, animator->GetTargetOpacity()); +} + } // namespace } // namespace ui diff --git a/ui/gfx/compositor/layer_unittest.cc b/ui/gfx/compositor/layer_unittest.cc index 2308cd0..8d269c4 100644 --- a/ui/gfx/compositor/layer_unittest.cc +++ b/ui/gfx/compositor/layer_unittest.cc @@ -597,6 +597,8 @@ TEST_F(LayerWithNullDelegateTest, HoleWithNinetyDegreeTransforms) { EXPECT_TRUE(!parent->hole_rect().IsEmpty()); for (int i = -4; i <= 4; ++i) { + SCOPED_TRACE(::testing::Message() << "Iteration " << i); + ui::Transform t; // Need to rotate in local coordinates. t.SetTranslate(-25, -25); |