| // Copyright 2012 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 "cc/animation/keyframed_animation_curve.h" |
| |
| #include "cc/animation/transform_operations.h" |
| #include "testing/gmock/include/gmock/gmock.h" |
| #include "testing/gtest/include/gtest/gtest.h" |
| #include "ui/gfx/animation/tween.h" |
| #include "ui/gfx/geometry/box_f.h" |
| #include "ui/gfx/test/gfx_util.h" |
| |
| namespace cc { |
| namespace { |
| |
| void ExpectTranslateX(SkMScalar translate_x, const gfx::Transform& transform) { |
| EXPECT_FLOAT_EQ(translate_x, transform.matrix().get(0, 3)); |
| } |
| |
| void ExpectBrightness(double brightness, const FilterOperations& filter) { |
| EXPECT_EQ(1u, filter.size()); |
| EXPECT_EQ(FilterOperation::BRIGHTNESS, filter.at(0).type()); |
| EXPECT_FLOAT_EQ(brightness, filter.at(0).amount()); |
| } |
| |
| // Tests that a color animation with one keyframe works as expected. |
| TEST(KeyframedAnimationCurveTest, OneColorKeyFrame) { |
| SkColor color = SkColorSetARGB(255, 255, 255, 255); |
| scoped_ptr<KeyframedColorAnimationCurve> curve( |
| KeyframedColorAnimationCurve::Create()); |
| curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta(), color, nullptr)); |
| |
| EXPECT_SKCOLOR_EQ(color, |
| curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| EXPECT_SKCOLOR_EQ(color, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| EXPECT_SKCOLOR_EQ(color, |
| curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| EXPECT_SKCOLOR_EQ(color, curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| EXPECT_SKCOLOR_EQ(color, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| } |
| |
| // Tests that a color animation with two keyframes works as expected. |
| TEST(KeyframedAnimationCurveTest, TwoColorKeyFrame) { |
| SkColor color_a = SkColorSetARGB(255, 255, 0, 0); |
| SkColor color_b = SkColorSetARGB(255, 0, 255, 0); |
| SkColor color_midpoint = gfx::Tween::ColorValueBetween(0.5, color_a, color_b); |
| scoped_ptr<KeyframedColorAnimationCurve> curve( |
| KeyframedColorAnimationCurve::Create()); |
| curve->AddKeyframe( |
| ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr)); |
| curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), |
| color_b, nullptr)); |
| |
| EXPECT_SKCOLOR_EQ(color_a, |
| curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| EXPECT_SKCOLOR_EQ(color_a, |
| curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| EXPECT_SKCOLOR_EQ(color_midpoint, |
| curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| EXPECT_SKCOLOR_EQ(color_b, |
| curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| EXPECT_SKCOLOR_EQ(color_b, |
| curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| } |
| |
| // Tests that a color animation with three keyframes works as expected. |
| TEST(KeyframedAnimationCurveTest, ThreeColorKeyFrame) { |
| SkColor color_a = SkColorSetARGB(255, 255, 0, 0); |
| SkColor color_b = SkColorSetARGB(255, 0, 255, 0); |
| SkColor color_c = SkColorSetARGB(255, 0, 0, 255); |
| SkColor color_midpoint1 = |
| gfx::Tween::ColorValueBetween(0.5, color_a, color_b); |
| SkColor color_midpoint2 = |
| gfx::Tween::ColorValueBetween(0.5, color_b, color_c); |
| scoped_ptr<KeyframedColorAnimationCurve> curve( |
| KeyframedColorAnimationCurve::Create()); |
| curve->AddKeyframe( |
| ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr)); |
| curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), |
| color_b, nullptr)); |
| curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), |
| color_c, nullptr)); |
| |
| EXPECT_SKCOLOR_EQ(color_a, |
| curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| EXPECT_SKCOLOR_EQ(color_a, |
| curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| EXPECT_SKCOLOR_EQ(color_midpoint1, |
| curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| EXPECT_SKCOLOR_EQ(color_b, |
| curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| EXPECT_SKCOLOR_EQ(color_midpoint2, |
| curve->GetValue(base::TimeDelta::FromSecondsD(1.5f))); |
| EXPECT_SKCOLOR_EQ(color_c, |
| curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| EXPECT_SKCOLOR_EQ(color_c, |
| curve->GetValue(base::TimeDelta::FromSecondsD(3.f))); |
| } |
| |
| // Tests that a colro animation with multiple keys at a given time works sanely. |
| TEST(KeyframedAnimationCurveTest, RepeatedColorKeyFrame) { |
| SkColor color_a = SkColorSetARGB(255, 64, 0, 0); |
| SkColor color_b = SkColorSetARGB(255, 192, 0, 0); |
| |
| scoped_ptr<KeyframedColorAnimationCurve> curve( |
| KeyframedColorAnimationCurve::Create()); |
| curve->AddKeyframe( |
| ColorKeyframe::Create(base::TimeDelta(), color_a, nullptr)); |
| curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), |
| color_a, nullptr)); |
| curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), |
| color_b, nullptr)); |
| curve->AddKeyframe(ColorKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), |
| color_b, nullptr)); |
| |
| EXPECT_SKCOLOR_EQ(color_a, |
| curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| EXPECT_SKCOLOR_EQ(color_a, |
| curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| EXPECT_SKCOLOR_EQ(color_a, |
| curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| |
| SkColor value = curve->GetValue(base::TimeDelta::FromSecondsD(1.0f)); |
| EXPECT_EQ(255u, SkColorGetA(value)); |
| int red_value = SkColorGetR(value); |
| EXPECT_LE(64, red_value); |
| EXPECT_GE(192, red_value); |
| |
| EXPECT_SKCOLOR_EQ(color_b, |
| curve->GetValue(base::TimeDelta::FromSecondsD(1.5f))); |
| EXPECT_SKCOLOR_EQ(color_b, |
| curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| EXPECT_SKCOLOR_EQ(color_b, |
| curve->GetValue(base::TimeDelta::FromSecondsD(3.f))); |
| } |
| |
| // Tests that a float animation with one keyframe works as expected. |
| TEST(KeyframedAnimationCurveTest, OneFloatKeyframe) { |
| scoped_ptr<KeyframedFloatAnimationCurve> curve( |
| KeyframedFloatAnimationCurve::Create()); |
| curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr)); |
| EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| } |
| |
| // Tests that a float animation with two keyframes works as expected. |
| TEST(KeyframedAnimationCurveTest, TwoFloatKeyframe) { |
| scoped_ptr<KeyframedFloatAnimationCurve> curve( |
| KeyframedFloatAnimationCurve::Create()); |
| curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 4.f, nullptr)); |
| EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| } |
| |
| // Tests that a float animation with three keyframes works as expected. |
| TEST(KeyframedAnimationCurveTest, ThreeFloatKeyframe) { |
| scoped_ptr<KeyframedFloatAnimationCurve> curve( |
| KeyframedFloatAnimationCurve::Create()); |
| curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 4.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), 8.f, nullptr)); |
| EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f))); |
| EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f))); |
| } |
| |
| // Tests that a float animation with multiple keys at a given time works sanely. |
| TEST(KeyframedAnimationCurveTest, RepeatedFloatKeyTimes) { |
| scoped_ptr<KeyframedFloatAnimationCurve> curve( |
| KeyframedFloatAnimationCurve::Create()); |
| curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 4.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 4.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 6.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), 6.f, nullptr)); |
| |
| EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| |
| // There is a discontinuity at 1. Any value between 4 and 6 is valid. |
| float value = curve->GetValue(base::TimeDelta::FromSecondsD(1.f)); |
| EXPECT_TRUE(value >= 4 && value <= 6); |
| |
| EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f))); |
| EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f))); |
| } |
| |
| // Tests that a transform animation with one keyframe works as expected. |
| TEST(KeyframedAnimationCurveTest, OneTransformKeyframe) { |
| scoped_ptr<KeyframedTransformAnimationCurve> curve( |
| KeyframedTransformAnimationCurve::Create()); |
| TransformOperations operations; |
| operations.AppendTranslate(2.f, 0.f, 0.f); |
| curve->AddKeyframe( |
| TransformKeyframe::Create(base::TimeDelta(), operations, nullptr)); |
| |
| ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| } |
| |
| // Tests that a transform animation with two keyframes works as expected. |
| TEST(KeyframedAnimationCurveTest, TwoTransformKeyframe) { |
| scoped_ptr<KeyframedTransformAnimationCurve> curve( |
| KeyframedTransformAnimationCurve::Create()); |
| TransformOperations operations1; |
| operations1.AppendTranslate(2.f, 0.f, 0.f); |
| TransformOperations operations2; |
| operations2.AppendTranslate(4.f, 0.f, 0.f); |
| |
| curve->AddKeyframe( |
| TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr)); |
| curve->AddKeyframe(TransformKeyframe::Create( |
| base::TimeDelta::FromSecondsD(1.0), operations2, nullptr)); |
| ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| ExpectTranslateX(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| } |
| |
| // Tests that a transform animation with three keyframes works as expected. |
| TEST(KeyframedAnimationCurveTest, ThreeTransformKeyframe) { |
| scoped_ptr<KeyframedTransformAnimationCurve> curve( |
| KeyframedTransformAnimationCurve::Create()); |
| TransformOperations operations1; |
| operations1.AppendTranslate(2.f, 0.f, 0.f); |
| TransformOperations operations2; |
| operations2.AppendTranslate(4.f, 0.f, 0.f); |
| TransformOperations operations3; |
| operations3.AppendTranslate(8.f, 0.f, 0.f); |
| curve->AddKeyframe( |
| TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr)); |
| curve->AddKeyframe(TransformKeyframe::Create( |
| base::TimeDelta::FromSecondsD(1.0), operations2, nullptr)); |
| curve->AddKeyframe(TransformKeyframe::Create( |
| base::TimeDelta::FromSecondsD(2.0), operations3, nullptr)); |
| ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| ExpectTranslateX(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| ExpectTranslateX(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f))); |
| ExpectTranslateX(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| ExpectTranslateX(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f))); |
| } |
| |
| // Tests that a transform animation with multiple keys at a given time works |
| // sanely. |
| TEST(KeyframedAnimationCurveTest, RepeatedTransformKeyTimes) { |
| scoped_ptr<KeyframedTransformAnimationCurve> curve( |
| KeyframedTransformAnimationCurve::Create()); |
| // A step function. |
| TransformOperations operations1; |
| operations1.AppendTranslate(4.f, 0.f, 0.f); |
| TransformOperations operations2; |
| operations2.AppendTranslate(4.f, 0.f, 0.f); |
| TransformOperations operations3; |
| operations3.AppendTranslate(6.f, 0.f, 0.f); |
| TransformOperations operations4; |
| operations4.AppendTranslate(6.f, 0.f, 0.f); |
| curve->AddKeyframe( |
| TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr)); |
| curve->AddKeyframe(TransformKeyframe::Create( |
| base::TimeDelta::FromSecondsD(1.0), operations2, nullptr)); |
| curve->AddKeyframe(TransformKeyframe::Create( |
| base::TimeDelta::FromSecondsD(1.0), operations3, nullptr)); |
| curve->AddKeyframe(TransformKeyframe::Create( |
| base::TimeDelta::FromSecondsD(2.0), operations4, nullptr)); |
| |
| ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| ExpectTranslateX(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| |
| // There is a discontinuity at 1. Any value between 4 and 6 is valid. |
| gfx::Transform value = curve->GetValue(base::TimeDelta::FromSecondsD(1.f)); |
| EXPECT_GE(value.matrix().get(0, 3), 4.f); |
| EXPECT_LE(value.matrix().get(0, 3), 6.f); |
| |
| ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f))); |
| ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| ExpectTranslateX(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f))); |
| } |
| |
| // Tests that a filter animation with one keyframe works as expected. |
| TEST(KeyframedAnimationCurveTest, OneFilterKeyframe) { |
| scoped_ptr<KeyframedFilterAnimationCurve> curve( |
| KeyframedFilterAnimationCurve::Create()); |
| FilterOperations operations; |
| operations.Append(FilterOperation::CreateBrightnessFilter(2.f)); |
| curve->AddKeyframe( |
| FilterKeyframe::Create(base::TimeDelta(), operations, nullptr)); |
| |
| ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| } |
| |
| // Tests that a filter animation with two keyframes works as expected. |
| TEST(KeyframedAnimationCurveTest, TwoFilterKeyframe) { |
| scoped_ptr<KeyframedFilterAnimationCurve> curve( |
| KeyframedFilterAnimationCurve::Create()); |
| FilterOperations operations1; |
| operations1.Append(FilterOperation::CreateBrightnessFilter(2.f)); |
| FilterOperations operations2; |
| operations2.Append(FilterOperation::CreateBrightnessFilter(4.f)); |
| |
| curve->AddKeyframe( |
| FilterKeyframe::Create(base::TimeDelta(), operations1, nullptr)); |
| curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), |
| operations2, nullptr)); |
| ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| ExpectBrightness(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| } |
| |
| // Tests that a filter animation with three keyframes works as expected. |
| TEST(KeyframedAnimationCurveTest, ThreeFilterKeyframe) { |
| scoped_ptr<KeyframedFilterAnimationCurve> curve( |
| KeyframedFilterAnimationCurve::Create()); |
| FilterOperations operations1; |
| operations1.Append(FilterOperation::CreateBrightnessFilter(2.f)); |
| FilterOperations operations2; |
| operations2.Append(FilterOperation::CreateBrightnessFilter(4.f)); |
| FilterOperations operations3; |
| operations3.Append(FilterOperation::CreateBrightnessFilter(8.f)); |
| curve->AddKeyframe( |
| FilterKeyframe::Create(base::TimeDelta(), operations1, nullptr)); |
| curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), |
| operations2, nullptr)); |
| curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), |
| operations3, nullptr)); |
| ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| ExpectBrightness(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| ExpectBrightness(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f))); |
| ExpectBrightness(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| ExpectBrightness(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f))); |
| } |
| |
| // Tests that a filter animation with multiple keys at a given time works |
| // sanely. |
| TEST(KeyframedAnimationCurveTest, RepeatedFilterKeyTimes) { |
| scoped_ptr<KeyframedFilterAnimationCurve> curve( |
| KeyframedFilterAnimationCurve::Create()); |
| // A step function. |
| FilterOperations operations1; |
| operations1.Append(FilterOperation::CreateBrightnessFilter(4.f)); |
| FilterOperations operations2; |
| operations2.Append(FilterOperation::CreateBrightnessFilter(4.f)); |
| FilterOperations operations3; |
| operations3.Append(FilterOperation::CreateBrightnessFilter(6.f)); |
| FilterOperations operations4; |
| operations4.Append(FilterOperation::CreateBrightnessFilter(6.f)); |
| curve->AddKeyframe( |
| FilterKeyframe::Create(base::TimeDelta(), operations1, nullptr)); |
| curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), |
| operations2, nullptr)); |
| curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), |
| operations3, nullptr)); |
| curve->AddKeyframe(FilterKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), |
| operations4, nullptr)); |
| |
| ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| ExpectBrightness(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| |
| // There is a discontinuity at 1. Any value between 4 and 6 is valid. |
| FilterOperations value = curve->GetValue(base::TimeDelta::FromSecondsD(1.f)); |
| EXPECT_EQ(1u, value.size()); |
| EXPECT_EQ(FilterOperation::BRIGHTNESS, value.at(0).type()); |
| EXPECT_GE(value.at(0).amount(), 4); |
| EXPECT_LE(value.at(0).amount(), 6); |
| |
| ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f))); |
| ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| ExpectBrightness(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f))); |
| } |
| |
| // Tests that the keyframes may be added out of order. |
| TEST(KeyframedAnimationCurveTest, UnsortedKeyframes) { |
| scoped_ptr<KeyframedFloatAnimationCurve> curve( |
| KeyframedFloatAnimationCurve::Create()); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), 8.f, nullptr)); |
| curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 2.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 4.f, nullptr)); |
| EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| EXPECT_FLOAT_EQ(2.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| EXPECT_FLOAT_EQ(4.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| EXPECT_FLOAT_EQ(6.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.5f))); |
| EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| EXPECT_FLOAT_EQ(8.f, curve->GetValue(base::TimeDelta::FromSecondsD(3.f))); |
| } |
| |
| // Tests that a cubic bezier timing function works as expected. |
| TEST(KeyframedAnimationCurveTest, CubicBezierTimingFunction) { |
| scoped_ptr<KeyframedFloatAnimationCurve> curve( |
| KeyframedFloatAnimationCurve::Create()); |
| curve->AddKeyframe(FloatKeyframe::Create( |
| base::TimeDelta(), 0.f, |
| CubicBezierTimingFunction::Create(0.25f, 0.f, 0.75f, 1.f))); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 1.f, nullptr)); |
| |
| EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| EXPECT_LT(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f))); |
| EXPECT_GT(0.25f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f))); |
| EXPECT_NEAR(curve->GetValue(base::TimeDelta::FromSecondsD(0.5f)), 0.5f, |
| 0.00015f); |
| EXPECT_LT(0.75f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f))); |
| EXPECT_GT(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f))); |
| EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| } |
| |
| // Tests that animated bounds are computed as expected. |
| TEST(KeyframedAnimationCurveTest, AnimatedBounds) { |
| scoped_ptr<KeyframedTransformAnimationCurve> curve( |
| KeyframedTransformAnimationCurve::Create()); |
| |
| TransformOperations operations1; |
| curve->AddKeyframe( |
| TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr)); |
| operations1.AppendTranslate(2.0, 3.0, -1.0); |
| curve->AddKeyframe(TransformKeyframe::Create( |
| base::TimeDelta::FromSecondsD(0.5f), operations1, nullptr)); |
| TransformOperations operations2; |
| operations2.AppendTranslate(4.0, 1.0, 2.0); |
| curve->AddKeyframe( |
| TransformKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), operations2, |
| EaseTimingFunction::Create())); |
| |
| gfx::BoxF box(2.f, 3.f, 4.f, 1.f, 3.f, 2.f); |
| gfx::BoxF bounds; |
| |
| EXPECT_TRUE(curve->AnimatedBoundsForBox(box, &bounds)); |
| EXPECT_EQ(gfx::BoxF(2.f, 3.f, 3.f, 5.f, 6.f, 5.f).ToString(), |
| bounds.ToString()); |
| } |
| |
| // Tests that animations that affect scale are correctly identified. |
| TEST(KeyframedAnimationCurveTest, AffectsScale) { |
| scoped_ptr<KeyframedTransformAnimationCurve> curve( |
| KeyframedTransformAnimationCurve::Create()); |
| |
| TransformOperations operations1; |
| curve->AddKeyframe( |
| TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr)); |
| operations1.AppendTranslate(2.0, 3.0, -1.0); |
| TransformOperations operations2; |
| operations2.AppendTranslate(4.0, 1.0, 2.0); |
| curve->AddKeyframe(TransformKeyframe::Create( |
| base::TimeDelta::FromSecondsD(1.f), operations2, nullptr)); |
| |
| EXPECT_FALSE(curve->AffectsScale()); |
| |
| TransformOperations operations3; |
| operations3.AppendScale(2.f, 2.f, 2.f); |
| curve->AddKeyframe(TransformKeyframe::Create( |
| base::TimeDelta::FromSecondsD(2.f), operations3, nullptr)); |
| |
| EXPECT_TRUE(curve->AffectsScale()); |
| |
| TransformOperations operations4; |
| operations3.AppendTranslate(2.f, 2.f, 2.f); |
| curve->AddKeyframe(TransformKeyframe::Create( |
| base::TimeDelta::FromSecondsD(3.f), operations4, nullptr)); |
| |
| EXPECT_TRUE(curve->AffectsScale()); |
| } |
| |
| // Tests that animations that are translations are correctly identified. |
| TEST(KeyframedAnimationCurveTest, IsTranslation) { |
| scoped_ptr<KeyframedTransformAnimationCurve> curve( |
| KeyframedTransformAnimationCurve::Create()); |
| |
| TransformOperations operations1; |
| curve->AddKeyframe( |
| TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr)); |
| operations1.AppendTranslate(2.0, 3.0, -1.0); |
| TransformOperations operations2; |
| operations2.AppendTranslate(4.0, 1.0, 2.0); |
| curve->AddKeyframe(TransformKeyframe::Create( |
| base::TimeDelta::FromSecondsD(1.f), operations2, nullptr)); |
| |
| EXPECT_TRUE(curve->IsTranslation()); |
| |
| TransformOperations operations3; |
| operations3.AppendScale(2.f, 2.f, 2.f); |
| curve->AddKeyframe(TransformKeyframe::Create( |
| base::TimeDelta::FromSecondsD(2.f), operations3, nullptr)); |
| |
| EXPECT_FALSE(curve->IsTranslation()); |
| |
| TransformOperations operations4; |
| operations3.AppendTranslate(2.f, 2.f, 2.f); |
| curve->AddKeyframe(TransformKeyframe::Create( |
| base::TimeDelta::FromSecondsD(3.f), operations4, nullptr)); |
| |
| EXPECT_FALSE(curve->IsTranslation()); |
| } |
| |
| // Tests that maximum target scale is computed as expected. |
| TEST(KeyframedAnimationCurveTest, MaximumTargetScale) { |
| scoped_ptr<KeyframedTransformAnimationCurve> curve( |
| KeyframedTransformAnimationCurve::Create()); |
| |
| TransformOperations operations1; |
| curve->AddKeyframe( |
| TransformKeyframe::Create(base::TimeDelta(), operations1, nullptr)); |
| operations1.AppendScale(2.f, -3.f, 1.f); |
| curve->AddKeyframe( |
| TransformKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), operations1, |
| EaseTimingFunction::Create())); |
| |
| float maximum_scale = 0.f; |
| EXPECT_TRUE(curve->MaximumTargetScale(true, &maximum_scale)); |
| EXPECT_EQ(3.f, maximum_scale); |
| |
| TransformOperations operations2; |
| operations2.AppendScale(6.f, 3.f, 2.f); |
| curve->AddKeyframe( |
| TransformKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), operations2, |
| EaseTimingFunction::Create())); |
| |
| EXPECT_TRUE(curve->MaximumTargetScale(true, &maximum_scale)); |
| EXPECT_EQ(6.f, maximum_scale); |
| |
| TransformOperations operations3; |
| operations3.AppendRotate(1.f, 0.f, 0.f, 90.f); |
| curve->AddKeyframe( |
| TransformKeyframe::Create(base::TimeDelta::FromSecondsD(3.f), operations3, |
| EaseTimingFunction::Create())); |
| |
| EXPECT_FALSE(curve->MaximumTargetScale(true, &maximum_scale)); |
| |
| // The original scale is not used in computing the max. |
| scoped_ptr<KeyframedTransformAnimationCurve> curve2( |
| KeyframedTransformAnimationCurve::Create()); |
| |
| TransformOperations operations4; |
| operations4.AppendScale(0.4f, 0.2f, 0.6f); |
| curve2->AddKeyframe(TransformKeyframe::Create(base::TimeDelta(), operations4, |
| EaseTimingFunction::Create())); |
| TransformOperations operations5; |
| operations5.AppendScale(0.5f, 0.3f, -0.8f); |
| curve2->AddKeyframe( |
| TransformKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), operations5, |
| EaseTimingFunction::Create())); |
| |
| EXPECT_TRUE(curve2->MaximumTargetScale(true, &maximum_scale)); |
| EXPECT_EQ(0.8f, maximum_scale); |
| |
| EXPECT_TRUE(curve2->MaximumTargetScale(false, &maximum_scale)); |
| EXPECT_EQ(0.6f, maximum_scale); |
| } |
| |
| // Tests that an animation with a curve timing function works as expected. |
| TEST(KeyframedAnimationCurveTest, CurveTiming) { |
| scoped_ptr<KeyframedFloatAnimationCurve> curve( |
| KeyframedFloatAnimationCurve::Create()); |
| curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr)); |
| curve->SetTimingFunction( |
| CubicBezierTimingFunction::Create(0.75f, 0.f, 0.25f, 1.f).Pass()); |
| EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| EXPECT_NEAR(0.05f, curve->GetValue(base::TimeDelta::FromSecondsD(0.25f)), |
| 0.005f); |
| EXPECT_FLOAT_EQ(0.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| EXPECT_NEAR(0.95f, curve->GetValue(base::TimeDelta::FromSecondsD(0.75f)), |
| 0.005f); |
| EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| } |
| |
| // Tests that an animation with a curve and keyframe timing function works as |
| // expected. |
| TEST(KeyframedAnimationCurveTest, CurveAndKeyframeTiming) { |
| scoped_ptr<KeyframedFloatAnimationCurve> curve( |
| KeyframedFloatAnimationCurve::Create()); |
| curve->AddKeyframe(FloatKeyframe::Create( |
| base::TimeDelta(), 0.f, |
| CubicBezierTimingFunction::Create(0.35f, 0.f, 0.65f, 1.f).Pass())); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr)); |
| // Curve timing function producing outputs outside of range [0,1]. |
| curve->SetTimingFunction( |
| CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f).Pass()); |
| EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD( |
| 0.25f))); // Clamped. c(.25) < 0 |
| EXPECT_NEAR(0.17f, curve->GetValue(base::TimeDelta::FromSecondsD(0.42f)), |
| 0.005f); // c(.42)=.27, k(.27)=.17 |
| EXPECT_FLOAT_EQ(0.5f, curve->GetValue(base::TimeDelta::FromSecondsD(0.5f))); |
| EXPECT_NEAR(0.83f, curve->GetValue(base::TimeDelta::FromSecondsD(0.58f)), |
| 0.005f); // c(.58)=.73, k(.73)=.83 |
| EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD( |
| 0.75f))); // Clamped. c(.75) > 1 |
| EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f))); |
| EXPECT_FLOAT_EQ(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| } |
| |
| // Tests that an animation with a curve timing function and multiple keyframes |
| // works as expected. |
| TEST(KeyframedAnimationCurveTest, CurveTimingMultipleKeyframes) { |
| scoped_ptr<KeyframedFloatAnimationCurve> curve( |
| KeyframedFloatAnimationCurve::Create()); |
| curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.f), 1.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.f), 3.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(3.f), 6.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(4.f), 9.f, nullptr)); |
| curve->SetTimingFunction( |
| CubicBezierTimingFunction::Create(0.5f, 0.f, 0.5f, 1.f).Pass()); |
| EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(-1.f))); |
| EXPECT_FLOAT_EQ(0.f, curve->GetValue(base::TimeDelta::FromSecondsD(0.f))); |
| EXPECT_NEAR(0.42f, curve->GetValue(base::TimeDelta::FromSecondsD(1.f)), |
| 0.005f); |
| EXPECT_NEAR(1.f, curve->GetValue(base::TimeDelta::FromSecondsD(1.455f)), |
| 0.005f); |
| EXPECT_FLOAT_EQ(3.f, curve->GetValue(base::TimeDelta::FromSecondsD(2.f))); |
| EXPECT_NEAR(8.72f, curve->GetValue(base::TimeDelta::FromSecondsD(3.5f)), |
| 0.01f); |
| EXPECT_FLOAT_EQ(9.f, curve->GetValue(base::TimeDelta::FromSecondsD(4.f))); |
| EXPECT_FLOAT_EQ(9.f, curve->GetValue(base::TimeDelta::FromSecondsD(5.f))); |
| } |
| |
| // Tests that an animation with a curve timing function that overshoots works as |
| // expected. |
| TEST(KeyframedAnimationCurveTest, CurveTimingOvershootMultipeKeyframes) { |
| scoped_ptr<KeyframedFloatAnimationCurve> curve( |
| KeyframedFloatAnimationCurve::Create()); |
| curve->AddKeyframe(FloatKeyframe::Create(base::TimeDelta(), 0.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(1.0), 1.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(2.0), 3.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(3.0), 6.f, nullptr)); |
| curve->AddKeyframe( |
| FloatKeyframe::Create(base::TimeDelta::FromSecondsD(4.0), 9.f, nullptr)); |
| // Curve timing function producing outputs outside of range [0,1]. |
| curve->SetTimingFunction( |
| CubicBezierTimingFunction::Create(0.5f, -0.5f, 0.5f, 1.5f).Pass()); |
| EXPECT_LE(curve->GetValue(base::TimeDelta::FromSecondsD(1.f)), |
| 0.f); // c(.25) < 0 |
| EXPECT_GE(curve->GetValue(base::TimeDelta::FromSecondsD(3.f)), |
| 9.f); // c(.75) > 1 |
| } |
| |
| } // namespace |
| } // namespace cc |