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 {
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
......@@ -19,6 +19,7 @@ class BoxF;
namespace cc {
class BooleanAnimationCurve;
class ColorAnimationCurve;
class FilterAnimationCurve;
class FloatAnimationCurve;
......@@ -30,7 +31,15 @@ class TransformOperations;
// An animation curve is a function that returns a value given a time.
class CC_ANIMATION_EXPORT AnimationCurve {
public:
enum CurveType { COLOR, FLOAT, TRANSFORM, FILTER, SCROLL_OFFSET, SIZE };
enum CurveType {
COLOR,
FLOAT,
TRANSFORM,
FILTER,
SCROLL_OFFSET,
SIZE,
BOOLEAN,
};
virtual ~AnimationCurve() {}
......@@ -44,6 +53,7 @@ class CC_ANIMATION_EXPORT AnimationCurve {
const FilterAnimationCurve* ToFilterAnimationCurve() const;
const ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve() const;
const SizeAnimationCurve* ToSizeAnimationCurve() const;
const BooleanAnimationCurve* ToBooleanAnimationCurve() const;
ScrollOffsetAnimationCurve* ToScrollOffsetAnimationCurve();
};
......@@ -54,7 +64,7 @@ class CC_ANIMATION_EXPORT ColorAnimationCurve : public AnimationCurve {
virtual SkColor GetValue(base::TimeDelta t) const = 0;
// Partial Animation implementation.
// Partial AnimationCurve implementation.
CurveType Type() const override;
};
......@@ -64,7 +74,7 @@ class CC_ANIMATION_EXPORT FloatAnimationCurve : public AnimationCurve {
virtual float GetValue(base::TimeDelta t) const = 0;
// Partial Animation implementation.
// Partial AnimationCurve implementation.
CurveType Type() const override;
};
......@@ -98,7 +108,7 @@ class CC_ANIMATION_EXPORT TransformAnimationCurve : public AnimationCurve {
virtual bool MaximumTargetScale(bool forward_direction,
float* max_scale) const = 0;
// Partial Animation implementation.
// Partial AnimationCurve implementation.
CurveType Type() const override;
};
......@@ -119,6 +129,16 @@ class CC_ANIMATION_EXPORT SizeAnimationCurve : public AnimationCurve {
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.
CurveType Type() const override;
};
......
......@@ -754,7 +754,8 @@ void AnimationPlayer::TickAnimation(base::TimeTicks monotonic_time,
curve->ToFilterAnimationCurve()->GetValue(trimmed), animation);
break;
case TargetProperty::BACKGROUND_COLOR:
// Not yet implemented.
target->NotifyClientBackgroundColorAnimated(
curve->ToColorAnimationCurve()->GetValue(trimmed), animation);
break;
case TargetProperty::SCROLL_OFFSET:
target->NotifyClientScrollOffsetAnimated(
......@@ -764,6 +765,10 @@ void AnimationPlayer::TickAnimation(base::TimeTicks monotonic_time,
target->NotifyClientBoundsAnimated(
curve->ToSizeAnimationCurve()->GetValue(trimmed), animation);
break;
case TargetProperty::VISIBILITY:
target->NotifyClientVisibilityAnimated(
curve->ToBooleanAnimationCurve()->GetValue(trimmed), animation);
break;
}
}
......
......@@ -6,12 +6,11 @@
#define CC_ANIMATION_ANIMATION_TARGET_H_
#include "cc/animation/animation_export.h"
#include "third_party/skia/include/core/SkColor.h"
namespace gfx {
class ScrollOffset;
class SizeF;
} // namespace gfx
namespace cc {
......@@ -32,6 +31,10 @@ class CC_ANIMATION_EXPORT AnimationTarget {
Animation* animation) {}
virtual void NotifyClientBoundsAnimated(const gfx::SizeF& size,
Animation* animation) {}
virtual void NotifyClientBackgroundColorAnimated(SkColor color,
Animation* animation) {}
virtual void NotifyClientVisibilityAnimated(bool visibility,
Animation* animation) {}
virtual void NotifyClientTransformOperationsAnimated(
const TransformOperations& operations,
Animation* animation) {}
......
......@@ -230,6 +230,33 @@ std::unique_ptr<SizeKeyframe> SizeKeyframe::Clone() const {
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>
KeyframedColorAnimationCurve::Create() {
return base::WrapUnique(new KeyframedColorAnimationCurve);
......@@ -570,4 +597,54 @@ gfx::SizeF KeyframedSizeAnimationCurve::GetValue(base::TimeDelta t) const {
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
......@@ -136,6 +136,26 @@ class CC_ANIMATION_EXPORT SizeKeyframe : public Keyframe {
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
: public ColorAnimationCurve {
public:
......@@ -332,6 +352,42 @@ class CC_ANIMATION_EXPORT 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
#endif // CC_ANIMATION_KEYFRAMED_ANIMATION_CURVE_H_
......@@ -1076,5 +1076,87 @@ TEST(KeyframedAnimationCurveTest, RepeatedSizeKeyFrame) {
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 cc
......@@ -15,8 +15,8 @@ static_assert(TargetProperty::FIRST_TARGET_PROPERTY == 0,
// This should match the TargetProperty enum.
static const char* const s_targetPropertyNames[] = {
"TRANSFORM", "OPACITY", "FILTER",
"SCROLL_OFFSET", "BACKGROUND_COLOR", "BOUNDS"};
"TRANSFORM", "OPACITY", "FILTER", "SCROLL_OFFSET",
"BACKGROUND_COLOR", "BOUNDS", "VISIBILITY"};
static_assert(static_cast<int>(TargetProperty::LAST_TARGET_PROPERTY) + 1 ==
arraysize(s_targetPropertyNames),
......
......@@ -20,9 +20,10 @@ enum Type {
SCROLL_OFFSET,
BACKGROUND_COLOR,
BOUNDS,
VISIBILITY,
// These sentinels must be last
FIRST_TARGET_PROPERTY = TRANSFORM,
LAST_TARGET_PROPERTY = BOUNDS
LAST_TARGET_PROPERTY = VISIBILITY,
};
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