1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
7 #include "cc/animation/keyframed_animation_curve.h"
8 #include "ui/gfx/animation/tween.h"
9 #include "ui/gfx/box_f.h"
15 template <class Keyframe
>
16 void InsertKeyframe(scoped_ptr
<Keyframe
> keyframe
,
17 ScopedPtrVector
<Keyframe
>& keyframes
) {
18 // Usually, the keyframes will be added in order, so this loop would be
19 // unnecessary and we should skip it if possible.
20 if (!keyframes
.empty() && keyframe
->Time() < keyframes
.back()->Time()) {
21 for (size_t i
= 0; i
< keyframes
.size(); ++i
) {
22 if (keyframe
->Time() < keyframes
[i
]->Time()) {
23 keyframes
.insert(keyframes
.begin() + i
, keyframe
.Pass());
29 keyframes
.push_back(keyframe
.Pass());
32 template <class Keyframes
>
33 float GetProgress(double t
, size_t i
, const Keyframes
& keyframes
) {
35 static_cast<float>((t
- keyframes
[i
]->Time()) /
36 (keyframes
[i
+ 1]->Time() - keyframes
[i
]->Time()));
38 if (keyframes
[i
]->timing_function())
39 progress
= keyframes
[i
]->timing_function()->GetValue(progress
);
43 scoped_ptr
<TimingFunction
> CloneTimingFunction(
44 const TimingFunction
* timing_function
) {
45 DCHECK(timing_function
);
46 scoped_ptr
<AnimationCurve
> curve(timing_function
->Clone());
47 return scoped_ptr
<TimingFunction
>(
48 static_cast<TimingFunction
*>(curve
.release()));
53 Keyframe::Keyframe(double time
, scoped_ptr
<TimingFunction
> timing_function
)
55 timing_function_(timing_function
.Pass()) {}
57 Keyframe::~Keyframe() {}
59 double Keyframe::Time() const {
63 scoped_ptr
<ColorKeyframe
> ColorKeyframe::Create(
66 scoped_ptr
<TimingFunction
> timing_function
) {
67 return make_scoped_ptr(
68 new ColorKeyframe(time
, value
, timing_function
.Pass()));
71 ColorKeyframe::ColorKeyframe(double time
,
73 scoped_ptr
<TimingFunction
> timing_function
)
74 : Keyframe(time
, timing_function
.Pass()),
77 ColorKeyframe::~ColorKeyframe() {}
79 SkColor
ColorKeyframe::Value() const { return value_
; }
81 scoped_ptr
<ColorKeyframe
> ColorKeyframe::Clone() const {
82 scoped_ptr
<TimingFunction
> func
;
83 if (timing_function())
84 func
= CloneTimingFunction(timing_function());
85 return ColorKeyframe::Create(Time(), Value(), func
.Pass());
88 scoped_ptr
<FloatKeyframe
> FloatKeyframe::Create(
91 scoped_ptr
<TimingFunction
> timing_function
) {
92 return make_scoped_ptr(
93 new FloatKeyframe(time
, value
, timing_function
.Pass()));
96 FloatKeyframe::FloatKeyframe(double time
,
98 scoped_ptr
<TimingFunction
> timing_function
)
99 : Keyframe(time
, timing_function
.Pass()),
102 FloatKeyframe::~FloatKeyframe() {}
104 float FloatKeyframe::Value() const {
108 scoped_ptr
<FloatKeyframe
> FloatKeyframe::Clone() const {
109 scoped_ptr
<TimingFunction
> func
;
110 if (timing_function())
111 func
= CloneTimingFunction(timing_function());
112 return FloatKeyframe::Create(Time(), Value(), func
.Pass());
115 scoped_ptr
<TransformKeyframe
> TransformKeyframe::Create(
117 const TransformOperations
& value
,
118 scoped_ptr
<TimingFunction
> timing_function
) {
119 return make_scoped_ptr(
120 new TransformKeyframe(time
, value
, timing_function
.Pass()));
123 TransformKeyframe::TransformKeyframe(double time
,
124 const TransformOperations
& value
,
125 scoped_ptr
<TimingFunction
> timing_function
)
126 : Keyframe(time
, timing_function
.Pass()),
129 TransformKeyframe::~TransformKeyframe() {}
131 const TransformOperations
& TransformKeyframe::Value() const {
135 scoped_ptr
<TransformKeyframe
> TransformKeyframe::Clone() const {
136 scoped_ptr
<TimingFunction
> func
;
137 if (timing_function())
138 func
= CloneTimingFunction(timing_function());
139 return TransformKeyframe::Create(Time(), Value(), func
.Pass());
142 scoped_ptr
<FilterKeyframe
> FilterKeyframe::Create(
144 const FilterOperations
& value
,
145 scoped_ptr
<TimingFunction
> timing_function
) {
146 return make_scoped_ptr(
147 new FilterKeyframe(time
, value
, timing_function
.Pass()));
150 FilterKeyframe::FilterKeyframe(double time
,
151 const FilterOperations
& value
,
152 scoped_ptr
<TimingFunction
> timing_function
)
153 : Keyframe(time
, timing_function
.Pass()),
156 FilterKeyframe::~FilterKeyframe() {}
158 const FilterOperations
& FilterKeyframe::Value() const {
162 scoped_ptr
<FilterKeyframe
> FilterKeyframe::Clone() const {
163 scoped_ptr
<TimingFunction
> func
;
164 if (timing_function())
165 func
= CloneTimingFunction(timing_function());
166 return FilterKeyframe::Create(Time(), Value(), func
.Pass());
169 scoped_ptr
<KeyframedColorAnimationCurve
> KeyframedColorAnimationCurve::
171 return make_scoped_ptr(new KeyframedColorAnimationCurve
);
174 KeyframedColorAnimationCurve::KeyframedColorAnimationCurve() {}
176 KeyframedColorAnimationCurve::~KeyframedColorAnimationCurve() {}
178 void KeyframedColorAnimationCurve::AddKeyframe(
179 scoped_ptr
<ColorKeyframe
> keyframe
) {
180 InsertKeyframe(keyframe
.Pass(), keyframes_
);
183 double KeyframedColorAnimationCurve::Duration() const {
184 return keyframes_
.back()->Time() - keyframes_
.front()->Time();
187 scoped_ptr
<AnimationCurve
> KeyframedColorAnimationCurve::Clone() const {
188 scoped_ptr
<KeyframedColorAnimationCurve
> to_return(
189 KeyframedColorAnimationCurve::Create());
190 for (size_t i
= 0; i
< keyframes_
.size(); ++i
)
191 to_return
->AddKeyframe(keyframes_
[i
]->Clone());
192 return to_return
.PassAs
<AnimationCurve
>();
195 SkColor
KeyframedColorAnimationCurve::GetValue(double t
) const {
196 if (t
<= keyframes_
.front()->Time())
197 return keyframes_
.front()->Value();
199 if (t
>= keyframes_
.back()->Time())
200 return keyframes_
.back()->Value();
203 for (; i
< keyframes_
.size() - 1; ++i
) {
204 if (t
< keyframes_
[i
+ 1]->Time())
208 float progress
= GetProgress(t
, i
, keyframes_
);
210 return gfx::Tween::ColorValueBetween(
211 progress
, keyframes_
[i
]->Value(), keyframes_
[i
+ 1]->Value());
214 // KeyframedFloatAnimationCurve
216 scoped_ptr
<KeyframedFloatAnimationCurve
> KeyframedFloatAnimationCurve::
218 return make_scoped_ptr(new KeyframedFloatAnimationCurve
);
221 KeyframedFloatAnimationCurve::KeyframedFloatAnimationCurve() {}
223 KeyframedFloatAnimationCurve::~KeyframedFloatAnimationCurve() {}
225 void KeyframedFloatAnimationCurve::AddKeyframe(
226 scoped_ptr
<FloatKeyframe
> keyframe
) {
227 InsertKeyframe(keyframe
.Pass(), keyframes_
);
230 double KeyframedFloatAnimationCurve::Duration() const {
231 return keyframes_
.back()->Time() - keyframes_
.front()->Time();
234 scoped_ptr
<AnimationCurve
> KeyframedFloatAnimationCurve::Clone() const {
235 scoped_ptr
<KeyframedFloatAnimationCurve
> to_return(
236 KeyframedFloatAnimationCurve::Create());
237 for (size_t i
= 0; i
< keyframes_
.size(); ++i
)
238 to_return
->AddKeyframe(keyframes_
[i
]->Clone());
239 return to_return
.PassAs
<AnimationCurve
>();
242 float KeyframedFloatAnimationCurve::GetValue(double t
) const {
243 if (t
<= keyframes_
.front()->Time())
244 return keyframes_
.front()->Value();
246 if (t
>= keyframes_
.back()->Time())
247 return keyframes_
.back()->Value();
250 for (; i
< keyframes_
.size() - 1; ++i
) {
251 if (t
< keyframes_
[i
+1]->Time())
255 float progress
= GetProgress(t
, i
, keyframes_
);
257 return keyframes_
[i
]->Value() +
258 (keyframes_
[i
+1]->Value() - keyframes_
[i
]->Value()) * progress
;
261 scoped_ptr
<KeyframedTransformAnimationCurve
> KeyframedTransformAnimationCurve::
263 return make_scoped_ptr(new KeyframedTransformAnimationCurve
);
266 KeyframedTransformAnimationCurve::KeyframedTransformAnimationCurve() {}
268 KeyframedTransformAnimationCurve::~KeyframedTransformAnimationCurve() {}
270 void KeyframedTransformAnimationCurve::AddKeyframe(
271 scoped_ptr
<TransformKeyframe
> keyframe
) {
272 InsertKeyframe(keyframe
.Pass(), keyframes_
);
275 double KeyframedTransformAnimationCurve::Duration() const {
276 return keyframes_
.back()->Time() - keyframes_
.front()->Time();
279 scoped_ptr
<AnimationCurve
> KeyframedTransformAnimationCurve::Clone() const {
280 scoped_ptr
<KeyframedTransformAnimationCurve
> to_return(
281 KeyframedTransformAnimationCurve::Create());
282 for (size_t i
= 0; i
< keyframes_
.size(); ++i
)
283 to_return
->AddKeyframe(keyframes_
[i
]->Clone());
284 return to_return
.PassAs
<AnimationCurve
>();
287 // Assumes that (*keyframes).front()->Time() < t < (*keyframes).back()-Time().
288 template<typename ValueType
, typename KeyframeType
>
289 static ValueType
GetCurveValue(const ScopedPtrVector
<KeyframeType
>* keyframes
,
292 for (; i
< keyframes
->size() - 1; ++i
) {
293 if (t
< (*keyframes
)[i
+1]->Time())
297 double progress
= (t
- (*keyframes
)[i
]->Time()) /
298 ((*keyframes
)[i
+1]->Time() - (*keyframes
)[i
]->Time());
300 if ((*keyframes
)[i
]->timing_function())
301 progress
= (*keyframes
)[i
]->timing_function()->GetValue(progress
);
303 return (*keyframes
)[i
+1]->Value().Blend((*keyframes
)[i
]->Value(), progress
);
306 gfx::Transform
KeyframedTransformAnimationCurve::GetValue(double t
) const {
307 if (t
<= keyframes_
.front()->Time())
308 return keyframes_
.front()->Value().Apply();
310 if (t
>= keyframes_
.back()->Time())
311 return keyframes_
.back()->Value().Apply();
313 return GetCurveValue
<gfx::Transform
, TransformKeyframe
>(&keyframes_
, t
);
316 bool KeyframedTransformAnimationCurve::AnimatedBoundsForBox(
317 const gfx::BoxF
& box
,
318 gfx::BoxF
* bounds
) const {
319 DCHECK_GE(keyframes_
.size(), 2ul);
320 *bounds
= gfx::BoxF();
321 for (size_t i
= 0; i
< keyframes_
.size() - 1; ++i
) {
322 gfx::BoxF bounds_for_step
;
323 float min_progress
= 0.0;
324 float max_progress
= 1.0;
325 if (keyframes_
[i
]->timing_function())
326 keyframes_
[i
]->timing_function()->Range(&min_progress
, &max_progress
);
327 if (!keyframes_
[i
+1]->Value().BlendedBoundsForBox(box
,
328 keyframes_
[i
]->Value(),
333 bounds
->Union(bounds_for_step
);
338 bool KeyframedTransformAnimationCurve::AffectsScale() const {
339 for (size_t i
= 0; i
< keyframes_
.size(); ++i
) {
340 if (keyframes_
[i
]->Value().AffectsScale())
346 bool KeyframedTransformAnimationCurve::IsTranslation() const {
347 for (size_t i
= 0; i
< keyframes_
.size(); ++i
) {
348 if (!keyframes_
[i
]->Value().IsTranslation() &&
349 !keyframes_
[i
]->Value().IsIdentity())
355 bool KeyframedTransformAnimationCurve::MaximumScale(float* max_scale
) const {
356 DCHECK_GE(keyframes_
.size(), 2ul);
358 for (size_t i
= 1; i
< keyframes_
.size(); ++i
) {
359 float min_progress
= 0.f
;
360 float max_progress
= 1.f
;
361 if (keyframes_
[i
- 1]->timing_function())
362 keyframes_
[i
- 1]->timing_function()->Range(&min_progress
, &max_progress
);
364 float max_scale_for_segment
= 0.f
;
365 if (!keyframes_
[i
]->Value().MaximumScale(keyframes_
[i
- 1]->Value(),
368 &max_scale_for_segment
))
371 *max_scale
= std::max(*max_scale
, max_scale_for_segment
);
376 scoped_ptr
<KeyframedFilterAnimationCurve
> KeyframedFilterAnimationCurve::
378 return make_scoped_ptr(new KeyframedFilterAnimationCurve
);
381 KeyframedFilterAnimationCurve::KeyframedFilterAnimationCurve() {}
383 KeyframedFilterAnimationCurve::~KeyframedFilterAnimationCurve() {}
385 void KeyframedFilterAnimationCurve::AddKeyframe(
386 scoped_ptr
<FilterKeyframe
> keyframe
) {
387 InsertKeyframe(keyframe
.Pass(), keyframes_
);
390 double KeyframedFilterAnimationCurve::Duration() const {
391 return keyframes_
.back()->Time() - keyframes_
.front()->Time();
394 scoped_ptr
<AnimationCurve
> KeyframedFilterAnimationCurve::Clone() const {
395 scoped_ptr
<KeyframedFilterAnimationCurve
> to_return(
396 KeyframedFilterAnimationCurve::Create());
397 for (size_t i
= 0; i
< keyframes_
.size(); ++i
)
398 to_return
->AddKeyframe(keyframes_
[i
]->Clone());
399 return to_return
.PassAs
<AnimationCurve
>();
402 FilterOperations
KeyframedFilterAnimationCurve::GetValue(double t
) const {
403 if (t
<= keyframes_
.front()->Time())
404 return keyframes_
.front()->Value();
406 if (t
>= keyframes_
.back()->Time())
407 return keyframes_
.back()->Value();
409 return GetCurveValue
<FilterOperations
, FilterKeyframe
>(&keyframes_
, t
);
412 bool KeyframedFilterAnimationCurve::HasFilterThatMovesPixels() const {
413 for (size_t i
= 0; i
< keyframes_
.size(); ++i
) {
414 if (keyframes_
[i
]->Value().HasFilterThatMovesPixels()) {