blob: 9794ee2fc9c8fe1473fca6b52da3202681685a64 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/vr/animation.h"
#include "cc/animation/animation_target.h"
#include "cc/test/geometry_test_utils.h"
#include "chrome/browser/vr/target_property.h"
#include "chrome/browser/vr/test/animation_utils.h"
#include "chrome/browser/vr/test/constants.h"
#include "chrome/browser/vr/transition.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "third_party/skia/include/core/SkColor.h"
#include "ui/gfx/test/gfx_util.h"
namespace vr {
static constexpr float kNoise = 1e-6f;
class TestAnimationTarget : public cc::AnimationTarget {
public:
TestAnimationTarget() {
layout_offset_.AppendTranslate(0, 0, 0);
operations_.AppendTranslate(0, 0, 0);
operations_.AppendRotate(1, 0, 0, 0);
operations_.AppendScale(1, 1, 1);
}
const gfx::SizeF& size() const { return size_; }
const cc::TransformOperations& operations() const { return operations_; }
const cc::TransformOperations& layout_offset() const {
return layout_offset_;
}
float opacity() const { return opacity_; }
SkColor background_color() const { return background_color_; }
void NotifyClientSizeAnimated(const gfx::SizeF& size,
int target_property_id,
cc::KeyframeModel* keyframe_model) override {
size_ = size;
}
void NotifyClientTransformOperationsAnimated(
const cc::TransformOperations& operations,
int target_property_id,
cc::KeyframeModel* keyframe_model) override {
if (target_property_id == LAYOUT_OFFSET) {
layout_offset_ = operations;
} else {
operations_ = operations;
}
}
void NotifyClientFloatAnimated(float opacity,
int target_property_id,
cc::KeyframeModel* keyframe_model) override {
opacity_ = opacity;
}
void NotifyClientColorAnimated(SkColor color,
int target_property_id,
cc::KeyframeModel* keyframe_model) override {
background_color_ = color;
}
void NotifyClientFilterAnimated(const cc::FilterOperations& filter,
int target_property_id,
cc::KeyframeModel* keyframe_model) override {}
void NotifyClientScrollOffsetAnimated(
const gfx::ScrollOffset& scroll_offset,
int target_property_id,
cc::KeyframeModel* keyframe_model) override {}
private:
cc::TransformOperations layout_offset_;
cc::TransformOperations operations_;
gfx::SizeF size_ = {10.0f, 10.0f};
float opacity_ = 1.0f;
SkColor background_color_ = SK_ColorRED;
};
TEST(AnimationTest, AddRemoveKeyframeModels) {
Animation animation;
EXPECT_TRUE(animation.keyframe_models().empty());
animation.AddKeyframeModel(CreateBoundsAnimation(1, 1, gfx::SizeF(10, 100),
gfx::SizeF(20, 200),
MicrosecondsToDelta(10000)));
EXPECT_EQ(1ul, animation.keyframe_models().size());
EXPECT_EQ(BOUNDS, animation.keyframe_models()[0]->target_property_id());
cc::TransformOperations from_operations;
from_operations.AppendTranslate(10, 100, 1000);
cc::TransformOperations to_operations;
to_operations.AppendTranslate(20, 200, 2000);
animation.AddKeyframeModel(CreateTransformAnimation(
2, 2, from_operations, to_operations, MicrosecondsToDelta(10000)));
EXPECT_EQ(2ul, animation.keyframe_models().size());
EXPECT_EQ(TRANSFORM, animation.keyframe_models()[1]->target_property_id());
animation.AddKeyframeModel(CreateTransformAnimation(
3, 3, from_operations, to_operations, MicrosecondsToDelta(10000)));
EXPECT_EQ(3ul, animation.keyframe_models().size());
EXPECT_EQ(TRANSFORM, animation.keyframe_models()[2]->target_property_id());
animation.RemoveKeyframeModels(TRANSFORM);
EXPECT_EQ(1ul, animation.keyframe_models().size());
EXPECT_EQ(BOUNDS, animation.keyframe_models()[0]->target_property_id());
animation.RemoveKeyframeModel(animation.keyframe_models()[0]->id());
EXPECT_TRUE(animation.keyframe_models().empty());
}
TEST(AnimationTest, AnimationLifecycle) {
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
animation.AddKeyframeModel(CreateBoundsAnimation(1, 1, gfx::SizeF(10, 100),
gfx::SizeF(20, 200),
MicrosecondsToDelta(10000)));
EXPECT_EQ(1ul, animation.keyframe_models().size());
EXPECT_EQ(BOUNDS, animation.keyframe_models()[0]->target_property_id());
EXPECT_EQ(cc::KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY,
animation.keyframe_models()[0]->run_state());
base::TimeTicks start_time = MicrosecondsToTicks(1);
animation.Tick(start_time);
EXPECT_EQ(cc::KeyframeModel::RUNNING,
animation.keyframe_models()[0]->run_state());
EXPECT_SIZEF_EQ(gfx::SizeF(10, 100), target.size());
// Tick beyond the animation
animation.Tick(start_time + MicrosecondsToDelta(20000));
EXPECT_TRUE(animation.keyframe_models().empty());
// Should have assumed the final value.
EXPECT_SIZEF_EQ(gfx::SizeF(20, 200), target.size());
}
TEST(AnimationTest, AnimationQueue) {
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
animation.AddKeyframeModel(CreateBoundsAnimation(1, 1, gfx::SizeF(10, 100),
gfx::SizeF(20, 200),
MicrosecondsToDelta(10000)));
EXPECT_EQ(1ul, animation.keyframe_models().size());
EXPECT_EQ(BOUNDS, animation.keyframe_models()[0]->target_property_id());
EXPECT_EQ(cc::KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY,
animation.keyframe_models()[0]->run_state());
base::TimeTicks start_time = MicrosecondsToTicks(1);
animation.Tick(start_time);
EXPECT_EQ(cc::KeyframeModel::RUNNING,
animation.keyframe_models()[0]->run_state());
EXPECT_SIZEF_EQ(gfx::SizeF(10, 100), target.size());
animation.AddKeyframeModel(CreateBoundsAnimation(2, 2, gfx::SizeF(10, 100),
gfx::SizeF(20, 200),
MicrosecondsToDelta(10000)));
cc::TransformOperations from_operations;
from_operations.AppendTranslate(10, 100, 1000);
cc::TransformOperations to_operations;
to_operations.AppendTranslate(20, 200, 2000);
animation.AddKeyframeModel(CreateTransformAnimation(
3, 2, from_operations, to_operations, MicrosecondsToDelta(10000)));
EXPECT_EQ(3ul, animation.keyframe_models().size());
EXPECT_EQ(BOUNDS, animation.keyframe_models()[1]->target_property_id());
EXPECT_EQ(TRANSFORM, animation.keyframe_models()[2]->target_property_id());
int id1 = animation.keyframe_models()[1]->id();
animation.Tick(start_time + MicrosecondsToDelta(1));
// Only the transform animation should have started (since there's no
// conflicting animation).
EXPECT_EQ(cc::KeyframeModel::WAITING_FOR_TARGET_AVAILABILITY,
animation.keyframe_models()[1]->run_state());
EXPECT_EQ(cc::KeyframeModel::RUNNING,
animation.keyframe_models()[2]->run_state());
// Tick beyond the first animation. This should cause it (and the transform
// animation) to get removed and for the second bounds animation to start.
animation.Tick(start_time + MicrosecondsToDelta(15000));
EXPECT_EQ(1ul, animation.keyframe_models().size());
EXPECT_EQ(cc::KeyframeModel::RUNNING,
animation.keyframe_models()[0]->run_state());
EXPECT_EQ(id1, animation.keyframe_models()[0]->id());
// Tick beyond all animations. There should be none remaining.
animation.Tick(start_time + MicrosecondsToDelta(30000));
EXPECT_TRUE(animation.keyframe_models().empty());
}
TEST(AnimationTest, FinishedTransition) {
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
Transition transition;
transition.target_properties = {OPACITY};
transition.duration = MsToDelta(10);
animation.set_transition(transition);
base::TimeTicks start_time = MsToTicks(1000);
animation.Tick(start_time);
float from = 1.0f;
float to = 0.0f;
animation.TransitionFloatTo(start_time, OPACITY, from, to);
animation.Tick(start_time);
EXPECT_EQ(from, target.opacity());
// We now simulate a long pause where the element hasn't been ticked (eg, it
// may have been hidden). If this happens, the unticked transition must still
// be treated as having finished.
animation.TransitionFloatTo(start_time + MsToDelta(1000), OPACITY,
target.opacity(), 1.0f);
animation.Tick(start_time + MsToDelta(1000));
EXPECT_EQ(to, target.opacity());
}
TEST(AnimationTest, OpacityTransitions) {
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
Transition transition;
transition.target_properties = {OPACITY};
transition.duration = MicrosecondsToDelta(10000);
animation.set_transition(transition);
base::TimeTicks start_time = MicrosecondsToTicks(1000000);
animation.Tick(start_time);
float from = 1.0f;
float to = 0.5f;
animation.TransitionFloatTo(start_time, OPACITY, from, to);
EXPECT_EQ(from, target.opacity());
animation.Tick(start_time);
// Scheduling a redundant, approximately equal transition should be ignored.
int keyframe_model_id = animation.keyframe_models().front()->id();
float nearby = to + kNoise;
animation.TransitionFloatTo(start_time, OPACITY, from, nearby);
EXPECT_EQ(keyframe_model_id, animation.keyframe_models().front()->id());
animation.Tick(start_time + MicrosecondsToDelta(5000));
EXPECT_GT(from, target.opacity());
EXPECT_LT(to, target.opacity());
animation.Tick(start_time + MicrosecondsToDelta(10000));
EXPECT_EQ(to, target.opacity());
}
TEST(AnimationTest, ReversedOpacityTransitions) {
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
Transition transition;
transition.target_properties = {OPACITY};
transition.duration = MicrosecondsToDelta(10000);
animation.set_transition(transition);
base::TimeTicks start_time = MicrosecondsToTicks(1000000);
animation.Tick(start_time);
float from = 1.0f;
float to = 0.5f;
animation.TransitionFloatTo(start_time, OPACITY, from, to);
EXPECT_EQ(from, target.opacity());
animation.Tick(start_time);
animation.Tick(start_time + MicrosecondsToDelta(1000));
float value_before_reversing = target.opacity();
EXPECT_GT(from, value_before_reversing);
EXPECT_LT(to, value_before_reversing);
animation.TransitionFloatTo(start_time + MicrosecondsToDelta(1000), OPACITY,
target.opacity(), from);
animation.Tick(start_time + MicrosecondsToDelta(1000));
EXPECT_FLOAT_EQ(value_before_reversing, target.opacity());
animation.Tick(start_time + MicrosecondsToDelta(2000));
EXPECT_EQ(from, target.opacity());
}
TEST(AnimationTest, LayoutOffsetTransitions) {
// In this test, we do expect exact equality.
float tolerance = 0.0f;
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
Transition transition;
transition.target_properties = {LAYOUT_OFFSET};
transition.duration = MicrosecondsToDelta(10000);
animation.set_transition(transition);
base::TimeTicks start_time = MicrosecondsToTicks(1000000);
animation.Tick(start_time);
cc::TransformOperations from = target.layout_offset();
cc::TransformOperations to;
to.AppendTranslate(8, 0, 0);
animation.TransitionTransformOperationsTo(start_time, LAYOUT_OFFSET, from,
to);
EXPECT_TRUE(from.ApproximatelyEqual(target.layout_offset(), tolerance));
animation.Tick(start_time);
// Scheduling a redundant, approximately equal transition should be ignored.
int keyframe_model_id = animation.keyframe_models().front()->id();
cc::TransformOperations nearby = to;
nearby.at(0).translate.x += kNoise;
animation.TransitionTransformOperationsTo(start_time, LAYOUT_OFFSET, from,
nearby);
EXPECT_EQ(keyframe_model_id, animation.keyframe_models().front()->id());
animation.Tick(start_time + MicrosecondsToDelta(5000));
EXPECT_LT(from.at(0).translate.x, target.layout_offset().at(0).translate.x);
EXPECT_GT(to.at(0).translate.x, target.layout_offset().at(0).translate.x);
animation.Tick(start_time + MicrosecondsToDelta(10000));
EXPECT_TRUE(to.ApproximatelyEqual(target.layout_offset(), tolerance));
}
TEST(AnimationTest, TransformTransitions) {
// In this test, we do expect exact equality.
float tolerance = 0.0f;
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
Transition transition;
transition.target_properties = {TRANSFORM};
transition.duration = MicrosecondsToDelta(10000);
animation.set_transition(transition);
base::TimeTicks start_time = MicrosecondsToTicks(1000000);
animation.Tick(start_time);
cc::TransformOperations from = target.operations();
cc::TransformOperations to;
to.AppendTranslate(8, 0, 0);
to.AppendRotate(1, 0, 0, 0);
to.AppendScale(1, 1, 1);
animation.TransitionTransformOperationsTo(start_time, TRANSFORM, from, to);
EXPECT_TRUE(from.ApproximatelyEqual(target.operations(), tolerance));
animation.Tick(start_time);
// Scheduling a redundant, approximately equal transition should be ignored.
int keyframe_model_id = animation.keyframe_models().front()->id();
cc::TransformOperations nearby = to;
nearby.at(0).translate.x += kNoise;
animation.TransitionTransformOperationsTo(start_time, TRANSFORM, from,
nearby);
EXPECT_EQ(keyframe_model_id, animation.keyframe_models().front()->id());
animation.Tick(start_time + MicrosecondsToDelta(5000));
EXPECT_LT(from.at(0).translate.x, target.operations().at(0).translate.x);
EXPECT_GT(to.at(0).translate.x, target.operations().at(0).translate.x);
animation.Tick(start_time + MicrosecondsToDelta(10000));
EXPECT_TRUE(to.ApproximatelyEqual(target.operations(), tolerance));
}
TEST(AnimationTest, ReversedTransformTransitions) {
// In this test, we do expect exact equality.
float tolerance = 0.0f;
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
Transition transition;
transition.target_properties = {TRANSFORM};
transition.duration = MicrosecondsToDelta(10000);
animation.set_transition(transition);
base::TimeTicks start_time = MicrosecondsToTicks(1000000);
animation.Tick(start_time);
cc::TransformOperations from = target.operations();
cc::TransformOperations to;
to.AppendTranslate(8, 0, 0);
to.AppendRotate(1, 0, 0, 0);
to.AppendScale(1, 1, 1);
animation.TransitionTransformOperationsTo(start_time, TRANSFORM, from, to);
EXPECT_TRUE(from.ApproximatelyEqual(target.operations(), tolerance));
animation.Tick(start_time);
animation.Tick(start_time + MicrosecondsToDelta(1000));
cc::TransformOperations value_before_reversing = target.operations();
EXPECT_LT(from.at(0).translate.x, target.operations().at(0).translate.x);
EXPECT_GT(to.at(0).translate.x, target.operations().at(0).translate.x);
animation.TransitionTransformOperationsTo(
start_time + MicrosecondsToDelta(1000), TRANSFORM, target.operations(),
from);
animation.Tick(start_time + MicrosecondsToDelta(1000));
EXPECT_TRUE(value_before_reversing.ApproximatelyEqual(target.operations(),
tolerance));
animation.Tick(start_time + MicrosecondsToDelta(2000));
EXPECT_TRUE(from.ApproximatelyEqual(target.operations(), tolerance));
}
TEST(AnimationTest, BoundsTransitions) {
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
Transition transition;
transition.target_properties = {BOUNDS};
transition.duration = MicrosecondsToDelta(10000);
animation.set_transition(transition);
base::TimeTicks start_time = MicrosecondsToTicks(1000000);
animation.Tick(start_time);
gfx::SizeF from = target.size();
gfx::SizeF to(20.0f, 20.0f);
animation.TransitionSizeTo(start_time, BOUNDS, from, to);
EXPECT_FLOAT_SIZE_EQ(from, target.size());
animation.Tick(start_time);
// Scheduling a redundant, approximately equal transition should be ignored.
int keyframe_model_id = animation.keyframe_models().front()->id();
gfx::SizeF nearby = to;
nearby.set_width(to.width() + kNoise);
animation.TransitionSizeTo(start_time, BOUNDS, from, nearby);
EXPECT_EQ(keyframe_model_id, animation.keyframe_models().front()->id());
animation.Tick(start_time + MicrosecondsToDelta(5000));
EXPECT_LT(from.width(), target.size().width());
EXPECT_GT(to.width(), target.size().width());
EXPECT_LT(from.height(), target.size().height());
EXPECT_GT(to.height(), target.size().height());
animation.Tick(start_time + MicrosecondsToDelta(10000));
EXPECT_FLOAT_SIZE_EQ(to, target.size());
}
TEST(AnimationTest, ReversedBoundsTransitions) {
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
Transition transition;
transition.target_properties = {BOUNDS};
transition.duration = MicrosecondsToDelta(10000);
animation.set_transition(transition);
base::TimeTicks start_time = MicrosecondsToTicks(1000000);
animation.Tick(start_time);
gfx::SizeF from = target.size();
gfx::SizeF to(20.0f, 20.0f);
animation.TransitionSizeTo(start_time, BOUNDS, from, to);
EXPECT_FLOAT_SIZE_EQ(from, target.size());
animation.Tick(start_time);
animation.Tick(start_time + MicrosecondsToDelta(1000));
gfx::SizeF value_before_reversing = target.size();
EXPECT_LT(from.width(), target.size().width());
EXPECT_GT(to.width(), target.size().width());
EXPECT_LT(from.height(), target.size().height());
EXPECT_GT(to.height(), target.size().height());
animation.TransitionSizeTo(start_time + MicrosecondsToDelta(1000), BOUNDS,
target.size(), from);
animation.Tick(start_time + MicrosecondsToDelta(1000));
EXPECT_FLOAT_SIZE_EQ(value_before_reversing, target.size());
animation.Tick(start_time + MicrosecondsToDelta(2000));
EXPECT_FLOAT_SIZE_EQ(from, target.size());
}
TEST(AnimationTest, BackgroundColorTransitions) {
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
Transition transition;
transition.target_properties = {BACKGROUND_COLOR};
transition.duration = MicrosecondsToDelta(10000);
animation.set_transition(transition);
base::TimeTicks start_time = MicrosecondsToTicks(1000000);
animation.Tick(start_time);
SkColor from = SK_ColorRED;
SkColor to = SK_ColorGREEN;
animation.TransitionColorTo(start_time, BACKGROUND_COLOR, from, to);
EXPECT_EQ(from, target.background_color());
animation.Tick(start_time);
animation.Tick(start_time + MicrosecondsToDelta(5000));
EXPECT_GT(SkColorGetR(from), SkColorGetR(target.background_color()));
EXPECT_LT(SkColorGetR(to), SkColorGetR(target.background_color()));
EXPECT_LT(SkColorGetG(from), SkColorGetG(target.background_color()));
EXPECT_GT(SkColorGetG(to), SkColorGetG(target.background_color()));
EXPECT_EQ(0u, SkColorGetB(target.background_color()));
EXPECT_EQ(255u, SkColorGetA(target.background_color()));
animation.Tick(start_time + MicrosecondsToDelta(10000));
EXPECT_EQ(to, target.background_color());
}
TEST(AnimationTest, ReversedBackgroundColorTransitions) {
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
Transition transition;
transition.target_properties = {BACKGROUND_COLOR};
transition.duration = MicrosecondsToDelta(10000);
animation.set_transition(transition);
base::TimeTicks start_time = MicrosecondsToTicks(1000000);
animation.Tick(start_time);
SkColor from = SK_ColorRED;
SkColor to = SK_ColorGREEN;
animation.TransitionColorTo(start_time, BACKGROUND_COLOR, from, to);
EXPECT_EQ(from, target.background_color());
animation.Tick(start_time);
animation.Tick(start_time + MicrosecondsToDelta(1000));
SkColor value_before_reversing = target.background_color();
EXPECT_GT(SkColorGetR(from), SkColorGetR(target.background_color()));
EXPECT_LT(SkColorGetR(to), SkColorGetR(target.background_color()));
EXPECT_LT(SkColorGetG(from), SkColorGetG(target.background_color()));
EXPECT_GT(SkColorGetG(to), SkColorGetG(target.background_color()));
EXPECT_EQ(0u, SkColorGetB(target.background_color()));
EXPECT_EQ(255u, SkColorGetA(target.background_color()));
animation.TransitionColorTo(start_time + MicrosecondsToDelta(1000),
BACKGROUND_COLOR, target.background_color(),
from);
animation.Tick(start_time + MicrosecondsToDelta(1000));
EXPECT_EQ(value_before_reversing, target.background_color());
animation.Tick(start_time + MicrosecondsToDelta(2000));
EXPECT_EQ(from, target.background_color());
}
TEST(AnimationTest, DoubleReversedTransitions) {
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
Transition transition;
transition.target_properties = {OPACITY};
transition.duration = MicrosecondsToDelta(10000);
animation.set_transition(transition);
base::TimeTicks start_time = MicrosecondsToTicks(1000000);
animation.Tick(start_time);
float from = 1.0f;
float to = 0.5f;
animation.TransitionFloatTo(start_time, OPACITY, from, to);
EXPECT_EQ(from, target.opacity());
animation.Tick(start_time);
animation.Tick(start_time + MicrosecondsToDelta(1000));
float value_before_reversing = target.opacity();
EXPECT_GT(from, value_before_reversing);
EXPECT_LT(to, value_before_reversing);
animation.TransitionFloatTo(start_time + MicrosecondsToDelta(1000), OPACITY,
target.opacity(), from);
animation.Tick(start_time + MicrosecondsToDelta(1000));
EXPECT_FLOAT_EQ(value_before_reversing, target.opacity());
animation.Tick(start_time + MicrosecondsToDelta(1500));
value_before_reversing = target.opacity();
// If the code for reversing transitions does not account for an existing time
// offset, then reversing a second time will give incorrect values.
animation.TransitionFloatTo(start_time + MicrosecondsToDelta(1500), OPACITY,
target.opacity(), to);
animation.Tick(start_time + MicrosecondsToDelta(1500));
EXPECT_FLOAT_EQ(value_before_reversing, target.opacity());
}
TEST(AnimationTest, RedundantTransition) {
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
Transition transition;
transition.target_properties = {OPACITY};
transition.duration = MicrosecondsToDelta(10000);
animation.set_transition(transition);
base::TimeTicks start_time = MicrosecondsToTicks(1000000);
animation.Tick(start_time);
float from = 1.0f;
float to = 0.5f;
animation.TransitionFloatTo(start_time, OPACITY, from, to);
EXPECT_EQ(from, target.opacity());
animation.Tick(start_time);
animation.Tick(start_time + MicrosecondsToDelta(1000));
float value_before_redundant_transition = target.opacity();
// While an existing transition is in progress to the same value, we should
// not start a new transition.
animation.TransitionFloatTo(start_time, OPACITY, target.opacity(), to);
EXPECT_EQ(1lu, animation.keyframe_models().size());
EXPECT_EQ(value_before_redundant_transition, target.opacity());
}
TEST(AnimationTest, TransitionToSameValue) {
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
Transition transition;
transition.target_properties = {OPACITY};
transition.duration = MicrosecondsToDelta(10000);
animation.set_transition(transition);
base::TimeTicks start_time = MicrosecondsToTicks(1000000);
animation.Tick(start_time);
// Transitioning to the same value should be a no-op.
float from = 1.0f;
float to = 1.0f;
animation.TransitionFloatTo(start_time, OPACITY, from, to);
EXPECT_EQ(from, target.opacity());
EXPECT_TRUE(animation.keyframe_models().empty());
}
TEST(AnimationTest, CorrectTargetValue) {
TestAnimationTarget target;
Animation animation;
animation.set_target(&target);
base::TimeDelta duration = MicrosecondsToDelta(10000);
float from_opacity = 1.0f;
float to_opacity = 0.5f;
gfx::SizeF from_bounds = gfx::SizeF(10, 200);
gfx::SizeF to_bounds = gfx::SizeF(20, 200);
SkColor from_color = SK_ColorRED;
SkColor to_color = SK_ColorGREEN;
cc::TransformOperations from_transform;
from_transform.AppendTranslate(10, 100, 1000);
cc::TransformOperations to_transform;
to_transform.AppendTranslate(20, 200, 2000);
// Verify the default value is returned if there's no running animations.
EXPECT_EQ(from_opacity, animation.GetTargetFloatValue(OPACITY, from_opacity));
EXPECT_SIZEF_EQ(from_bounds,
animation.GetTargetSizeValue(BOUNDS, from_bounds));
EXPECT_EQ(from_color,
animation.GetTargetColorValue(BACKGROUND_COLOR, from_color));
EXPECT_TRUE(from_transform.ApproximatelyEqual(
animation.GetTargetTransformOperationsValue(TRANSFORM, from_transform),
kEpsilon));
// Add keyframe_models.
animation.AddKeyframeModel(
CreateOpacityAnimation(2, 1, from_opacity, to_opacity, duration));
animation.AddKeyframeModel(
CreateBoundsAnimation(1, 1, from_bounds, to_bounds, duration));
animation.AddKeyframeModel(
CreateBackgroundColorAnimation(3, 1, from_color, to_color, duration));
animation.AddKeyframeModel(
CreateTransformAnimation(4, 1, from_transform, to_transform, duration));
base::TimeTicks start_time = MicrosecondsToTicks(1000000);
animation.Tick(start_time);
// Verify target value.
EXPECT_EQ(to_opacity, animation.GetTargetFloatValue(OPACITY, from_opacity));
EXPECT_SIZEF_EQ(to_bounds, animation.GetTargetSizeValue(BOUNDS, from_bounds));
EXPECT_EQ(to_color,
animation.GetTargetColorValue(BACKGROUND_COLOR, from_color));
EXPECT_TRUE(to_transform.ApproximatelyEqual(
animation.GetTargetTransformOperationsValue(TRANSFORM, from_transform),
kEpsilon));
}
} // namespace vr