普通文本  |  550行  |  21.71 KB

// 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/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(0.0, color, scoped_ptr<TimingFunction>()));

  EXPECT_SKCOLOR_EQ(color, curve->GetValue(-1.f));
  EXPECT_SKCOLOR_EQ(color, curve->GetValue(0.f));
  EXPECT_SKCOLOR_EQ(color, curve->GetValue(0.5f));
  EXPECT_SKCOLOR_EQ(color, curve->GetValue(1.f));
  EXPECT_SKCOLOR_EQ(color, curve->GetValue(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(0.0, color_a, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(
      ColorKeyframe::Create(1.0, color_b, scoped_ptr<TimingFunction>()));

  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(-1.f));
  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.f));
  EXPECT_SKCOLOR_EQ(color_midpoint, curve->GetValue(0.5f));
  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(1.f));
  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(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(0.0, color_a, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(
      ColorKeyframe::Create(1.0, color_b, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(
      ColorKeyframe::Create(2.0, color_c, scoped_ptr<TimingFunction>()));

  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(-1.f));
  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.f));
  EXPECT_SKCOLOR_EQ(color_midpoint1, curve->GetValue(0.5f));
  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(1.f));
  EXPECT_SKCOLOR_EQ(color_midpoint2, curve->GetValue(1.5f));
  EXPECT_SKCOLOR_EQ(color_c, curve->GetValue(2.f));
  EXPECT_SKCOLOR_EQ(color_c, curve->GetValue(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(0.0, color_a, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(
      ColorKeyframe::Create(1.0, color_a, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(
      ColorKeyframe::Create(1.0, color_b, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(
      ColorKeyframe::Create(2.0, color_b, scoped_ptr<TimingFunction>()));

  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(-1.f));
  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.f));
  EXPECT_SKCOLOR_EQ(color_a, curve->GetValue(0.5f));

  SkColor value = curve->GetValue(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(1.5f));
  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(2.f));
  EXPECT_SKCOLOR_EQ(color_b, curve->GetValue(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(0.0, 2.f, scoped_ptr<TimingFunction>()));
  EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f));
  EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f));
  EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.5f));
  EXPECT_FLOAT_EQ(2.f, curve->GetValue(1.f));
  EXPECT_FLOAT_EQ(2.f, curve->GetValue(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(0.0, 2.f, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(
      FloatKeyframe::Create(1.0, 4.f, scoped_ptr<TimingFunction>()));
  EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f));
  EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f));
  EXPECT_FLOAT_EQ(3.f, curve->GetValue(0.5f));
  EXPECT_FLOAT_EQ(4.f, curve->GetValue(1.f));
  EXPECT_FLOAT_EQ(4.f, curve->GetValue(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(0.0, 2.f, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(
      FloatKeyframe::Create(1.0, 4.f, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(
      FloatKeyframe::Create(2.0, 8.f, scoped_ptr<TimingFunction>()));
  EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f));
  EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f));
  EXPECT_FLOAT_EQ(3.f, curve->GetValue(0.5f));
  EXPECT_FLOAT_EQ(4.f, curve->GetValue(1.f));
  EXPECT_FLOAT_EQ(6.f, curve->GetValue(1.5f));
  EXPECT_FLOAT_EQ(8.f, curve->GetValue(2.f));
  EXPECT_FLOAT_EQ(8.f, curve->GetValue(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(0.0, 4.f, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(
      FloatKeyframe::Create(1.0, 4.f, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(
      FloatKeyframe::Create(1.0, 6.f, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(
      FloatKeyframe::Create(2.0, 6.f, scoped_ptr<TimingFunction>()));

  EXPECT_FLOAT_EQ(4.f, curve->GetValue(-1.f));
  EXPECT_FLOAT_EQ(4.f, curve->GetValue(0.f));
  EXPECT_FLOAT_EQ(4.f, curve->GetValue(0.5f));

  // There is a discontinuity at 1. Any value between 4 and 6 is valid.
  float value = curve->GetValue(1.f);
  EXPECT_TRUE(value >= 4 && value <= 6);

  EXPECT_FLOAT_EQ(6.f, curve->GetValue(1.5f));
  EXPECT_FLOAT_EQ(6.f, curve->GetValue(2.f));
  EXPECT_FLOAT_EQ(6.f, curve->GetValue(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(0.f, operations, scoped_ptr<TimingFunction>()));

  ExpectTranslateX(2.f, curve->GetValue(-1.f));
  ExpectTranslateX(2.f, curve->GetValue(0.f));
  ExpectTranslateX(2.f, curve->GetValue(0.5f));
  ExpectTranslateX(2.f, curve->GetValue(1.f));
  ExpectTranslateX(2.f, curve->GetValue(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(
      0.f, operations1, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(TransformKeyframe::Create(
      1.f, operations2, scoped_ptr<TimingFunction>()));
  ExpectTranslateX(2.f, curve->GetValue(-1.f));
  ExpectTranslateX(2.f, curve->GetValue(0.f));
  ExpectTranslateX(3.f, curve->GetValue(0.5f));
  ExpectTranslateX(4.f, curve->GetValue(1.f));
  ExpectTranslateX(4.f, curve->GetValue(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(
      0.f, operations1, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(TransformKeyframe::Create(
      1.f, operations2, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(TransformKeyframe::Create(
      2.f, operations3, scoped_ptr<TimingFunction>()));
  ExpectTranslateX(2.f, curve->GetValue(-1.f));
  ExpectTranslateX(2.f, curve->GetValue(0.f));
  ExpectTranslateX(3.f, curve->GetValue(0.5f));
  ExpectTranslateX(4.f, curve->GetValue(1.f));
  ExpectTranslateX(6.f, curve->GetValue(1.5f));
  ExpectTranslateX(8.f, curve->GetValue(2.f));
  ExpectTranslateX(8.f, curve->GetValue(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(
      0.f, operations1, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(TransformKeyframe::Create(
      1.f, operations2, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(TransformKeyframe::Create(
      1.f, operations3, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(TransformKeyframe::Create(
      2.f, operations4, scoped_ptr<TimingFunction>()));

  ExpectTranslateX(4.f, curve->GetValue(-1.f));
  ExpectTranslateX(4.f, curve->GetValue(0.f));
  ExpectTranslateX(4.f, curve->GetValue(0.5f));

  // There is a discontinuity at 1. Any value between 4 and 6 is valid.
  gfx::Transform value = curve->GetValue(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(1.5f));
  ExpectTranslateX(6.f, curve->GetValue(2.f));
  ExpectTranslateX(6.f, curve->GetValue(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(0.f, operations, scoped_ptr<TimingFunction>()));

  ExpectBrightness(2.f, curve->GetValue(-1.f));
  ExpectBrightness(2.f, curve->GetValue(0.f));
  ExpectBrightness(2.f, curve->GetValue(0.5f));
  ExpectBrightness(2.f, curve->GetValue(1.f));
  ExpectBrightness(2.f, curve->GetValue(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(
      0.f, operations1, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(FilterKeyframe::Create(
      1.f, operations2, scoped_ptr<TimingFunction>()));
  ExpectBrightness(2.f, curve->GetValue(-1.f));
  ExpectBrightness(2.f, curve->GetValue(0.f));
  ExpectBrightness(3.f, curve->GetValue(0.5f));
  ExpectBrightness(4.f, curve->GetValue(1.f));
  ExpectBrightness(4.f, curve->GetValue(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(
      0.f, operations1, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(FilterKeyframe::Create(
      1.f, operations2, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(FilterKeyframe::Create(
      2.f, operations3, scoped_ptr<TimingFunction>()));
  ExpectBrightness(2.f, curve->GetValue(-1.f));
  ExpectBrightness(2.f, curve->GetValue(0.f));
  ExpectBrightness(3.f, curve->GetValue(0.5f));
  ExpectBrightness(4.f, curve->GetValue(1.f));
  ExpectBrightness(6.f, curve->GetValue(1.5f));
  ExpectBrightness(8.f, curve->GetValue(2.f));
  ExpectBrightness(8.f, curve->GetValue(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(
      0.f, operations1, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(FilterKeyframe::Create(
      1.f, operations2, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(FilterKeyframe::Create(
      1.f, operations3, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(FilterKeyframe::Create(
      2.f, operations4, scoped_ptr<TimingFunction>()));

  ExpectBrightness(4.f, curve->GetValue(-1.f));
  ExpectBrightness(4.f, curve->GetValue(0.f));
  ExpectBrightness(4.f, curve->GetValue(0.5f));

  // There is a discontinuity at 1. Any value between 4 and 6 is valid.
  FilterOperations value = curve->GetValue(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(1.5f));
  ExpectBrightness(6.f, curve->GetValue(2.f));
  ExpectBrightness(6.f, curve->GetValue(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(2.0, 8.f, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(
      FloatKeyframe::Create(0.0, 2.f, scoped_ptr<TimingFunction>()));
  curve->AddKeyframe(
      FloatKeyframe::Create(1.0, 4.f, scoped_ptr<TimingFunction>()));
  EXPECT_FLOAT_EQ(2.f, curve->GetValue(-1.f));
  EXPECT_FLOAT_EQ(2.f, curve->GetValue(0.f));
  EXPECT_FLOAT_EQ(3.f, curve->GetValue(0.5f));
  EXPECT_FLOAT_EQ(4.f, curve->GetValue(1.f));
  EXPECT_FLOAT_EQ(6.f, curve->GetValue(1.5f));
  EXPECT_FLOAT_EQ(8.f, curve->GetValue(2.f));
  EXPECT_FLOAT_EQ(8.f, curve->GetValue(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(
      0.0,
      0.f,
      CubicBezierTimingFunction::Create(0.25f, 0.f, 0.75f, 1.f)
          .PassAs<TimingFunction>()));
  curve->AddKeyframe(
      FloatKeyframe::Create(1.0, 1.f, scoped_ptr<TimingFunction>()));

  EXPECT_FLOAT_EQ(0.f, curve->GetValue(0.f));
  EXPECT_LT(0.f, curve->GetValue(0.25f));
  EXPECT_GT(0.25f, curve->GetValue(0.25f));
  EXPECT_NEAR(curve->GetValue(0.5f), 0.5f, 0.00015f);
  EXPECT_LT(0.75f, curve->GetValue(0.75f));
  EXPECT_GT(1.f, curve->GetValue(0.75f));
  EXPECT_FLOAT_EQ(1.f, curve->GetValue(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(
      0.0, operations1, scoped_ptr<TimingFunction>()));
  operations1.AppendTranslate(2.0, 3.0, -1.0);
  curve->AddKeyframe(TransformKeyframe::Create(
      0.5, operations1, scoped_ptr<TimingFunction>()));
  TransformOperations operations2;
  operations2.AppendTranslate(4.0, 1.0, 2.0);
  curve->AddKeyframe(TransformKeyframe::Create(
      1.0, 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(
      0.0, operations1, scoped_ptr<TimingFunction>()));
  operations1.AppendTranslate(2.0, 3.0, -1.0);
  TransformOperations operations2;
  operations2.AppendTranslate(4.0, 1.0, 2.0);
  curve->AddKeyframe(TransformKeyframe::Create(
      1.0, operations2, scoped_ptr<TimingFunction>()));

  EXPECT_FALSE(curve->AffectsScale());

  TransformOperations operations3;
  operations3.AppendScale(2.f, 2.f, 2.f);
  curve->AddKeyframe(TransformKeyframe::Create(
      2.0, operations3, scoped_ptr<TimingFunction>()));

  EXPECT_TRUE(curve->AffectsScale());

  TransformOperations operations4;
  operations3.AppendTranslate(2.f, 2.f, 2.f);
  curve->AddKeyframe(TransformKeyframe::Create(
      3.0, operations4, scoped_ptr<TimingFunction>()));

  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(
      0.0, operations1, scoped_ptr<TimingFunction>()));
  operations1.AppendTranslate(2.0, 3.0, -1.0);
  TransformOperations operations2;
  operations2.AppendTranslate(4.0, 1.0, 2.0);
  curve->AddKeyframe(TransformKeyframe::Create(
      1.0, operations2, scoped_ptr<TimingFunction>()));

  EXPECT_TRUE(curve->IsTranslation());

  TransformOperations operations3;
  operations3.AppendScale(2.f, 2.f, 2.f);
  curve->AddKeyframe(TransformKeyframe::Create(
      2.0, operations3, scoped_ptr<TimingFunction>()));

  EXPECT_FALSE(curve->IsTranslation());

  TransformOperations operations4;
  operations3.AppendTranslate(2.f, 2.f, 2.f);
  curve->AddKeyframe(TransformKeyframe::Create(
      3.0, operations4, scoped_ptr<TimingFunction>()));

  EXPECT_FALSE(curve->IsTranslation());
}

// Tests that maximum scale is computed as expected.
TEST(KeyframedAnimationCurveTest, MaximumScale) {
  scoped_ptr<KeyframedTransformAnimationCurve> curve(
      KeyframedTransformAnimationCurve::Create());

  TransformOperations operations1;
  curve->AddKeyframe(TransformKeyframe::Create(
      0.0, operations1, scoped_ptr<TimingFunction>()));
  operations1.AppendScale(2.f, -3.f, 1.f);
  curve->AddKeyframe(TransformKeyframe::Create(
      1.0, operations1, EaseTimingFunction::Create()));

  float maximum_scale = 0.f;
  EXPECT_TRUE(curve->MaximumScale(&maximum_scale));
  EXPECT_EQ(3.f, maximum_scale);

  TransformOperations operations2;
  operations2.AppendScale(6.f, 3.f, 2.f);
  curve->AddKeyframe(TransformKeyframe::Create(
      2.0, operations2, EaseTimingFunction::Create()));

  EXPECT_TRUE(curve->MaximumScale(&maximum_scale));
  EXPECT_EQ(6.f, maximum_scale);

  TransformOperations operations3;
  operations3.AppendRotate(1.f, 0.f, 0.f, 90.f);
  curve->AddKeyframe(TransformKeyframe::Create(
      3.0, operations3, EaseTimingFunction::Create()));

  EXPECT_FALSE(curve->MaximumScale(&maximum_scale));
}

}  // namespace
}  // namespace cc