// 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 "ui/gfx/animation/tween.h" #include "ui/gfx/box_f.h" namespace cc { namespace { template <class Keyframe> void InsertKeyframe(scoped_ptr<Keyframe> keyframe, ScopedPtrVector<Keyframe>& keyframes) { // Usually, the keyframes will be added in order, so this loop would be // unnecessary and we should skip it if possible. if (!keyframes.empty() && keyframe->Time() < keyframes.back()->Time()) { for (size_t i = 0; i < keyframes.size(); ++i) { if (keyframe->Time() < keyframes[i]->Time()) { keyframes.insert(keyframes.begin() + i, keyframe.Pass()); return; } } } keyframes.push_back(keyframe.Pass()); } template <class Keyframes> float GetProgress(double t, size_t i, const Keyframes& keyframes) { float progress = static_cast<float>((t - keyframes[i]->Time()) / (keyframes[i + 1]->Time() - keyframes[i]->Time())); if (keyframes[i]->timing_function()) progress = keyframes[i]->timing_function()->GetValue(progress); return progress; } scoped_ptr<TimingFunction> CloneTimingFunction( const TimingFunction* timing_function) { DCHECK(timing_function); scoped_ptr<AnimationCurve> curve(timing_function->Clone()); return scoped_ptr<TimingFunction>( static_cast<TimingFunction*>(curve.release())); } } // namespace Keyframe::Keyframe(double time, scoped_ptr<TimingFunction> timing_function) : time_(time), timing_function_(timing_function.Pass()) {} Keyframe::~Keyframe() {} double Keyframe::Time() const { return time_; } scoped_ptr<ColorKeyframe> ColorKeyframe::Create( double time, SkColor value, scoped_ptr<TimingFunction> timing_function) { return make_scoped_ptr( new ColorKeyframe(time, value, timing_function.Pass())); } ColorKeyframe::ColorKeyframe(double time, SkColor value, scoped_ptr<TimingFunction> timing_function) : Keyframe(time, timing_function.Pass()), value_(value) {} ColorKeyframe::~ColorKeyframe() {} SkColor ColorKeyframe::Value() const { return value_; } scoped_ptr<ColorKeyframe> ColorKeyframe::Clone() const { scoped_ptr<TimingFunction> func; if (timing_function()) func = CloneTimingFunction(timing_function()); return ColorKeyframe::Create(Time(), Value(), func.Pass()); } scoped_ptr<FloatKeyframe> FloatKeyframe::Create( double time, float value, scoped_ptr<TimingFunction> timing_function) { return make_scoped_ptr( new FloatKeyframe(time, value, timing_function.Pass())); } FloatKeyframe::FloatKeyframe(double time, float value, scoped_ptr<TimingFunction> timing_function) : Keyframe(time, timing_function.Pass()), value_(value) {} FloatKeyframe::~FloatKeyframe() {} float FloatKeyframe::Value() const { return value_; } scoped_ptr<FloatKeyframe> FloatKeyframe::Clone() const { scoped_ptr<TimingFunction> func; if (timing_function()) func = CloneTimingFunction(timing_function()); return FloatKeyframe::Create(Time(), Value(), func.Pass()); } scoped_ptr<TransformKeyframe> TransformKeyframe::Create( double time, const TransformOperations& value, scoped_ptr<TimingFunction> timing_function) { return make_scoped_ptr( new TransformKeyframe(time, value, timing_function.Pass())); } TransformKeyframe::TransformKeyframe(double time, const TransformOperations& value, scoped_ptr<TimingFunction> timing_function) : Keyframe(time, timing_function.Pass()), value_(value) {} TransformKeyframe::~TransformKeyframe() {} const TransformOperations& TransformKeyframe::Value() const { return value_; } scoped_ptr<TransformKeyframe> TransformKeyframe::Clone() const { scoped_ptr<TimingFunction> func; if (timing_function()) func = CloneTimingFunction(timing_function()); return TransformKeyframe::Create(Time(), Value(), func.Pass()); } scoped_ptr<FilterKeyframe> FilterKeyframe::Create( double time, const FilterOperations& value, scoped_ptr<TimingFunction> timing_function) { return make_scoped_ptr( new FilterKeyframe(time, value, timing_function.Pass())); } FilterKeyframe::FilterKeyframe(double time, const FilterOperations& value, scoped_ptr<TimingFunction> timing_function) : Keyframe(time, timing_function.Pass()), value_(value) {} FilterKeyframe::~FilterKeyframe() {} const FilterOperations& FilterKeyframe::Value() const { return value_; } scoped_ptr<FilterKeyframe> FilterKeyframe::Clone() const { scoped_ptr<TimingFunction> func; if (timing_function()) func = CloneTimingFunction(timing_function()); return FilterKeyframe::Create(Time(), Value(), func.Pass()); } scoped_ptr<KeyframedColorAnimationCurve> KeyframedColorAnimationCurve:: Create() { return make_scoped_ptr(new KeyframedColorAnimationCurve); } KeyframedColorAnimationCurve::KeyframedColorAnimationCurve() {} KeyframedColorAnimationCurve::~KeyframedColorAnimationCurve() {} void KeyframedColorAnimationCurve::AddKeyframe( scoped_ptr<ColorKeyframe> keyframe) { InsertKeyframe(keyframe.Pass(), keyframes_); } double KeyframedColorAnimationCurve::Duration() const { return keyframes_.back()->Time() - keyframes_.front()->Time(); } scoped_ptr<AnimationCurve> KeyframedColorAnimationCurve::Clone() const { scoped_ptr<KeyframedColorAnimationCurve> to_return( KeyframedColorAnimationCurve::Create()); for (size_t i = 0; i < keyframes_.size(); ++i) to_return->AddKeyframe(keyframes_[i]->Clone()); return to_return.PassAs<AnimationCurve>(); } SkColor KeyframedColorAnimationCurve::GetValue(double t) const { if (t <= keyframes_.front()->Time()) return keyframes_.front()->Value(); if (t >= keyframes_.back()->Time()) return keyframes_.back()->Value(); size_t i = 0; for (; i < keyframes_.size() - 1; ++i) { if (t < keyframes_[i + 1]->Time()) break; } float progress = GetProgress(t, i, keyframes_); return gfx::Tween::ColorValueBetween( progress, keyframes_[i]->Value(), keyframes_[i + 1]->Value()); } // KeyframedFloatAnimationCurve scoped_ptr<KeyframedFloatAnimationCurve> KeyframedFloatAnimationCurve:: Create() { return make_scoped_ptr(new KeyframedFloatAnimationCurve); } KeyframedFloatAnimationCurve::KeyframedFloatAnimationCurve() {} KeyframedFloatAnimationCurve::~KeyframedFloatAnimationCurve() {} void KeyframedFloatAnimationCurve::AddKeyframe( scoped_ptr<FloatKeyframe> keyframe) { InsertKeyframe(keyframe.Pass(), keyframes_); } double KeyframedFloatAnimationCurve::Duration() const { return keyframes_.back()->Time() - keyframes_.front()->Time(); } scoped_ptr<AnimationCurve> KeyframedFloatAnimationCurve::Clone() const { scoped_ptr<KeyframedFloatAnimationCurve> to_return( KeyframedFloatAnimationCurve::Create()); for (size_t i = 0; i < keyframes_.size(); ++i) to_return->AddKeyframe(keyframes_[i]->Clone()); return to_return.PassAs<AnimationCurve>(); } float KeyframedFloatAnimationCurve::GetValue(double t) const { if (t <= keyframes_.front()->Time()) return keyframes_.front()->Value(); if (t >= keyframes_.back()->Time()) return keyframes_.back()->Value(); size_t i = 0; for (; i < keyframes_.size() - 1; ++i) { if (t < keyframes_[i+1]->Time()) break; } float progress = GetProgress(t, i, keyframes_); return keyframes_[i]->Value() + (keyframes_[i+1]->Value() - keyframes_[i]->Value()) * progress; } scoped_ptr<KeyframedTransformAnimationCurve> KeyframedTransformAnimationCurve:: Create() { return make_scoped_ptr(new KeyframedTransformAnimationCurve); } KeyframedTransformAnimationCurve::KeyframedTransformAnimationCurve() {} KeyframedTransformAnimationCurve::~KeyframedTransformAnimationCurve() {} void KeyframedTransformAnimationCurve::AddKeyframe( scoped_ptr<TransformKeyframe> keyframe) { InsertKeyframe(keyframe.Pass(), keyframes_); } double KeyframedTransformAnimationCurve::Duration() const { return keyframes_.back()->Time() - keyframes_.front()->Time(); } scoped_ptr<AnimationCurve> KeyframedTransformAnimationCurve::Clone() const { scoped_ptr<KeyframedTransformAnimationCurve> to_return( KeyframedTransformAnimationCurve::Create()); for (size_t i = 0; i < keyframes_.size(); ++i) to_return->AddKeyframe(keyframes_[i]->Clone()); return to_return.PassAs<AnimationCurve>(); } // Assumes that (*keyframes).front()->Time() < t < (*keyframes).back()-Time(). template<typename ValueType, typename KeyframeType> static ValueType GetCurveValue(const ScopedPtrVector<KeyframeType>* keyframes, double t) { size_t i = 0; for (; i < keyframes->size() - 1; ++i) { if (t < (*keyframes)[i+1]->Time()) break; } double progress = (t - (*keyframes)[i]->Time()) / ((*keyframes)[i+1]->Time() - (*keyframes)[i]->Time()); if ((*keyframes)[i]->timing_function()) progress = (*keyframes)[i]->timing_function()->GetValue(progress); return (*keyframes)[i+1]->Value().Blend((*keyframes)[i]->Value(), progress); } gfx::Transform KeyframedTransformAnimationCurve::GetValue(double t) const { if (t <= keyframes_.front()->Time()) return keyframes_.front()->Value().Apply(); if (t >= keyframes_.back()->Time()) return keyframes_.back()->Value().Apply(); return GetCurveValue<gfx::Transform, TransformKeyframe>(&keyframes_, t); } bool KeyframedTransformAnimationCurve::AnimatedBoundsForBox( const gfx::BoxF& box, gfx::BoxF* bounds) const { DCHECK_GE(keyframes_.size(), 2ul); *bounds = gfx::BoxF(); for (size_t i = 0; i < keyframes_.size() - 1; ++i) { gfx::BoxF bounds_for_step; float min_progress = 0.0; float max_progress = 1.0; if (keyframes_[i]->timing_function()) keyframes_[i]->timing_function()->Range(&min_progress, &max_progress); if (!keyframes_[i+1]->Value().BlendedBoundsForBox(box, keyframes_[i]->Value(), min_progress, max_progress, &bounds_for_step)) return false; bounds->Union(bounds_for_step); } return true; } scoped_ptr<KeyframedFilterAnimationCurve> KeyframedFilterAnimationCurve:: Create() { return make_scoped_ptr(new KeyframedFilterAnimationCurve); } KeyframedFilterAnimationCurve::KeyframedFilterAnimationCurve() {} KeyframedFilterAnimationCurve::~KeyframedFilterAnimationCurve() {} void KeyframedFilterAnimationCurve::AddKeyframe( scoped_ptr<FilterKeyframe> keyframe) { InsertKeyframe(keyframe.Pass(), keyframes_); } double KeyframedFilterAnimationCurve::Duration() const { return keyframes_.back()->Time() - keyframes_.front()->Time(); } scoped_ptr<AnimationCurve> KeyframedFilterAnimationCurve::Clone() const { scoped_ptr<KeyframedFilterAnimationCurve> to_return( KeyframedFilterAnimationCurve::Create()); for (size_t i = 0; i < keyframes_.size(); ++i) to_return->AddKeyframe(keyframes_[i]->Clone()); return to_return.PassAs<AnimationCurve>(); } FilterOperations KeyframedFilterAnimationCurve::GetValue(double t) const { if (t <= keyframes_.front()->Time()) return keyframes_.front()->Value(); if (t >= keyframes_.back()->Time()) return keyframes_.back()->Value(); return GetCurveValue<FilterOperations, FilterKeyframe>(&keyframes_, t); } } // namespace cc