summaryrefslogtreecommitdiffstats
path: root/ui/gfx
diff options
context:
space:
mode:
Diffstat (limited to 'ui/gfx')
-rw-r--r--ui/gfx/compositor/layer_animation_element.cc10
-rw-r--r--ui/gfx/compositor/layer_animation_element.h4
-rw-r--r--ui/gfx/compositor/layer_animation_element_unittest.cc6
-rw-r--r--ui/gfx/compositor/layer_animation_observer.h3
-rw-r--r--ui/gfx/compositor/layer_animation_sequence.cc4
-rw-r--r--ui/gfx/compositor/layer_animation_sequence_unittest.cc2
-rw-r--r--ui/gfx/compositor/layer_animator.cc180
-rw-r--r--ui/gfx/compositor/layer_animator.h7
-rw-r--r--ui/gfx/compositor/layer_animator_unittest.cc31
-rw-r--r--ui/gfx/compositor/layer_unittest.cc2
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);