From e81480f1fd21a75545b1c5dda31a1e7c8abf847f Mon Sep 17 00:00:00 2001 From: "sky@chromium.org" Date: Thu, 11 Oct 2012 23:06:45 +0000 Subject: Adds ability to animate the color of a layer. BUG=155179 TEST=none R=vollick@chromium.org Review URL: https://codereview.chromium.org/11103037 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@161432 0039d316-1c4b-4281-b951-d872f2087c98 --- ui/compositor/layer.cc | 25 +++++- ui/compositor/layer.h | 3 + ui/compositor/layer_animation_delegate.h | 3 + ui/compositor/layer_animation_element.cc | 90 +++++++++++++++++++--- ui/compositor/layer_animation_element.h | 11 ++- ui/compositor/layer_animator.cc | 14 ++++ ui/compositor/layer_animator.h | 4 + ui/compositor/layer_animator_unittest.cc | 48 ++++++++++++ .../test/test_layer_animation_delegate.cc | 14 +++- ui/compositor/test/test_layer_animation_delegate.h | 3 + 10 files changed, 198 insertions(+), 17 deletions(-) (limited to 'ui') diff --git a/ui/compositor/layer.cc b/ui/compositor/layer.cc index e71cbd5..950c309 100644 --- a/ui/compositor/layer.cc +++ b/ui/compositor/layer.cc @@ -425,10 +425,7 @@ void Layer::SetExternalTexture(Texture* texture) { } void Layer::SetColor(SkColor color) { - DCHECK_EQ(type_, LAYER_SOLID_COLOR); - // WebColor is equivalent to SkColor, per WebColor.h. - solid_color_layer_->setBackgroundColor(static_cast(color)); - SetFillsBoundsOpaquely(SkColorGetA(color) == 0xFF); + GetAnimator()->SetColor(color); } bool Layer::SchedulePaint(const gfx::Rect& invalid_rect) { @@ -655,6 +652,13 @@ void Layer::SetGrayscaleImmediately(float grayscale) { SetLayerFilters(); } +void Layer::SetColorImmediately(SkColor color) { + DCHECK_EQ(type_, LAYER_SOLID_COLOR); + // WebColor is equivalent to SkColor, per WebColor.h. + solid_color_layer_->setBackgroundColor(static_cast(color)); + SetFillsBoundsOpaquely(SkColorGetA(color) == 0xFF); +} + void Layer::SetBoundsFromAnimation(const gfx::Rect& bounds) { SetBoundsImmediately(bounds); } @@ -674,10 +678,15 @@ void Layer::SetVisibilityFromAnimation(bool visibility) { void Layer::SetBrightnessFromAnimation(float brightness) { SetBrightnessImmediately(brightness); } + void Layer::SetGrayscaleFromAnimation(float grayscale) { SetGrayscaleImmediately(grayscale); } +void Layer::SetColorFromAnimation(SkColor color) { + SetColorImmediately(color); +} + void Layer::ScheduleDrawForAnimation() { ScheduleDraw(); } @@ -706,6 +715,14 @@ float Layer::GetGrayscaleForAnimation() const { return layer_grayscale(); } +SkColor Layer::GetColorForAnimation() const { + // WebColor is equivalent to SkColor, per WebColor.h. + // The NULL check is here since this is invoked regardless of whether we have + // been configured as LAYER_SOLID_COLOR. + return solid_color_layer_.get() ? + solid_color_layer_->layer()->backgroundColor() : SK_ColorBLACK; +} + void Layer::CreateWebLayer() { WebKit::WebCompositorSupport* compositor_support = WebKit::Platform::current()->compositorSupport(); diff --git a/ui/compositor/layer.h b/ui/compositor/layer.h index f9fcbc9..984bc39 100644 --- a/ui/compositor/layer.h +++ b/ui/compositor/layer.h @@ -302,6 +302,7 @@ class COMPOSITOR_EXPORT Layer void SetVisibilityImmediately(bool visibility); void SetBrightnessImmediately(float brightness); void SetGrayscaleImmediately(float grayscale); + void SetColorImmediately(SkColor color); // Implementation of LayerAnimatorDelegate virtual void SetBoundsFromAnimation(const gfx::Rect& bounds) OVERRIDE; @@ -310,6 +311,7 @@ class COMPOSITOR_EXPORT Layer virtual void SetVisibilityFromAnimation(bool visibility) OVERRIDE; virtual void SetBrightnessFromAnimation(float brightness) OVERRIDE; virtual void SetGrayscaleFromAnimation(float grayscale) OVERRIDE; + virtual void SetColorFromAnimation(SkColor color) OVERRIDE; virtual void ScheduleDrawForAnimation() OVERRIDE; virtual const gfx::Rect& GetBoundsForAnimation() const OVERRIDE; virtual const Transform& GetTransformForAnimation() const OVERRIDE; @@ -317,6 +319,7 @@ class COMPOSITOR_EXPORT Layer virtual bool GetVisibilityForAnimation() const OVERRIDE; virtual float GetBrightnessForAnimation() const OVERRIDE; virtual float GetGrayscaleForAnimation() const OVERRIDE; + virtual SkColor GetColorForAnimation() const OVERRIDE; void CreateWebLayer(); void RecomputeTransform(); diff --git a/ui/compositor/layer_animation_delegate.h b/ui/compositor/layer_animation_delegate.h index 08485a0..0b61fa7 100644 --- a/ui/compositor/layer_animation_delegate.h +++ b/ui/compositor/layer_animation_delegate.h @@ -5,6 +5,7 @@ #ifndef UI_COMPOSITOR_LAYER_ANIMATION_DELEGATE_H_ #define UI_COMPOSITOR_LAYER_ANIMATION_DELEGATE_H_ +#include "third_party/skia/include/core/SkColor.h" #include "ui/compositor/compositor_export.h" #include "ui/gfx/rect.h" #include "ui/gfx/transform.h" @@ -20,6 +21,7 @@ class COMPOSITOR_EXPORT LayerAnimationDelegate { virtual void SetVisibilityFromAnimation(bool visibility) = 0; virtual void SetBrightnessFromAnimation(float brightness) = 0; virtual void SetGrayscaleFromAnimation(float grayscale) = 0; + virtual void SetColorFromAnimation(SkColor color) = 0; virtual void ScheduleDrawForAnimation() = 0; virtual const gfx::Rect& GetBoundsForAnimation() const = 0; virtual const Transform& GetTransformForAnimation() const = 0; @@ -27,6 +29,7 @@ class COMPOSITOR_EXPORT LayerAnimationDelegate { virtual bool GetVisibilityForAnimation() const = 0; virtual float GetBrightnessForAnimation() const = 0; virtual float GetGrayscaleForAnimation() const = 0; + virtual SkColor GetColorForAnimation() const = 0; protected: virtual ~LayerAnimationDelegate() {} diff --git a/ui/compositor/layer_animation_element.cc b/ui/compositor/layer_animation_element.cc index 98326d2..c48a81c 100644 --- a/ui/compositor/layer_animation_element.cc +++ b/ui/compositor/layer_animation_element.cc @@ -314,6 +314,59 @@ class GrayscaleTransition : public LayerAnimationElement { DISALLOW_COPY_AND_ASSIGN(GrayscaleTransition); }; +// ColorTransition ------------------------------------------------------------- + +class ColorTransition : public LayerAnimationElement { + public: + ColorTransition(SkColor target, base::TimeDelta duration) + : LayerAnimationElement(GetProperties(), duration), + start_(SK_ColorBLACK), + target_(target) { + } + virtual ~ColorTransition() {} + + protected: + virtual void OnStart(LayerAnimationDelegate* delegate) OVERRIDE { + start_ = delegate->GetColorForAnimation(); + } + + virtual bool OnProgress(double t, LayerAnimationDelegate* delegate) OVERRIDE { + delegate->SetColorFromAnimation( + SkColorSetARGB( + Tween::ValueBetween(t, + static_cast(SkColorGetA(start_)), + static_cast(SkColorGetA(target_))), + Tween::ValueBetween(t, + static_cast(SkColorGetR(start_)), + static_cast(SkColorGetR(target_))), + Tween::ValueBetween(t, + static_cast(SkColorGetG(start_)), + static_cast(SkColorGetG(target_))), + Tween::ValueBetween(t, + static_cast(SkColorGetB(start_)), + static_cast(SkColorGetB(target_))))); + return true; + } + + virtual void OnGetTarget(TargetValue* target) const OVERRIDE { + target->color = target_; + } + + virtual void OnAbort() OVERRIDE {} + + private: + static AnimatableProperties GetProperties() { + AnimatableProperties properties; + properties.insert(LayerAnimationElement::COLOR); + return properties; + } + + SkColor start_; + const SkColor target_; + + DISALLOW_COPY_AND_ASSIGN(ColorTransition); +}; + } // namespace // LayerAnimationElement::TargetValue ------------------------------------------ @@ -322,7 +375,8 @@ LayerAnimationElement::TargetValue::TargetValue() : opacity(0.0f), visibility(false), brightness(0.0f), - grayscale(0.0f) { + grayscale(0.0f), + color(SK_ColorBLACK) { } LayerAnimationElement::TargetValue::TargetValue( @@ -332,7 +386,8 @@ LayerAnimationElement::TargetValue::TargetValue( opacity(delegate ? delegate->GetOpacityForAnimation() : 0.0f), visibility(delegate ? delegate->GetVisibilityForAnimation() : false), brightness(delegate ? delegate->GetBrightnessForAnimation() : 0.0f), - grayscale(delegate ? delegate->GetGrayscaleForAnimation() : 0.0f) { + grayscale(delegate ? delegate->GetGrayscaleForAnimation() : 0.0f), + color(delegate ? delegate->GetColorForAnimation() : 0.0f) { } // LayerAnimationElement ------------------------------------------------------- @@ -381,51 +436,66 @@ base::TimeDelta LayerAnimationElement::GetEffectiveDuration( // static LayerAnimationElement* LayerAnimationElement::CreateTransformElement( - const Transform& transform, base::TimeDelta duration) { + const Transform& transform, + base::TimeDelta duration) { return new TransformTransition(transform, duration); } // static LayerAnimationElement* LayerAnimationElement::CreateInterpolatedTransformElement( - InterpolatedTransform* interpolated_transform, base::TimeDelta duration) { + InterpolatedTransform* interpolated_transform, + base::TimeDelta duration) { return new InterpolatedTransformTransition(interpolated_transform, duration); } // static LayerAnimationElement* LayerAnimationElement::CreateBoundsElement( - const gfx::Rect& bounds, base::TimeDelta duration) { + const gfx::Rect& bounds, + base::TimeDelta duration) { return new BoundsTransition(bounds, duration); } // static LayerAnimationElement* LayerAnimationElement::CreateOpacityElement( - float opacity, base::TimeDelta duration) { + float opacity, + base::TimeDelta duration) { return new OpacityTransition(opacity, duration); } // static LayerAnimationElement* LayerAnimationElement::CreateVisibilityElement( - bool visibility, base::TimeDelta duration) { + bool visibility, + base::TimeDelta duration) { return new VisibilityTransition(visibility, duration); } // static LayerAnimationElement* LayerAnimationElement::CreateBrightnessElement( - float brightness, base::TimeDelta duration) { + float brightness, + base::TimeDelta duration) { return new BrightnessTransition(brightness, duration); } // static LayerAnimationElement* LayerAnimationElement::CreateGrayscaleElement( - float grayscale, base::TimeDelta duration) { + float grayscale, + base::TimeDelta duration) { return new GrayscaleTransition(grayscale, duration); } // static LayerAnimationElement* LayerAnimationElement::CreatePauseElement( - const AnimatableProperties& properties, base::TimeDelta duration) { + const AnimatableProperties& properties, + base::TimeDelta duration) { return new Pause(properties, duration); } +// static +LayerAnimationElement* LayerAnimationElement::CreateColorElement( + SkColor color, + base::TimeDelta duration) { + return new ColorTransition(color, duration); +} + } // namespace ui diff --git a/ui/compositor/layer_animation_element.h b/ui/compositor/layer_animation_element.h index 89bf26f..870f005 100644 --- a/ui/compositor/layer_animation_element.h +++ b/ui/compositor/layer_animation_element.h @@ -8,6 +8,7 @@ #include #include "base/time.h" +#include "third_party/skia/include/core/SkColor.h" #include "ui/base/animation/tween.h" #include "ui/compositor/compositor_export.h" #include "ui/gfx/rect.h" @@ -30,7 +31,8 @@ class COMPOSITOR_EXPORT LayerAnimationElement { OPACITY, VISIBILITY, BRIGHTNESS, - GRAYSCALE + GRAYSCALE, + COLOR, }; struct COMPOSITOR_EXPORT TargetValue { @@ -44,6 +46,7 @@ class COMPOSITOR_EXPORT LayerAnimationElement { bool visibility; float brightness; float grayscale; + SkColor color; }; typedef std::set AnimatableProperties; @@ -105,6 +108,12 @@ class COMPOSITOR_EXPORT LayerAnimationElement { const AnimatableProperties& properties, base::TimeDelta duration); + // Creates an element that transitions to the given color. The caller owns the + // return value. + static LayerAnimationElement* CreateColorElement( + SkColor color, + base::TimeDelta duration); + // Updates the delegate to the appropriate value for |t|, which is in the // range [0, 1] (0 for initial, and 1 for final). If the animation is not // aborted, it is guaranteed that Progress will eventually be called with diff --git a/ui/compositor/layer_animator.cc b/ui/compositor/layer_animator.cc index 2cf25dc..0524586 100644 --- a/ui/compositor/layer_animator.cc +++ b/ui/compositor/layer_animator.cc @@ -158,6 +158,20 @@ float LayerAnimator::GetTargetGrayscale() const { return target.grayscale; } +void LayerAnimator::SetColor(SkColor color) { + base::TimeDelta duration = GetTransitionDuration(); + scoped_ptr element( + LayerAnimationElement::CreateColorElement(color, duration)); + element->set_tween_type(tween_type_); + StartAnimation(new LayerAnimationSequence(element.release())); +} + +SkColor LayerAnimator::GetTargetColor() const { + LayerAnimationElement::TargetValue target(delegate()); + GetTargetValue(&target); + return target.color; +} + void LayerAnimator::SetDelegate(LayerAnimationDelegate* delegate) { delegate_ = delegate; } diff --git a/ui/compositor/layer_animator.h b/ui/compositor/layer_animator.h index 0c92a81..783d6cb 100644 --- a/ui/compositor/layer_animator.h +++ b/ui/compositor/layer_animator.h @@ -83,6 +83,10 @@ class COMPOSITOR_EXPORT LayerAnimator virtual void SetGrayscale(float grayscale); float GetTargetGrayscale() const; + // Sets the color on the delegate. May cause an implicit animation. + virtual void SetColor(SkColor color); + SkColor GetTargetColor() const; + // Sets the layer animation delegate the animator is associated with. The // animator does not own the delegate. The layer animator expects a non-NULL // delegate for most of its operations, so do not call any methods without diff --git a/ui/compositor/layer_animator_unittest.cc b/ui/compositor/layer_animator_unittest.cc index d60fc319..d1219a15 100644 --- a/ui/compositor/layer_animator_unittest.cc +++ b/ui/compositor/layer_animator_unittest.cc @@ -7,6 +7,7 @@ #include "base/basictypes.h" #include "base/compiler_specific.h" #include "base/memory/scoped_ptr.h" +#include "base/stringprintf.h" #include "base/time.h" #include "testing/gtest/include/gtest/gtest.h" #include "ui/compositor/layer_animation_delegate.h" @@ -23,6 +24,14 @@ namespace ui { namespace { +// Converts |color| to a string. Each component of the color is separated by a +// space and the order if A R G B. +std::string ColorToString(SkColor color) { + return base::StringPrintf("%d %d %d %d", SkColorGetA(color), + SkColorGetR(color), SkColorGetG(color), + SkColorGetB(color)); +} + class TestImplicitAnimationObserver : public ImplicitAnimationObserver { public: explicit TestImplicitAnimationObserver(bool notify_when_animator_destructed) @@ -1164,6 +1173,45 @@ TEST(LayerAnimatorTest, GetTargetGrayscale) { } } +// Verifies color property is modified appropriately. +TEST(LayerAnimatorTest, Color) { + scoped_refptr animator(LayerAnimator::CreateDefaultAnimator()); + AnimationContainerElement* element = animator.get(); + animator->set_disable_timer_for_test(true); + TestLayerAnimationDelegate delegate; + animator->SetDelegate(&delegate); + + SkColor start_color = SkColorSetARGB( 0, 20, 40, 60); + SkColor middle_color = SkColorSetARGB(127, 30, 60, 100); + SkColor target_color = SkColorSetARGB(254, 40, 80, 140); + + base::TimeDelta delta = base::TimeDelta::FromSeconds(1); + + delegate.SetColorFromAnimation(start_color); + + animator->ScheduleAnimation( + new LayerAnimationSequence( + LayerAnimationElement::CreateColorElement(target_color, delta))); + + EXPECT_TRUE(animator->is_animating()); + EXPECT_EQ(ColorToString(start_color), + ColorToString(delegate.GetColorForAnimation())); + + base::TimeTicks start_time = animator->last_step_time(); + + element->Step(start_time + base::TimeDelta::FromMilliseconds(500)); + + EXPECT_TRUE(animator->is_animating()); + EXPECT_EQ(ColorToString(middle_color), + ColorToString(delegate.GetColorForAnimation())); + + element->Step(start_time + base::TimeDelta::FromMilliseconds(1000)); + + EXPECT_FALSE(animator->is_animating()); + EXPECT_EQ(ColorToString(target_color), + ColorToString(delegate.GetColorForAnimation())); +} + // Verifies SchedulePauseForProperties(). TEST(LayerAnimatorTest, SchedulePauseForProperties) { scoped_refptr animator(LayerAnimator::CreateDefaultAnimator()); diff --git a/ui/compositor/test/test_layer_animation_delegate.cc b/ui/compositor/test/test_layer_animation_delegate.cc index bb5cdc5..f5e9262 100644 --- a/ui/compositor/test/test_layer_animation_delegate.cc +++ b/ui/compositor/test/test_layer_animation_delegate.cc @@ -10,7 +10,8 @@ TestLayerAnimationDelegate::TestLayerAnimationDelegate() : opacity_(1.0f), visibility_(true), brightness_(0.0f), - grayscale_(0.0f) { + grayscale_(0.0f), + color_(SK_ColorBLACK) { } TestLayerAnimationDelegate::TestLayerAnimationDelegate( @@ -18,7 +19,8 @@ TestLayerAnimationDelegate::TestLayerAnimationDelegate( : bounds_(other.GetBoundsForAnimation()), transform_(other.GetTransformForAnimation()), opacity_(other.GetOpacityForAnimation()), - visibility_(other.GetVisibilityForAnimation()) { + visibility_(other.GetVisibilityForAnimation()), + color_(SK_ColorBLACK) { } TestLayerAnimationDelegate::~TestLayerAnimationDelegate() { @@ -50,6 +52,10 @@ void TestLayerAnimationDelegate::SetGrayscaleFromAnimation(float grayscale) { grayscale_ = grayscale; } +void TestLayerAnimationDelegate::SetColorFromAnimation(SkColor color) { + color_ = color; +} + void TestLayerAnimationDelegate::ScheduleDrawForAnimation() { } @@ -77,4 +83,8 @@ float TestLayerAnimationDelegate::GetGrayscaleForAnimation() const { return grayscale_; } +SkColor TestLayerAnimationDelegate::GetColorForAnimation() const { + return color_; +} + } // namespace ui diff --git a/ui/compositor/test/test_layer_animation_delegate.h b/ui/compositor/test/test_layer_animation_delegate.h index a17fbf3..e492d4a 100644 --- a/ui/compositor/test/test_layer_animation_delegate.h +++ b/ui/compositor/test/test_layer_animation_delegate.h @@ -25,6 +25,7 @@ class TestLayerAnimationDelegate : public LayerAnimationDelegate { virtual void SetVisibilityFromAnimation(bool visibility) OVERRIDE; virtual void SetBrightnessFromAnimation(float brightness) OVERRIDE; virtual void SetGrayscaleFromAnimation(float grayscale) OVERRIDE; + virtual void SetColorFromAnimation(SkColor color) OVERRIDE; virtual void ScheduleDrawForAnimation() OVERRIDE; virtual const gfx::Rect& GetBoundsForAnimation() const OVERRIDE; virtual const Transform& GetTransformForAnimation() const OVERRIDE; @@ -32,6 +33,7 @@ class TestLayerAnimationDelegate : public LayerAnimationDelegate { virtual bool GetVisibilityForAnimation() const OVERRIDE; virtual float GetBrightnessForAnimation() const OVERRIDE; virtual float GetGrayscaleForAnimation() const OVERRIDE; + virtual SkColor GetColorForAnimation() const OVERRIDE; private: gfx::Rect bounds_; @@ -40,6 +42,7 @@ class TestLayerAnimationDelegate : public LayerAnimationDelegate { bool visibility_; float brightness_; float grayscale_; + SkColor color_; // Allow copy and assign. }; -- cgit v1.1