Commit a31ad588 authored by Ian Vollick's avatar Ian Vollick Committed by Commit Bot

Add support for visibility animations

It is common to animate something away via a transform, bounds, or
opacity animation and want to flip a visibility bit upon completion of
that transition. Boolean animations are suited to this task. They act
as a step function returning the second value when the timing function
returns a fraction of 1.0 (and you can use this timing function to
adjust the position of the step).

This change also finishes the small bit of plumbing to tick bg
color animations.

Bug: None
Cq-Include-Trybots: master.tryserver.blink:linux_trusty_blink_rel
Change-Id: I18ab39570e2de63cbf103a36c10ea1766efc12e8
Reviewed-on: https://chromium-review.googlesource.com/579529
Commit-Queue: Ian Vollick <vollick@chromium.org>
Reviewed-by: default avatarAli Juma <ajuma@chromium.org>
Cr-Commit-Position: refs/heads/master@{#488311}
parent ba40a39f
...@@ -66,4 +66,13 @@ AnimationCurve::CurveType SizeAnimationCurve::Type() const { ...@@ -66,4 +66,13 @@ AnimationCurve::CurveType SizeAnimationCurve::Type() const {
return SIZE; return SIZE;
} }
const BooleanAnimationCurve* AnimationCurve::ToBooleanAnimationCurve() const {
DCHECK(Type() == AnimationCurve::BOOLEAN);
return static_cast<const BooleanAnimationCurve*>(this);
}
AnimationCurve::CurveType BooleanAnimationCurve::Type() const {
return BOOLEAN;
}
} // namespace cc } // namespace cc
...@@ -19,6 +19,7 @@ class BoxF; ...@@ -19,6 +19,7 @@ class BoxF;
namespace cc { namespace cc {
class BooleanAnimationCurve;
class ColorAnimationCurve; class ColorAnimationCurve;
class FilterAnimationCurve; class FilterAnimationCurve;
class FloatAnimationCurve; class FloatAnimationCurve;
...@@ -30,7 +31,15 @@ class TransformOperations; ...@@ -30,7 +31,15 @@ class TransformOperations;
// An animation curve is a function that returns a value given a time. // An animation curve is a function that returns a value given a time.
class CC_ANIMATION_EXPORT AnimationCurve { class CC_ANIMATION_EXPORT AnimationCurve {
public: public:
enum CurveType { COLOR, FLOAT, TRANSFORM, FILTER, SCROLL_OFFSET, SIZE }; enum CurveType {
COLOR,
FLOAT,
TRANSFORM,
FILTER,
SCROLL_OFFSET,
SIZE,
BOOLEAN,
};
virtual ~AnimationCurve() {} virtual ~AnimationCurve() {}
...@@ -44,6 +53,7 @@ class CC_ANIMATION_EXPORT AnimationCurve { ...@@ -44,6 +53,7 @@ class CC_ANIMATION_EXPORT AnimationCurve {
const FilterAnimationCurve* ToFilterAnimationCurve() const; const FilterAnimationCurve* ToFilterAnimationCurve() const;
const ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve() const; const ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve() const;
const SizeAnimationCurve* ToSizeAnimationCurve() const; const SizeAnimationCurve* ToSizeAnimationCurve() const;
const BooleanAnimationCurve* ToBooleanAnimationCurve() const;
ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve(); ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve();
}; };
...@@ -54,7 +64,7 @@ class CC_ANIMATION_EXPORT ColorAnimationCurve : public AnimationCurve { ...@@ -54,7 +64,7 @@ class CC_ANIMATION_EXPORT ColorAnimationCurve : public AnimationCurve {
virtual SkColor GetValue(base::TimeDelta t) const = 0; virtual SkColor GetValue(base::TimeDelta t) const = 0;
// Partial Animation implementation. // Partial AnimationCurve implementation.
CurveType Type() const override; CurveType Type() const override;
}; };
...@@ -64,7 +74,7 @@ class CC_ANIMATION_EXPORT FloatAnimationCurve : public AnimationCurve { ...@@ -64,7 +74,7 @@ class CC_ANIMATION_EXPORT FloatAnimationCurve : public AnimationCurve {
virtual float GetValue(base::TimeDelta t) const = 0; virtual float GetValue(base::TimeDelta t) const = 0;
// Partial Animation implementation. // Partial AnimationCurve implementation.
CurveType Type() const override; CurveType Type() const override;
}; };
...@@ -98,7 +108,7 @@ class CC_ANIMATION_EXPORT TransformAnimationCurve : public AnimationCurve { ...@@ -98,7 +108,7 @@ class CC_ANIMATION_EXPORT TransformAnimationCurve : public AnimationCurve {
virtual bool MaximumTargetScale(bool forward_direction, virtual bool MaximumTargetScale(bool forward_direction,
float* max_scale) const = 0; float* max_scale) const = 0;
// Partial Animation implementation. // Partial AnimationCurve implementation.
CurveType Type() const override; CurveType Type() const override;
}; };
...@@ -119,6 +129,16 @@ class CC_ANIMATION_EXPORT SizeAnimationCurve : public AnimationCurve { ...@@ -119,6 +129,16 @@ class CC_ANIMATION_EXPORT SizeAnimationCurve : public AnimationCurve {
virtual gfx::SizeF GetValue(base::TimeDelta t) const = 0; virtual gfx::SizeF GetValue(base::TimeDelta t) const = 0;
// Partial AnimationCurve implementation.
CurveType Type() const override;
};
class CC_ANIMATION_EXPORT BooleanAnimationCurve : public AnimationCurve {
public:
~BooleanAnimationCurve() override {}
virtual bool GetValue(base::TimeDelta t) const = 0;
// Partial Animation implementation. // Partial Animation implementation.
CurveType Type() const override; CurveType Type() const override;
}; };
......
...@@ -754,7 +754,8 @@ void AnimationPlayer::TickAnimation(base::TimeTicks monotonic_time, ...@@ -754,7 +754,8 @@ void AnimationPlayer::TickAnimation(base::TimeTicks monotonic_time,
curve->ToFilterAnimationCurve()->GetValue(trimmed), animation); curve->ToFilterAnimationCurve()->GetValue(trimmed), animation);
break; break;
case TargetProperty::BACKGROUND_COLOR: case TargetProperty::BACKGROUND_COLOR:
// Not yet implemented. target->NotifyClientBackgroundColorAnimated(
curve->ToColorAnimationCurve()->GetValue(trimmed), animation);
break; break;
case TargetProperty::SCROLL_OFFSET: case TargetProperty::SCROLL_OFFSET:
target->NotifyClientScrollOffsetAnimated( target->NotifyClientScrollOffsetAnimated(
...@@ -764,6 +765,10 @@ void AnimationPlayer::TickAnimation(base::TimeTicks monotonic_time, ...@@ -764,6 +765,10 @@ void AnimationPlayer::TickAnimation(base::TimeTicks monotonic_time,
target->NotifyClientBoundsAnimated( target->NotifyClientBoundsAnimated(
curve->ToSizeAnimationCurve()->GetValue(trimmed), animation); curve->ToSizeAnimationCurve()->GetValue(trimmed), animation);
break; break;
case TargetProperty::VISIBILITY:
target->NotifyClientVisibilityAnimated(
curve->ToBooleanAnimationCurve()->GetValue(trimmed), animation);
break;
} }
} }
......
...@@ -6,12 +6,11 @@ ...@@ -6,12 +6,11 @@
#define CC_ANIMATION_ANIMATION_TARGET_H_ #define CC_ANIMATION_ANIMATION_TARGET_H_
#include "cc/animation/animation_export.h" #include "cc/animation/animation_export.h"
#include "third_party/skia/include/core/SkColor.h"
namespace gfx { namespace gfx {
class ScrollOffset; class ScrollOffset;
class SizeF; class SizeF;
} // namespace gfx } // namespace gfx
namespace cc { namespace cc {
...@@ -32,6 +31,10 @@ class CC_ANIMATION_EXPORT AnimationTarget { ...@@ -32,6 +31,10 @@ class CC_ANIMATION_EXPORT AnimationTarget {
Animation* animation) {} Animation* animation) {}
virtual void NotifyClientBoundsAnimated(const gfx::SizeF& size, virtual void NotifyClientBoundsAnimated(const gfx::SizeF& size,
Animation* animation) {} Animation* animation) {}
virtual void NotifyClientBackgroundColorAnimated(SkColor color,
Animation* animation) {}
virtual void NotifyClientVisibilityAnimated(bool visibility,
Animation* animation) {}
virtual void NotifyClientTransformOperationsAnimated( virtual void NotifyClientTransformOperationsAnimated(
const TransformOperations& operations, const TransformOperations& operations,
Animation* animation) {} Animation* animation) {}
......
...@@ -230,6 +230,33 @@ std::unique_ptr<SizeKeyframe> SizeKeyframe::Clone() const { ...@@ -230,6 +230,33 @@ std::unique_ptr<SizeKeyframe> SizeKeyframe::Clone() const {
return SizeKeyframe::Create(Time(), Value(), std::move(func)); return SizeKeyframe::Create(Time(), Value(), std::move(func));
} }
std::unique_ptr<BooleanKeyframe> BooleanKeyframe::Create(
base::TimeDelta time,
bool value,
std::unique_ptr<TimingFunction> timing_function) {
return base::WrapUnique(
new BooleanKeyframe(time, value, std::move(timing_function)));
}
BooleanKeyframe::BooleanKeyframe(
base::TimeDelta time,
bool value,
std::unique_ptr<TimingFunction> timing_function)
: Keyframe(time, std::move(timing_function)), value_(value) {}
BooleanKeyframe::~BooleanKeyframe() {}
bool BooleanKeyframe::Value() const {
return value_;
}
std::unique_ptr<BooleanKeyframe> BooleanKeyframe::Clone() const {
std::unique_ptr<TimingFunction> func;
if (timing_function())
func = timing_function()->Clone();
return BooleanKeyframe::Create(Time(), Value(), std::move(func));
}
std::unique_ptr<KeyframedColorAnimationCurve> std::unique_ptr<KeyframedColorAnimationCurve>
KeyframedColorAnimationCurve::Create() { KeyframedColorAnimationCurve::Create() {
return base::WrapUnique(new KeyframedColorAnimationCurve); return base::WrapUnique(new KeyframedColorAnimationCurve);
...@@ -570,4 +597,54 @@ gfx::SizeF KeyframedSizeAnimationCurve::GetValue(base::TimeDelta t) const { ...@@ -570,4 +597,54 @@ gfx::SizeF KeyframedSizeAnimationCurve::GetValue(base::TimeDelta t) const {
keyframes_[i + 1]->Value()); keyframes_[i + 1]->Value());
} }
std::unique_ptr<KeyframedBooleanAnimationCurve>
KeyframedBooleanAnimationCurve::Create() {
return base::WrapUnique(new KeyframedBooleanAnimationCurve);
}
KeyframedBooleanAnimationCurve::KeyframedBooleanAnimationCurve()
: scaled_duration_(1.0) {}
KeyframedBooleanAnimationCurve::~KeyframedBooleanAnimationCurve() {}
void KeyframedBooleanAnimationCurve::AddKeyframe(
std::unique_ptr<BooleanKeyframe> keyframe) {
InsertKeyframe(std::move(keyframe), &keyframes_);
}
base::TimeDelta KeyframedBooleanAnimationCurve::Duration() const {
return TimeUtil::Scale(keyframes_.back()->Time() - keyframes_.front()->Time(),
scaled_duration());
}
std::unique_ptr<AnimationCurve> KeyframedBooleanAnimationCurve::Clone() const {
std::unique_ptr<KeyframedBooleanAnimationCurve> to_return =
KeyframedBooleanAnimationCurve::Create();
for (size_t i = 0; i < keyframes_.size(); ++i)
to_return->AddKeyframe(keyframes_[i]->Clone());
if (timing_function_)
to_return->SetTimingFunction(timing_function_->Clone());
to_return->set_scaled_duration(scaled_duration());
return std::move(to_return);
}
bool KeyframedBooleanAnimationCurve::GetValue(base::TimeDelta t) const {
if (t <= TimeUtil::Scale(keyframes_.front()->Time(), scaled_duration()))
return keyframes_.front()->Value();
if (t >= TimeUtil::Scale(keyframes_.back()->Time(), scaled_duration()))
return keyframes_.back()->Value();
t = TransformedAnimationTime(keyframes_, timing_function_, scaled_duration(),
t);
size_t i = GetActiveKeyframe(keyframes_, scaled_duration(), t);
double progress =
TransformedKeyframeProgress(keyframes_, scaled_duration(), t, i);
return progress >= 1.0 ? keyframes_[i + 1]->Value() : keyframes_[i]->Value();
}
} // namespace cc } // namespace cc
...@@ -136,6 +136,26 @@ class CC_ANIMATION_EXPORT SizeKeyframe : public Keyframe { ...@@ -136,6 +136,26 @@ class CC_ANIMATION_EXPORT SizeKeyframe : public Keyframe {
gfx::SizeF value_; gfx::SizeF value_;
}; };
class CC_ANIMATION_EXPORT BooleanKeyframe : public Keyframe {
public:
static std::unique_ptr<BooleanKeyframe> Create(
base::TimeDelta time,
bool value,
std::unique_ptr<TimingFunction> timing_function);
~BooleanKeyframe() override;
bool Value() const;
std::unique_ptr<BooleanKeyframe> Clone() const;
private:
BooleanKeyframe(base::TimeDelta time,
bool value,
std::unique_ptr<TimingFunction> timing_function);
bool value_;
};
class CC_ANIMATION_EXPORT KeyframedColorAnimationCurve class CC_ANIMATION_EXPORT KeyframedColorAnimationCurve
: public ColorAnimationCurve { : public ColorAnimationCurve {
public: public:
...@@ -332,6 +352,42 @@ class CC_ANIMATION_EXPORT KeyframedSizeAnimationCurve ...@@ -332,6 +352,42 @@ class CC_ANIMATION_EXPORT KeyframedSizeAnimationCurve
DISALLOW_COPY_AND_ASSIGN(KeyframedSizeAnimationCurve); DISALLOW_COPY_AND_ASSIGN(KeyframedSizeAnimationCurve);
}; };
class CC_ANIMATION_EXPORT KeyframedBooleanAnimationCurve
: public BooleanAnimationCurve {
public:
// It is required that the keyframes be sorted by time.
static std::unique_ptr<KeyframedBooleanAnimationCurve> Create();
~KeyframedBooleanAnimationCurve() override;
void AddKeyframe(std::unique_ptr<BooleanKeyframe> keyframe);
void SetTimingFunction(std::unique_ptr<TimingFunction> timing_function) {
timing_function_ = std::move(timing_function);
}
double scaled_duration() const { return scaled_duration_; }
void set_scaled_duration(double scaled_duration) {
scaled_duration_ = scaled_duration;
}
// AnimationCurve implementation
base::TimeDelta Duration() const override;
std::unique_ptr<AnimationCurve> Clone() const override;
// BooleanAnimationCurve implementation
bool GetValue(base::TimeDelta t) const override;
private:
KeyframedBooleanAnimationCurve();
// Always sorted in order of increasing time. No two keyframes have the
// same time.
std::vector<std::unique_ptr<BooleanKeyframe>> keyframes_;
std::unique_ptr<TimingFunction> timing_function_;
double scaled_duration_;
DISALLOW_COPY_AND_ASSIGN(KeyframedBooleanAnimationCurve);
};
} // namespace cc } // namespace cc
#endif // CC_ANIMATION_KEYFRAMED_ANIMATION_CURVE_H_ #endif // CC_ANIMATION_KEYFRAMED_ANIMATION_CURVE_H_
...@@ -1076,5 +1076,87 @@ TEST(KeyframedAnimationCurveTest, RepeatedSizeKeyFrame) { ...@@ -1076,5 +1076,87 @@ TEST(KeyframedAnimationCurveTest, RepeatedSizeKeyFrame) {
EXPECT_SIZEF_EQ(size_b, curve->GetValue(base::TimeDelta::FromSecondsD(3.f))); EXPECT_SIZEF_EQ(size_b, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
} }
// Tests that a boolean animation with one keyframe works as expected.
TEST(KeyframedAnimationCurveTest, OneBooleanKeyFrame) {
bool value = true;
std::unique_ptr<KeyframedBooleanAnimationCurve> curve(
KeyframedBooleanAnimationCurve::Create());
curve->AddKeyframe(
BooleanKeyframe::Create(base::TimeDelta(), value, nullptr));
EXPECT_EQ(value, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
EXPECT_EQ(value, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
EXPECT_EQ(value, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
EXPECT_EQ(value, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
EXPECT_EQ(value, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
}
// Tests that a boolean animation with two keyframes works as expected.
TEST(KeyframedAnimationCurveTest, TwoBooleanKeyFrame) {
bool value_a = true;
bool value_b = false;
std::unique_ptr<KeyframedBooleanAnimationCurve> curve(
KeyframedBooleanAnimationCurve::Create());
curve->AddKeyframe(
BooleanKeyframe::Create(base::TimeDelta(), value_a, nullptr));
curve->AddKeyframe(BooleanKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
value_b, nullptr));
EXPECT_EQ(value_a, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
EXPECT_EQ(value_a, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
EXPECT_EQ(value_a, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
EXPECT_EQ(value_b, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
EXPECT_EQ(value_b, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
}
// Tests that a boolean animation with three keyframes works as expected.
TEST(KeyframedAnimationCurveTest, ThreeBooleanKeyFrame) {
bool value_a = false;
bool value_b = true;
bool value_c = false;
std::unique_ptr<KeyframedBooleanAnimationCurve> curve(
KeyframedBooleanAnimationCurve::Create());
curve->AddKeyframe(
BooleanKeyframe::Create(base::TimeDelta(), value_a, nullptr));
curve->AddKeyframe(BooleanKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
value_b, nullptr));
curve->AddKeyframe(BooleanKeyframe::Create(base::TimeDelta::FromSecondsD(2.0),
value_c, nullptr));
EXPECT_EQ(value_a, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
EXPECT_EQ(value_a, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
EXPECT_EQ(value_a, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
EXPECT_EQ(value_b, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)));
EXPECT_EQ(value_b, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
EXPECT_EQ(value_c, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
EXPECT_EQ(value_c, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
}
// Tests that a boolean animation with multiple keys at a given time works
// sanely.
TEST(KeyframedAnimationCurveTest, RepeatedBooleanKeyFrame) {
bool value_a = true;
bool value_b = false;
std::unique_ptr<KeyframedBooleanAnimationCurve> curve(
KeyframedBooleanAnimationCurve::Create());
curve->AddKeyframe(
BooleanKeyframe::Create(base::TimeDelta(), value_a, nullptr));
curve->AddKeyframe(BooleanKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
value_a, nullptr));
curve->AddKeyframe(BooleanKeyframe::Create(base::TimeDelta::FromSecondsD(1.0),
value_b, nullptr));
curve->AddKeyframe(BooleanKeyframe::Create(base::TimeDelta::FromSecondsD(2.0),
value_b, nullptr));
EXPECT_EQ(value_a, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f)));
EXPECT_EQ(value_a, curve->GetValue(base::TimeDelta::FromSecondsD(0.f)));
EXPECT_EQ(value_a, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)));
EXPECT_EQ(value_b, curve->GetValue(base::TimeDelta::FromSecondsD(1.0f)));
EXPECT_EQ(value_b, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f)));
EXPECT_EQ(value_b, curve->GetValue(base::TimeDelta::FromSecondsD(2.f)));
EXPECT_EQ(value_b, curve->GetValue(base::TimeDelta::FromSecondsD(3.f)));
}
} // namespace } // namespace
} // namespace cc } // namespace cc
...@@ -15,8 +15,8 @@ static_assert(TargetProperty::FIRST_TARGET_PROPERTY == 0, ...@@ -15,8 +15,8 @@ static_assert(TargetProperty::FIRST_TARGET_PROPERTY == 0,
// This should match the TargetProperty enum. // This should match the TargetProperty enum.
static const char* const s_targetPropertyNames[] = { static const char* const s_targetPropertyNames[] = {
"TRANSFORM", "OPACITY", "FILTER", "TRANSFORM", "OPACITY", "FILTER", "SCROLL_OFFSET",
"SCROLL_OFFSET", "BACKGROUND_COLOR", "BOUNDS"}; "BACKGROUND_COLOR", "BOUNDS", "VISIBILITY"};
static_assert(static_cast<int>(TargetProperty::LAST_TARGET_PROPERTY) + 1 == static_assert(static_cast<int>(TargetProperty::LAST_TARGET_PROPERTY) + 1 ==
arraysize(s_targetPropertyNames), arraysize(s_targetPropertyNames),
......
...@@ -20,9 +20,10 @@ enum Type { ...@@ -20,9 +20,10 @@ enum Type {
SCROLL_OFFSET, SCROLL_OFFSET,
BACKGROUND_COLOR, BACKGROUND_COLOR,
BOUNDS, BOUNDS,
VISIBILITY,
// These sentinels must be last // These sentinels must be last
FIRST_TARGET_PROPERTY = TRANSFORM, FIRST_TARGET_PROPERTY = TRANSFORM,
LAST_TARGET_PROPERTY = BOUNDS LAST_TARGET_PROPERTY = VISIBILITY,
}; };
CC_EXPORT const char* GetName(TargetProperty::Type property); CC_EXPORT const char* GetName(TargetProperty::Type property);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment