diff options
author | avallee@chromium.org <avallee@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-12 19:49:02 +0000 |
---|---|---|
committer | avallee@chromium.org <avallee@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-09-12 19:49:02 +0000 |
commit | d0fe0b652a8854759461d0a94a1b21893fb47637 (patch) | |
tree | 2c65293370803cd7283e368b434444bf9d951aad /ui | |
parent | d5b04b8351b3a757bbaeb3bc0b56a374a049826f (diff) | |
download | chromium_src-d0fe0b652a8854759461d0a94a1b21893fb47637.zip chromium_src-d0fe0b652a8854759461d0a94a1b21893fb47637.tar.gz chromium_src-d0fe0b652a8854759461d0a94a1b21893fb47637.tar.bz2 |
Make inverse transform animations easier to create, using ScopedLayerAnimationSettings.
https://codereview.chromium.org/22861008/ Introduces inverse animations which allow layers to counter-animate against a base layer. However, manually building the animation elements is repetitive and error prone, this change makes these animations simpler to write.
Users should use it in this manner:
// Input values
Layer *base, *inversed1, *inversed2;
gfx::Transform new_transform;
void foo() {
ui::ScopedLayerAnimationSettings settings(base->GetAnimator());
settings.SetInverselyAnimatedBaseLayer(base);
settings.AddInverselyAnimatedLayer(inversed1);
settings.AddInverselyAnimatedLayer(inversed2);
base->SetTransform(new_transform);
}
BUG=270857
Review URL: https://chromiumcodereview.appspot.com/23622004
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@222839 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'ui')
-rw-r--r-- | ui/compositor/layer_animation_element.cc | 23 | ||||
-rw-r--r-- | ui/compositor/layer_animation_element.h | 5 | ||||
-rw-r--r-- | ui/compositor/layer_animation_sequence.cc | 14 | ||||
-rw-r--r-- | ui/compositor/layer_animation_sequence.h | 6 | ||||
-rw-r--r-- | ui/compositor/layer_animator_unittest.cc | 28 | ||||
-rw-r--r-- | ui/compositor/scoped_layer_animation_settings.cc | 85 | ||||
-rw-r--r-- | ui/compositor/scoped_layer_animation_settings.h | 11 |
7 files changed, 165 insertions, 7 deletions
diff --git a/ui/compositor/layer_animation_element.cc b/ui/compositor/layer_animation_element.cc index 51a1c48..7931141 100644 --- a/ui/compositor/layer_animation_element.cc +++ b/ui/compositor/layer_animation_element.cc @@ -575,10 +575,19 @@ class InverseTransformTransition : public ThreadedLayerAnimationElement { const LayerAnimationElement* uninverted_transition) : ThreadedLayerAnimationElement(*uninverted_transition), base_transform_(base_transform), - uninverted_transition_(CheckAndCast(uninverted_transition)) { + uninverted_transition_( + CheckAndCast<const ThreadedTransformTransition*>( + uninverted_transition)) { } virtual ~InverseTransformTransition() {} + static InverseTransformTransition* Clone(const LayerAnimationElement* other) { + const InverseTransformTransition* other_inverse = + CheckAndCast<const InverseTransformTransition*>(other); + return new InverseTransformTransition( + other_inverse->base_transform_, other_inverse->uninverted_transition_); + } + protected: virtual void OnStart(LayerAnimationDelegate* delegate) OVERRIDE { gfx::Transform start(delegate->GetTransformForAnimation()); @@ -658,11 +667,11 @@ class InverseTransformTransition : public ThreadedLayerAnimationElement { return properties; } - static const ThreadedTransformTransition* CheckAndCast( - const LayerAnimationElement* element) { + template <typename T> + static T CheckAndCast(const LayerAnimationElement* element) { const AnimatableProperties& properties = element->properties(); DCHECK(properties.find(TRANSFORM) != properties.end()); - return static_cast<const ThreadedTransformTransition*>(element); + return static_cast<T>(element); } gfx::Transform effective_start_; @@ -862,6 +871,12 @@ LayerAnimationElement* LayerAnimationElement::CreateInverseTransformElement( } // static +LayerAnimationElement* LayerAnimationElement::CloneInverseTransformElement( + const LayerAnimationElement* other) { + return InverseTransformTransition::Clone(other); +} + +// static LayerAnimationElement* LayerAnimationElement::CreateInterpolatedTransformElement( InterpolatedTransform* interpolated_transform, diff --git a/ui/compositor/layer_animation_element.h b/ui/compositor/layer_animation_element.h index b027764..9b969f1f 100644 --- a/ui/compositor/layer_animation_element.h +++ b/ui/compositor/layer_animation_element.h @@ -74,6 +74,11 @@ class COMPOSITOR_EXPORT LayerAnimationElement { const gfx::Transform& base_transform, const LayerAnimationElement* uninverted_transition); + + // Duplicates elements as created by CreateInverseTransformElement. + static LayerAnimationElement* CloneInverseTransformElement( + const LayerAnimationElement* other); + // Creates an element that transitions to another in a way determined by an // interpolated transform. The element accepts ownership of the interpolated // transform. NB: at every step, the interpolated transform clobbers the diff --git a/ui/compositor/layer_animation_sequence.cc b/ui/compositor/layer_animation_sequence.cc index f1c7eba..f336035 100644 --- a/ui/compositor/layer_animation_sequence.cc +++ b/ui/compositor/layer_animation_sequence.cc @@ -242,6 +242,18 @@ void LayerAnimationSequence::OnAnimatorDestroyed() { } } +size_t LayerAnimationSequence::size() const { + return elements_.size(); +} + +LayerAnimationElement* LayerAnimationSequence::FirstElement() const { + if (elements_.empty()) { + return NULL; + } + + return elements_[0].get(); +} + void LayerAnimationSequence::NotifyScheduled() { FOR_EACH_OBSERVER(LayerAnimationObserver, observers_, @@ -260,7 +272,7 @@ void LayerAnimationSequence::NotifyAborted() { OnLayerAnimationAborted(this)); } -LayerAnimationElement* LayerAnimationSequence::CurrentElement() { +LayerAnimationElement* LayerAnimationSequence::CurrentElement() const { if (elements_.empty()) return NULL; diff --git a/ui/compositor/layer_animation_sequence.h b/ui/compositor/layer_animation_sequence.h index a2972f7..854785a 100644 --- a/ui/compositor/layer_animation_sequence.h +++ b/ui/compositor/layer_animation_sequence.h @@ -125,6 +125,10 @@ class COMPOSITOR_EXPORT LayerAnimationSequence // by this sequence. Returns 0.0 if no elements have been progressed. double last_progressed_fraction() const { return last_progressed_fraction_; } + size_t size() const; + + LayerAnimationElement* FirstElement() const; + private: friend class LayerAnimatorTestController; @@ -143,7 +147,7 @@ class COMPOSITOR_EXPORT LayerAnimationSequence void NotifyAborted(); // The currently animating element. - LayerAnimationElement* CurrentElement(); + LayerAnimationElement* CurrentElement() const; // The union of all the properties modified by all elements in the sequence. LayerAnimationElement::AnimatableProperties properties_; diff --git a/ui/compositor/layer_animator_unittest.cc b/ui/compositor/layer_animator_unittest.cc index 5f5871f..8506455 100644 --- a/ui/compositor/layer_animator_unittest.cc +++ b/ui/compositor/layer_animator_unittest.cc @@ -10,6 +10,7 @@ #include "base/strings/stringprintf.h" #include "base/time/time.h" #include "testing/gtest/include/gtest/gtest.h" +#include "ui/compositor/layer.h" #include "ui/compositor/layer_animation_delegate.h" #include "ui/compositor/layer_animation_element.h" #include "ui/compositor/layer_animation_sequence.h" @@ -2375,4 +2376,31 @@ TEST(LayerAnimatorTest, TestSetterRespectEnqueueStrategy) { EXPECT_EQ(start_opacity, delegate.GetOpacityForAnimation()); } +TEST(LayerAnimatorTest, TestScopedCounterAnimation) { + Layer parent, child; + parent.Add(&child); + + gfx::Transform parent_begin, parent_end; + + parent_end.Scale3d(2.0, 0.5, 1.0); + + // Parent animates from identity to the end value. The counter animation will + // start at the end value and animate back to identity. + gfx::Transform child_begin(parent_end); + + child.SetTransform(child_begin); + parent.SetTransform(parent_begin); + + ScopedLayerAnimationSettings settings(parent.GetAnimator()); + settings.SetInverselyAnimatedBaseLayer(&parent); + settings.AddInverselyAnimatedLayer(&child); + + parent.SetTransform(parent_end); + + EXPECT_TRUE(child.GetTargetTransform().IsIdentity()) + << child.GetTargetTransform().ToString(); + EXPECT_TRUE(child.GetAnimator()->is_animating()); + +} + } // namespace ui diff --git a/ui/compositor/scoped_layer_animation_settings.cc b/ui/compositor/scoped_layer_animation_settings.cc index b45d94c..5c5a1bb 100644 --- a/ui/compositor/scoped_layer_animation_settings.cc +++ b/ui/compositor/scoped_layer_animation_settings.cc @@ -4,7 +4,9 @@ #include "ui/compositor/scoped_layer_animation_settings.h" +#include "ui/compositor/layer.h" #include "ui/compositor/layer_animation_observer.h" +#include "ui/compositor/layer_animation_sequence.h" #include "ui/compositor/layer_animator.h" namespace { @@ -15,12 +17,75 @@ const int kDefaultTransitionDurationMs = 200; namespace ui { +// InvertingObserver ----------------------------------------------------------- +class InvertingObserver : public ImplicitAnimationObserver { + public: + InvertingObserver() + : base_layer_(NULL) { + } + + virtual ~InvertingObserver() {} + + void SetLayer(Layer* base_layer) { base_layer_ = base_layer; } + + Layer* layer() { return base_layer_; } + + void AddInverselyAnimatedLayer(Layer* inverse_layer) { + inverse_layers_.push_back(inverse_layer); + } + + virtual void OnImplicitAnimationsCompleted() OVERRIDE {} + + virtual void OnLayerAnimationScheduled( + LayerAnimationSequence* sequence) OVERRIDE { + DCHECK(base_layer_ != NULL) + << "Must set base layer with ScopedLayerAnimationSettings::" + << "SetInverslyAnimatedBaseLayer"; + gfx::Transform base_transform = base_layer_->transform(); + scoped_ptr<LayerAnimationElement> inverse = GetInverseElement(sequence, + base_transform); + LayerAnimationElement::CloneInverseTransformElement(inverse.get()); + + for (std::vector<Layer*>::const_iterator i = + inverse_layers_.begin(); i != inverse_layers_.end(); ++i) { + (*i)->GetAnimator()->StartAnimation(new LayerAnimationSequence( + LayerAnimationElement::CloneInverseTransformElement( + inverse.get()))); + } + } + private: + scoped_ptr<LayerAnimationElement> GetInverseElement( + LayerAnimationSequence* sequence, + gfx::Transform base) const { + const size_t expected_size = 1; + DCHECK_EQ(expected_size, sequence->size()) << + "Inverse supported only for single element sequences."; + + LayerAnimationElement* element = sequence->FirstElement(); + LayerAnimationElement::AnimatableProperties transform_property; + transform_property.insert(LayerAnimationElement::TRANSFORM); + DCHECK(transform_property == element->properties()) + << "Only transform animations are currently invertible."; + + scoped_ptr<LayerAnimationElement> to_return( + LayerAnimationElement::CreateInverseTransformElement(base, element)); + return to_return.Pass(); + } + + Layer* base_layer_; + // child layers + std::vector<Layer*> inverse_layers_; +}; + + +// ScoperLayerAnimationSettings ------------------------------------------------ ScopedLayerAnimationSettings::ScopedLayerAnimationSettings( LayerAnimator* animator) : animator_(animator), old_transition_duration_(animator->transition_duration_), old_tween_type_(animator->tween_type()), - old_preemption_strategy_(animator->preemption_strategy()) { + old_preemption_strategy_(animator->preemption_strategy()), + inverse_observer_(new InvertingObserver()) { SetTransitionDuration( base::TimeDelta::FromMilliseconds(kDefaultTransitionDurationMs)); } @@ -35,6 +100,10 @@ ScopedLayerAnimationSettings::~ScopedLayerAnimationSettings() { animator_->observers_.RemoveObserver(*i); (*i)->SetActive(true); } + + if (inverse_observer_->layer()) { + animator_->observers_.RemoveObserver(inverse_observer_.get()); + } } void ScopedLayerAnimationSettings::AddObserver( @@ -70,4 +139,18 @@ ScopedLayerAnimationSettings::GetPreemptionStrategy() const { return animator_->preemption_strategy(); } +void ScopedLayerAnimationSettings::SetInverselyAnimatedBaseLayer(Layer* base) { + if (inverse_observer_->layer() && !base) { + animator_->RemoveObserver(inverse_observer_.get()); + } else if (base && !(inverse_observer_->layer())) { + animator_->AddObserver(inverse_observer_.get()); + } + inverse_observer_->SetLayer(base); +} + +void ScopedLayerAnimationSettings::AddInverselyAnimatedLayer( + Layer* inverse_layer) { + inverse_observer_->AddInverselyAnimatedLayer(inverse_layer); +} + } // namespace ui diff --git a/ui/compositor/scoped_layer_animation_settings.h b/ui/compositor/scoped_layer_animation_settings.h index 7f8e1c7..4e94eee 100644 --- a/ui/compositor/scoped_layer_animation_settings.h +++ b/ui/compositor/scoped_layer_animation_settings.h @@ -7,6 +7,7 @@ #include <set> +#include "base/memory/scoped_vector.h" #include "base/time/time.h" #include "ui/base/animation/tween.h" @@ -17,6 +18,7 @@ namespace ui { class ImplicitAnimationObserver; class LayerAnimationObserver; +class InvertingObserver; // Scoped settings allow you to temporarily change the animator's settings and // these changes are reverted when the object is destroyed. NOTE: when the @@ -38,12 +40,21 @@ class COMPOSITOR_EXPORT ScopedLayerAnimationSettings { void SetPreemptionStrategy(LayerAnimator::PreemptionStrategy strategy); LayerAnimator::PreemptionStrategy GetPreemptionStrategy() const; + // Sets the base layer whose animation will be countered. + void SetInverselyAnimatedBaseLayer(Layer* base); + + // Adds the layer to be counter-animated when a transform animation is + // scheduled on the animator_. Must call SetInverselyAnimatedBaseLayer with + // the layer associated with animator_ before animating. + void AddInverselyAnimatedLayer(Layer* inverse_layer); + private: LayerAnimator* animator_; base::TimeDelta old_transition_duration_; Tween::Type old_tween_type_; LayerAnimator::PreemptionStrategy old_preemption_strategy_; std::set<ImplicitAnimationObserver*> observers_; + scoped_ptr<InvertingObserver> inverse_observer_; DISALLOW_COPY_AND_ASSIGN(ScopedLayerAnimationSettings); }; |