diff options
-rw-r--r-- | cc/animation/animation_curve.h | 7 | ||||
-rw-r--r-- | cc/animation/keyframed_animation_curve.cc | 32 | ||||
-rw-r--r-- | cc/animation/keyframed_animation_curve.h | 2 | ||||
-rw-r--r-- | cc/animation/keyframed_animation_curve_unittest.cc | 63 | ||||
-rw-r--r-- | cc/animation/layer_animation_controller.cc | 33 | ||||
-rw-r--r-- | cc/animation/layer_animation_controller.h | 6 | ||||
-rw-r--r-- | cc/animation/layer_animation_controller_unittest.cc | 125 | ||||
-rw-r--r-- | cc/animation/transform_operations.cc | 84 | ||||
-rw-r--r-- | cc/animation/transform_operations.h | 16 | ||||
-rw-r--r-- | cc/animation/transform_operations_unittest.cc | 188 | ||||
-rw-r--r-- | cc/test/animation_test_common.cc | 7 | ||||
-rw-r--r-- | cc/test/animation_test_common.h | 2 | ||||
-rw-r--r-- | ui/compositor/transform_animation_curve_adapter.cc | 18 | ||||
-rw-r--r-- | ui/compositor/transform_animation_curve_adapter.h | 4 |
14 files changed, 587 insertions, 0 deletions
diff --git a/cc/animation/animation_curve.h b/cc/animation/animation_curve.h index 4c15225..72aadef 100644 --- a/cc/animation/animation_curve.h +++ b/cc/animation/animation_curve.h @@ -78,6 +78,13 @@ class CC_EXPORT TransformAnimationCurve : public AnimationCurve { // Returns true if this animation affects scale. virtual bool AffectsScale() const = 0; + // Returns true if this animation is a translation. + virtual bool IsTranslation() const = 0; + + // Set |max_scale| to the maximum scale along any dimension during this + // animation. Returns false if the maximum scale cannot be computed. + virtual bool MaximumScale(float* max_scale) const = 0; + // Partial Animation implementation. virtual CurveType Type() const OVERRIDE; }; diff --git a/cc/animation/keyframed_animation_curve.cc b/cc/animation/keyframed_animation_curve.cc index 2fce022..4522ca2 100644 --- a/cc/animation/keyframed_animation_curve.cc +++ b/cc/animation/keyframed_animation_curve.cc @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#include <algorithm> + #include "cc/animation/keyframed_animation_curve.h" #include "ui/gfx/animation/tween.h" #include "ui/gfx/box_f.h" @@ -341,6 +343,36 @@ bool KeyframedTransformAnimationCurve::AffectsScale() const { return false; } +bool KeyframedTransformAnimationCurve::IsTranslation() const { + for (size_t i = 0; i < keyframes_.size(); ++i) { + if (!keyframes_[i]->Value().IsTranslation() && + !keyframes_[i]->Value().IsIdentity()) + return false; + } + return true; +} + +bool KeyframedTransformAnimationCurve::MaximumScale(float* max_scale) const { + DCHECK_GE(keyframes_.size(), 2ul); + *max_scale = 0.f; + for (size_t i = 1; i < keyframes_.size(); ++i) { + float min_progress = 0.f; + float max_progress = 1.f; + if (keyframes_[i - 1]->timing_function()) + keyframes_[i - 1]->timing_function()->Range(&min_progress, &max_progress); + + float max_scale_for_segment = 0.f; + if (!keyframes_[i]->Value().MaximumScale(keyframes_[i - 1]->Value(), + min_progress, + max_progress, + &max_scale_for_segment)) + return false; + + *max_scale = std::max(*max_scale, max_scale_for_segment); + } + return true; +} + scoped_ptr<KeyframedFilterAnimationCurve> KeyframedFilterAnimationCurve:: Create() { return make_scoped_ptr(new KeyframedFilterAnimationCurve); diff --git a/cc/animation/keyframed_animation_curve.h b/cc/animation/keyframed_animation_curve.h index ceb900f..ded48c6 100644 --- a/cc/animation/keyframed_animation_curve.h +++ b/cc/animation/keyframed_animation_curve.h @@ -184,6 +184,8 @@ class CC_EXPORT KeyframedTransformAnimationCurve virtual bool AnimatedBoundsForBox(const gfx::BoxF& box, gfx::BoxF* bounds) const OVERRIDE; virtual bool AffectsScale() const OVERRIDE; + virtual bool IsTranslation() const OVERRIDE; + virtual bool MaximumScale(float* max_scale) const OVERRIDE; private: KeyframedTransformAnimationCurve(); diff --git a/cc/animation/keyframed_animation_curve_unittest.cc b/cc/animation/keyframed_animation_curve_unittest.cc index 1fb14966..eceba6f 100644 --- a/cc/animation/keyframed_animation_curve_unittest.cc +++ b/cc/animation/keyframed_animation_curve_unittest.cc @@ -482,5 +482,68 @@ TEST(KeyframedAnimationCurveTest, AffectsScale) { 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 diff --git a/cc/animation/layer_animation_controller.cc b/cc/animation/layer_animation_controller.cc index 12f5355..4c0b8bb 100644 --- a/cc/animation/layer_animation_controller.cc +++ b/cc/animation/layer_animation_controller.cc @@ -452,6 +452,39 @@ bool LayerAnimationController::HasAnimationThatAffectsScale() const { return false; } +bool LayerAnimationController::HasOnlyTranslationTransforms() const { + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->is_finished() || + active_animations_[i]->target_property() != Animation::Transform) + continue; + + const TransformAnimationCurve* transform_animation_curve = + active_animations_[i]->curve()->ToTransformAnimationCurve(); + if (!transform_animation_curve->IsTranslation()) + return false; + } + + return true; +} + +bool LayerAnimationController::MaximumScale(float* max_scale) const { + *max_scale = 0.f; + for (size_t i = 0; i < active_animations_.size(); ++i) { + if (active_animations_[i]->is_finished() || + active_animations_[i]->target_property() != Animation::Transform) + continue; + + const TransformAnimationCurve* transform_animation_curve = + active_animations_[i]->curve()->ToTransformAnimationCurve(); + float animation_scale = 0.f; + if (!transform_animation_curve->MaximumScale(&animation_scale)) + return false; + *max_scale = std::max(*max_scale, animation_scale); + } + + return true; +} + void LayerAnimationController::PushNewAnimationsToImplThread( LayerAnimationController* controller_impl) const { // Any new animations owned by the main thread's controller are cloned and diff --git a/cc/animation/layer_animation_controller.h b/cc/animation/layer_animation_controller.h index 0aba413..c5f0a31 100644 --- a/cc/animation/layer_animation_controller.h +++ b/cc/animation/layer_animation_controller.h @@ -121,6 +121,12 @@ class CC_EXPORT LayerAnimationController bool HasAnimationThatAffectsScale() const; + bool HasOnlyTranslationTransforms() const; + + // Sets |max_scale| to the maximum scale along any dimension during active + // animations. Returns false if the maximum scale cannot be computed. + bool MaximumScale(float* max_scale) const; + protected: friend class base::RefCounted<LayerAnimationController>; diff --git a/cc/animation/layer_animation_controller_unittest.cc b/cc/animation/layer_animation_controller_unittest.cc index 32e5d49..af795b2 100644 --- a/cc/animation/layer_animation_controller_unittest.cc +++ b/cc/animation/layer_animation_controller_unittest.cc @@ -1732,5 +1732,130 @@ TEST(LayerAnimationControllerTest, HasAnimationThatAffectsScale) { EXPECT_FALSE(controller_impl->HasAnimationThatAffectsScale()); } +TEST(LayerAnimationControllerTest, HasOnlyTranslationTransforms) { + scoped_refptr<LayerAnimationController> controller_impl( + LayerAnimationController::Create(0)); + + EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms()); + + controller_impl->AddAnimation(CreateAnimation( + scoped_ptr<AnimationCurve>(new FakeFloatTransition(1.0, 0.f, 1.f)).Pass(), + 1, + Animation::Opacity)); + + // Opacity animations aren't non-translation transforms. + EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms()); + + scoped_ptr<KeyframedTransformAnimationCurve> curve1( + KeyframedTransformAnimationCurve::Create()); + + TransformOperations operations1; + curve1->AddKeyframe(TransformKeyframe::Create( + 0.0, operations1, scoped_ptr<TimingFunction>())); + operations1.AppendTranslate(10.0, 15.0, 0.0); + curve1->AddKeyframe(TransformKeyframe::Create( + 1.0, operations1, scoped_ptr<TimingFunction>())); + + scoped_ptr<Animation> animation(Animation::Create( + curve1.PassAs<AnimationCurve>(), 2, 2, Animation::Transform)); + controller_impl->AddAnimation(animation.Pass()); + + // The only transform animation we've added is a translation. + EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms()); + + scoped_ptr<KeyframedTransformAnimationCurve> curve2( + KeyframedTransformAnimationCurve::Create()); + + TransformOperations operations2; + curve2->AddKeyframe(TransformKeyframe::Create( + 0.0, operations2, scoped_ptr<TimingFunction>())); + operations2.AppendScale(2.0, 3.0, 4.0); + curve2->AddKeyframe(TransformKeyframe::Create( + 1.0, operations2, scoped_ptr<TimingFunction>())); + + animation = Animation::Create( + curve2.PassAs<AnimationCurve>(), 3, 3, Animation::Transform); + controller_impl->AddAnimation(animation.Pass()); + + // A scale animation is not a translation. + EXPECT_FALSE(controller_impl->HasOnlyTranslationTransforms()); + + controller_impl->GetAnimation(3, Animation::Transform) + ->SetRunState(Animation::Finished, 0.0); + + // Only unfinished animations should be considered by + // HasOnlyTranslationTransforms. + EXPECT_TRUE(controller_impl->HasOnlyTranslationTransforms()); +} + +TEST(LayerAnimationControllerTest, MaximumScale) { + scoped_refptr<LayerAnimationController> controller_impl( + LayerAnimationController::Create(0)); + + float max_scale = 0.f; + EXPECT_TRUE(controller_impl->MaximumScale(&max_scale)); + EXPECT_EQ(0.f, max_scale); + + scoped_ptr<KeyframedTransformAnimationCurve> curve1( + KeyframedTransformAnimationCurve::Create()); + + TransformOperations operations1; + curve1->AddKeyframe(TransformKeyframe::Create( + 0.0, operations1, scoped_ptr<TimingFunction>())); + operations1.AppendScale(2.0, 3.0, 4.0); + curve1->AddKeyframe(TransformKeyframe::Create( + 1.0, operations1, scoped_ptr<TimingFunction>())); + + scoped_ptr<Animation> animation(Animation::Create( + curve1.PassAs<AnimationCurve>(), 1, 1, Animation::Transform)); + controller_impl->AddAnimation(animation.Pass()); + + EXPECT_TRUE(controller_impl->MaximumScale(&max_scale)); + EXPECT_EQ(4.f, max_scale); + + scoped_ptr<KeyframedTransformAnimationCurve> curve2( + KeyframedTransformAnimationCurve::Create()); + + TransformOperations operations2; + curve2->AddKeyframe(TransformKeyframe::Create( + 0.0, operations2, scoped_ptr<TimingFunction>())); + operations2.AppendScale(6.0, 5.0, 4.0); + curve2->AddKeyframe(TransformKeyframe::Create( + 1.0, operations2, scoped_ptr<TimingFunction>())); + + animation = Animation::Create( + curve2.PassAs<AnimationCurve>(), 2, 2, Animation::Transform); + controller_impl->AddAnimation(animation.Pass()); + + EXPECT_TRUE(controller_impl->MaximumScale(&max_scale)); + EXPECT_EQ(6.f, max_scale); + + scoped_ptr<KeyframedTransformAnimationCurve> curve3( + KeyframedTransformAnimationCurve::Create()); + + TransformOperations operations3; + curve3->AddKeyframe(TransformKeyframe::Create( + 0.0, operations3, scoped_ptr<TimingFunction>())); + operations3.AppendPerspective(6.0); + curve3->AddKeyframe(TransformKeyframe::Create( + 1.0, operations3, scoped_ptr<TimingFunction>())); + + animation = Animation::Create( + curve3.PassAs<AnimationCurve>(), 3, 3, Animation::Transform); + controller_impl->AddAnimation(animation.Pass()); + + EXPECT_FALSE(controller_impl->MaximumScale(&max_scale)); + + controller_impl->GetAnimation(3, Animation::Transform) + ->SetRunState(Animation::Finished, 0.0); + controller_impl->GetAnimation(2, Animation::Transform) + ->SetRunState(Animation::Finished, 0.0); + + // Only unfinished animations should be considered by + // MaximumScale. + EXPECT_TRUE(controller_impl->MaximumScale(&max_scale)); + EXPECT_EQ(4.f, max_scale); +} + } // namespace } // namespace cc diff --git a/cc/animation/transform_operations.cc b/cc/animation/transform_operations.cc index 5b20436..2d34290 100644 --- a/cc/animation/transform_operations.cc +++ b/cc/animation/transform_operations.cc @@ -6,6 +6,7 @@ #include <algorithm> +#include "ui/gfx/animation/tween.h" #include "ui/gfx/box_f.h" #include "ui/gfx/transform_util.h" #include "ui/gfx/vector3d_f.h" @@ -89,6 +90,89 @@ bool TransformOperations::AffectsScale() const { return false; } +bool TransformOperations::IsTranslation() const { + for (size_t i = 0; i < operations_.size(); ++i) { + switch (operations_[i].type) { + case TransformOperation::TransformOperationIdentity: + case TransformOperation::TransformOperationTranslate: + continue; + case TransformOperation::TransformOperationMatrix: + if (!operations_[i].matrix.IsIdentityOrTranslation()) + return false; + continue; + case TransformOperation::TransformOperationRotate: + case TransformOperation::TransformOperationScale: + case TransformOperation::TransformOperationSkew: + case TransformOperation::TransformOperationPerspective: + return false; + } + } + return true; +} + +bool TransformOperations::MaximumScale(const TransformOperations& from, + SkMScalar min_progress, + SkMScalar max_progress, + float* max_scale) const { + if (!MatchesTypes(from)) + return false; + + gfx::Vector3dF from_scale; + gfx::Vector3dF to_scale; + + if (!from.ScaleComponent(&from_scale) || !ScaleComponent(&to_scale)) + return false; + + gfx::Vector3dF scale_at_min_progress( + std::abs(gfx::Tween::FloatValueBetween( + min_progress, from_scale.x(), to_scale.x())), + std::abs(gfx::Tween::FloatValueBetween( + min_progress, from_scale.y(), to_scale.y())), + std::abs(gfx::Tween::FloatValueBetween( + min_progress, from_scale.z(), to_scale.z()))); + gfx::Vector3dF scale_at_max_progress( + std::abs(gfx::Tween::FloatValueBetween( + max_progress, from_scale.x(), to_scale.x())), + std::abs(gfx::Tween::FloatValueBetween( + max_progress, from_scale.y(), to_scale.y())), + std::abs(gfx::Tween::FloatValueBetween( + max_progress, from_scale.z(), to_scale.z()))); + + gfx::Vector3dF max_scale_3d = scale_at_min_progress; + max_scale_3d.SetToMax(scale_at_max_progress); + *max_scale = + std::max(max_scale_3d.x(), std::max(max_scale_3d.y(), max_scale_3d.z())); + return true; +} + +bool TransformOperations::ScaleComponent(gfx::Vector3dF* scale) const { + *scale = gfx::Vector3dF(1.f, 1.f, 1.f); + bool has_scale_component = false; + for (size_t i = 0; i < operations_.size(); ++i) { + switch (operations_[i].type) { + case TransformOperation::TransformOperationIdentity: + case TransformOperation::TransformOperationTranslate: + continue; + case TransformOperation::TransformOperationMatrix: + if (!operations_[i].matrix.IsIdentityOrTranslation()) + return false; + continue; + case TransformOperation::TransformOperationRotate: + case TransformOperation::TransformOperationSkew: + case TransformOperation::TransformOperationPerspective: + return false; + case TransformOperation::TransformOperationScale: + if (has_scale_component) + return false; + has_scale_component = true; + scale->Scale(operations_[i].scale.x, + operations_[i].scale.y, + operations_[i].scale.z); + } + } + return true; +} + bool TransformOperations::MatchesTypes(const TransformOperations& other) const { if (IsIdentity() || other.IsIdentity()) return true; diff --git a/cc/animation/transform_operations.h b/cc/animation/transform_operations.h index 7d42cea..f086eb1 100644 --- a/cc/animation/transform_operations.h +++ b/cc/animation/transform_operations.h @@ -60,6 +60,17 @@ class CC_EXPORT TransformOperations { // Returns true if these operations affect scale. bool AffectsScale() const; + // Returns true if these operations are only translations. + bool IsTranslation() const; + + // Sets |max_scale| to be the maximum scale in any dimension when calling + // Blend on |from| with progress in the range [min_progress, max_progress]. If + // this maximum scale cannot be computed, returns false. + bool MaximumScale(const TransformOperations& from, + SkMScalar min_progress, + SkMScalar max_progress, + float* max_scale) const; + // Returns true if this operation and its descendants have the same types // as other and its descendants. bool MatchesTypes(const TransformOperations& other) const; @@ -87,6 +98,11 @@ class CC_EXPORT TransformOperations { bool ComputeDecomposedTransform() const; + // If these operations have no more than one scale operation, and if the only + // other operations are translations, sets |scale| to the scale component + // of these operations. Otherwise, returns false. + bool ScaleComponent(gfx::Vector3dF* scale) const; + // For efficiency, we cache the decomposed transform. mutable scoped_ptr<gfx::DecomposedTransform> decomposed_transform_; mutable bool decomposed_transform_dirty_; diff --git a/cc/animation/transform_operations_unittest.cc b/cc/animation/transform_operations_unittest.cc index 8dad032..ce7d121 100644 --- a/cc/animation/transform_operations_unittest.cc +++ b/cc/animation/transform_operations_unittest.cc @@ -1317,5 +1317,193 @@ TEST(TransformOperationTest, AffectsScaleWithMultipleOperations) { EXPECT_TRUE(operations2.AffectsScale()); } +TEST(TransformOperationTest, IsTranslationWithSingleOperation) { + TransformOperations empty_operations; + EXPECT_TRUE(empty_operations.IsTranslation()); + + TransformOperations identity; + identity.AppendIdentity(); + EXPECT_TRUE(identity.IsTranslation()); + + TransformOperations translate; + translate.AppendTranslate(1.f, 2.f, 3.f); + EXPECT_TRUE(translate.IsTranslation()); + + TransformOperations rotate; + rotate.AppendRotate(1.f, 2.f, 3.f, 4.f); + EXPECT_FALSE(rotate.IsTranslation()); + + TransformOperations scale; + scale.AppendScale(1.f, 2.f, 3.f); + EXPECT_FALSE(scale.IsTranslation()); + + TransformOperations skew; + skew.AppendSkew(1.f, 2.f); + EXPECT_FALSE(skew.IsTranslation()); + + TransformOperations perspective; + perspective.AppendPerspective(1.f); + EXPECT_FALSE(perspective.IsTranslation()); + + TransformOperations identity_matrix; + identity_matrix.AppendMatrix(gfx::Transform()); + EXPECT_TRUE(identity_matrix.IsTranslation()); + + TransformOperations translation_matrix; + gfx::Transform translation_transform; + translation_transform.Translate3d(1.f, 2.f, 3.f); + translation_matrix.AppendMatrix(translation_transform); + EXPECT_TRUE(translation_matrix.IsTranslation()); + + TransformOperations scaling_matrix; + gfx::Transform scaling_transform; + scaling_transform.Scale(2.f, 2.f); + scaling_matrix.AppendMatrix(scaling_transform); + EXPECT_FALSE(scaling_matrix.IsTranslation()); +} + +TEST(TransformOperationTest, IsTranslationWithMultipleOperations) { + TransformOperations operations1; + operations1.AppendSkew(1.f, 2.f); + operations1.AppendTranslate(1.f, 2.f, 3.f); + operations1.AppendIdentity(); + EXPECT_FALSE(operations1.IsTranslation()); + + TransformOperations operations2; + operations2.AppendIdentity(); + operations2.AppendTranslate(3.f, 2.f, 1.f); + gfx::Transform translation_transform; + translation_transform.Translate3d(1.f, 2.f, 3.f); + operations2.AppendMatrix(translation_transform); + EXPECT_TRUE(operations2.IsTranslation()); +} + +TEST(TransformOperationTest, MaximumScale) { + TransformOperations operations1; + operations1.AppendScale(3.f, 2.f, 5.f); + TransformOperations operations2; + operations2.AppendScale(6.f, 5.f, 2.f); + + float max_scale = 0.f; + EXPECT_TRUE(operations2.MaximumScale(operations1, 0.f, 1.f, &max_scale)); + // x at progress 1.f + EXPECT_EQ(6.f, max_scale); + + EXPECT_TRUE(operations2.MaximumScale(operations1, -1.f, 1.f, &max_scale)); + // z at progress -1.f + EXPECT_EQ(8.f, max_scale); + + EXPECT_TRUE(operations2.MaximumScale(operations1, 0.f, 2.f, &max_scale)); + // x at progress 2.f + EXPECT_EQ(9.f, max_scale); + + TransformOperations operations3; + operations3.AppendScale(1.f, 4.f, 1.f); + TransformOperations operations4; + + EXPECT_TRUE(operations4.MaximumScale(operations3, 0.f, 1.f, &max_scale)); + // y at progress 0.f + EXPECT_EQ(4.f, max_scale); + + EXPECT_TRUE(operations4.MaximumScale(operations3, -1.f, 1.f, &max_scale)); + // y at progress -1.f + EXPECT_EQ(7.f, max_scale); + + EXPECT_TRUE(operations4.MaximumScale(operations3, 0.f, 2.f, &max_scale)); + // y at progress 0.f + EXPECT_EQ(4.f, max_scale); + + TransformOperations operations5; + operations5.AppendTranslate(1.f, 2.f, 3.f); + operations5.AppendScale(1.f, 1.f, 4.f); + gfx::Transform translation_transform; + translation_transform.Translate3d(1.f, 2.f, 3.f); + operations5.AppendMatrix(translation_transform); + TransformOperations operations6; + operations6.AppendTranslate(2.f, 3.f, 4.f); + operations6.AppendScale(2.f, 5.f, 1.f); + operations6.AppendMatrix(translation_transform); + + EXPECT_TRUE(operations6.MaximumScale(operations5, 0.f, 1.f, &max_scale)); + // y at progress 1.f + EXPECT_EQ(5.f, max_scale); + + EXPECT_TRUE(operations6.MaximumScale(operations5, -1.f, 1.f, &max_scale)); + // z at progress -1.f + EXPECT_EQ(7.f, max_scale); + + EXPECT_TRUE(operations6.MaximumScale(operations5, 0.f, 2.f, &max_scale)); + // y at progress 2.f + EXPECT_EQ(9.f, max_scale); +} + +TEST(TransformOperationTest, MaximumScaleCannotBeComputed) { + TransformOperations operations1; + operations1.AppendScale(2.f, 2.f, 2.f); + TransformOperations operations2; + operations2.AppendTranslate(1.f, 2.f, 3.f); + + float max_scale = 0.f; + + // Non-matching operations. + EXPECT_FALSE(operations2.MaximumScale(operations1, 0.f, 1.f, &max_scale)); + + TransformOperations operations3; + operations3.AppendScale(2.f, 2.f, 2.f); + operations3.AppendTranslate(1.f, 2.f, 3.f); + operations3.AppendScale(3.f, 3.f, 3.f); + TransformOperations operations4; + operations4.AppendScale(4.f, 4.f, 4.f); + operations4.AppendTranslate(2.f, 3.f, 4.f); + operations4.AppendScale(5.f, 5.f, 5.f); + + // More that one scale operation in a sequence. + EXPECT_FALSE(operations4.MaximumScale(operations3, 0.f, 1.f, &max_scale)); + + TransformOperations operations5; + operations5.AppendScale(2.f, 2.f, 2.f); + gfx::Transform scaling_transform; + scaling_transform.Scale(2.f, 2.f); + operations5.AppendMatrix(scaling_transform); + TransformOperations operations6; + operations6.AppendScale(3.f, 3.f, 3.f); + gfx::Transform translation_transform; + translation_transform.Translate3d(1.f, 2.f, 3.f); + operations6.AppendMatrix(translation_transform); + + // Non-translation matrix operation. + EXPECT_FALSE(operations6.MaximumScale(operations5, 0.f, 1.f, &max_scale)); + + TransformOperations operations7; + operations7.AppendScale(2.f, 2.f, 2.f); + operations7.AppendRotate(1.f, 2.f, 3.f, 4.f); + TransformOperations operations8; + operations8.AppendScale(3.f, 3.f, 3.f); + operations8.AppendRotate(3.f, 4.f, 5.f, 6.f); + + // Rotation operation. + EXPECT_FALSE(operations8.MaximumScale(operations7, 0.f, 1.f, &max_scale)); + + TransformOperations operations9; + operations9.AppendScale(2.f, 2.f, 2.f); + operations9.AppendSkew(1.f, 2.f); + TransformOperations operations10; + operations10.AppendScale(3.f, 3.f, 3.f); + operations10.AppendSkew(3.f, 4.f); + + // Skew operation. + EXPECT_FALSE(operations10.MaximumScale(operations9, 0.f, 1.f, &max_scale)); + + TransformOperations operations11; + operations11.AppendScale(2.f, 2.f, 2.f); + operations11.AppendPerspective(1.f); + TransformOperations operations12; + operations12.AppendScale(3.f, 3.f, 3.f); + operations12.AppendPerspective(3.f); + + // Perspective operation. + EXPECT_FALSE(operations12.MaximumScale(operations11, 0.f, 1.f, &max_scale)); +} + } // namespace } // namespace cc diff --git a/cc/test/animation_test_common.cc b/cc/test/animation_test_common.cc index 3dcaf23..b5af1d2 100644 --- a/cc/test/animation_test_common.cc +++ b/cc/test/animation_test_common.cc @@ -170,6 +170,13 @@ bool FakeTransformTransition::AnimatedBoundsForBox(const gfx::BoxF& box, bool FakeTransformTransition::AffectsScale() const { return false; } +bool FakeTransformTransition::IsTranslation() const { return true; } + +bool FakeTransformTransition::MaximumScale(float* max_scale) const { + *max_scale = 1.f; + return true; +} + scoped_ptr<AnimationCurve> FakeTransformTransition::Clone() const { return make_scoped_ptr(new FakeTransformTransition(*this)) .PassAs<AnimationCurve>(); diff --git a/cc/test/animation_test_common.h b/cc/test/animation_test_common.h index 7732c2d9..92da0e4 100644 --- a/cc/test/animation_test_common.h +++ b/cc/test/animation_test_common.h @@ -44,6 +44,8 @@ class FakeTransformTransition : public TransformAnimationCurve { virtual bool AnimatedBoundsForBox(const gfx::BoxF& box, gfx::BoxF* bounds) const OVERRIDE; virtual bool AffectsScale() const OVERRIDE; + virtual bool IsTranslation() const OVERRIDE; + virtual bool MaximumScale(float* max_scale) const OVERRIDE; virtual scoped_ptr<AnimationCurve> Clone() const OVERRIDE; diff --git a/ui/compositor/transform_animation_curve_adapter.cc b/ui/compositor/transform_animation_curve_adapter.cc index d2ae831..e875ca0 100644 --- a/ui/compositor/transform_animation_curve_adapter.cc +++ b/ui/compositor/transform_animation_curve_adapter.cc @@ -66,6 +66,15 @@ bool TransformAnimationCurveAdapter::AffectsScale() const { !target_value_.IsIdentityOrTranslation(); } +bool TransformAnimationCurveAdapter::IsTranslation() const { + return initial_value_.IsIdentityOrTranslation() && + target_value_.IsIdentityOrTranslation(); +} + +bool TransformAnimationCurveAdapter::MaximumScale(float* max_scale) const { + return false; +} + InverseTransformCurveAdapter::InverseTransformCurveAdapter( TransformAnimationCurveAdapter base_curve, gfx::Transform initial_value, @@ -120,4 +129,13 @@ bool InverseTransformCurveAdapter::AffectsScale() const { base_curve_.AffectsScale(); } +bool InverseTransformCurveAdapter::IsTranslation() const { + return initial_value_.IsIdentityOrTranslation() && + base_curve_.IsTranslation(); +} + +bool InverseTransformCurveAdapter::MaximumScale(float* max_scale) const { + return false; +} + } // namespace ui diff --git a/ui/compositor/transform_animation_curve_adapter.h b/ui/compositor/transform_animation_curve_adapter.h index 5c83eb1..c410ac0 100644 --- a/ui/compositor/transform_animation_curve_adapter.h +++ b/ui/compositor/transform_animation_curve_adapter.h @@ -31,6 +31,8 @@ class COMPOSITOR_EXPORT TransformAnimationCurveAdapter virtual bool AnimatedBoundsForBox(const gfx::BoxF& box, gfx::BoxF* bounds) const OVERRIDE; virtual bool AffectsScale() const OVERRIDE; + virtual bool IsTranslation() const OVERRIDE; + virtual bool MaximumScale(float* max_scale) const OVERRIDE; private: gfx::Tween::Type tween_type_; @@ -58,6 +60,8 @@ class COMPOSITOR_EXPORT InverseTransformCurveAdapter virtual bool AnimatedBoundsForBox(const gfx::BoxF& box, gfx::BoxF* bounds) const OVERRIDE; virtual bool AffectsScale() const OVERRIDE; + virtual bool IsTranslation() const OVERRIDE; + virtual bool MaximumScale(float* max_scale) const OVERRIDE; private: TransformAnimationCurveAdapter base_curve_; |