Update {virtual,override,final} to follow C++11 style in chrome/browser/chromeos...
[chromium-blink-merge.git] / cc / animation / keyframed_animation_curve.cc
blobbf65df8f20f00ca694b0f7b604ece794f76fdede
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.
5 #include <algorithm>
7 #include "cc/animation/keyframed_animation_curve.h"
8 #include "cc/base/time_util.h"
9 #include "ui/gfx/animation/tween.h"
10 #include "ui/gfx/geometry/box_f.h"
12 namespace cc {
14 namespace {
16 template <class KeyframeType>
17 void InsertKeyframe(scoped_ptr<KeyframeType> keyframe,
18 ScopedPtrVector<KeyframeType>* keyframes) {
19 // Usually, the keyframes will be added in order, so this loop would be
20 // unnecessary and we should skip it if possible.
21 if (!keyframes->empty() && keyframe->Time() < keyframes->back()->Time()) {
22 for (size_t i = 0; i < keyframes->size(); ++i) {
23 if (keyframe->Time() < keyframes->at(i)->Time()) {
24 keyframes->insert(keyframes->begin() + i, keyframe.Pass());
25 return;
30 keyframes->push_back(keyframe.Pass());
33 template <typename KeyframeType>
34 base::TimeDelta TransformedAnimationTime(
35 const ScopedPtrVector<KeyframeType>& keyframes,
36 const scoped_ptr<TimingFunction>& timing_function,
37 base::TimeDelta time) {
38 if (timing_function) {
39 base::TimeDelta start_time = keyframes.front()->Time();
40 base::TimeDelta duration =
41 keyframes.back()->Time() - keyframes.front()->Time();
42 double progress = TimeUtil::Divide(time - start_time, duration);
44 time = TimeUtil::Scale(duration, timing_function->GetValue(progress)) +
45 start_time;
48 return time;
51 template <typename KeyframeType>
52 size_t GetActiveKeyframe(const ScopedPtrVector<KeyframeType>& keyframes,
53 base::TimeDelta time) {
54 DCHECK_GE(keyframes.size(), 2ul);
55 size_t i = 0;
56 for (; i < keyframes.size() - 2; ++i) { // Last keyframe is never active.
57 if (time < keyframes[i + 1]->Time())
58 break;
61 return i;
64 template <typename KeyframeType>
65 double TransformedKeyframeProgress(
66 const ScopedPtrVector<KeyframeType>& keyframes,
67 base::TimeDelta time,
68 size_t i) {
69 double progress =
70 TimeUtil::Divide(time - keyframes[i]->Time(),
71 keyframes[i + 1]->Time() - keyframes[i]->Time());
73 if (keyframes[i]->timing_function()) {
74 progress = keyframes[i]->timing_function()->GetValue(progress);
77 return progress;
80 } // namespace
82 Keyframe::Keyframe(base::TimeDelta time,
83 scoped_ptr<TimingFunction> timing_function)
84 : time_(time), timing_function_(timing_function.Pass()) {
87 Keyframe::~Keyframe() {}
89 base::TimeDelta Keyframe::Time() const {
90 return time_;
93 scoped_ptr<ColorKeyframe> ColorKeyframe::Create(
94 base::TimeDelta time,
95 SkColor value,
96 scoped_ptr<TimingFunction> timing_function) {
97 return make_scoped_ptr(
98 new ColorKeyframe(time, value, timing_function.Pass()));
101 ColorKeyframe::ColorKeyframe(base::TimeDelta time,
102 SkColor value,
103 scoped_ptr<TimingFunction> timing_function)
104 : Keyframe(time, timing_function.Pass()), value_(value) {
107 ColorKeyframe::~ColorKeyframe() {}
109 SkColor ColorKeyframe::Value() const { return value_; }
111 scoped_ptr<ColorKeyframe> ColorKeyframe::Clone() const {
112 scoped_ptr<TimingFunction> func;
113 if (timing_function())
114 func = timing_function()->Clone();
115 return ColorKeyframe::Create(Time(), Value(), func.Pass());
118 scoped_ptr<FloatKeyframe> FloatKeyframe::Create(
119 base::TimeDelta time,
120 float value,
121 scoped_ptr<TimingFunction> timing_function) {
122 return make_scoped_ptr(
123 new FloatKeyframe(time, value, timing_function.Pass()));
126 FloatKeyframe::FloatKeyframe(base::TimeDelta time,
127 float value,
128 scoped_ptr<TimingFunction> timing_function)
129 : Keyframe(time, timing_function.Pass()), value_(value) {
132 FloatKeyframe::~FloatKeyframe() {}
134 float FloatKeyframe::Value() const {
135 return value_;
138 scoped_ptr<FloatKeyframe> FloatKeyframe::Clone() const {
139 scoped_ptr<TimingFunction> func;
140 if (timing_function())
141 func = timing_function()->Clone();
142 return FloatKeyframe::Create(Time(), Value(), func.Pass());
145 scoped_ptr<TransformKeyframe> TransformKeyframe::Create(
146 base::TimeDelta time,
147 const TransformOperations& value,
148 scoped_ptr<TimingFunction> timing_function) {
149 return make_scoped_ptr(
150 new TransformKeyframe(time, value, timing_function.Pass()));
153 TransformKeyframe::TransformKeyframe(base::TimeDelta time,
154 const TransformOperations& value,
155 scoped_ptr<TimingFunction> timing_function)
156 : Keyframe(time, timing_function.Pass()), value_(value) {
159 TransformKeyframe::~TransformKeyframe() {}
161 const TransformOperations& TransformKeyframe::Value() const {
162 return value_;
165 scoped_ptr<TransformKeyframe> TransformKeyframe::Clone() const {
166 scoped_ptr<TimingFunction> func;
167 if (timing_function())
168 func = timing_function()->Clone();
169 return TransformKeyframe::Create(Time(), Value(), func.Pass());
172 scoped_ptr<FilterKeyframe> FilterKeyframe::Create(
173 base::TimeDelta time,
174 const FilterOperations& value,
175 scoped_ptr<TimingFunction> timing_function) {
176 return make_scoped_ptr(
177 new FilterKeyframe(time, value, timing_function.Pass()));
180 FilterKeyframe::FilterKeyframe(base::TimeDelta time,
181 const FilterOperations& value,
182 scoped_ptr<TimingFunction> timing_function)
183 : Keyframe(time, timing_function.Pass()), value_(value) {
186 FilterKeyframe::~FilterKeyframe() {}
188 const FilterOperations& FilterKeyframe::Value() const {
189 return value_;
192 scoped_ptr<FilterKeyframe> FilterKeyframe::Clone() const {
193 scoped_ptr<TimingFunction> func;
194 if (timing_function())
195 func = timing_function()->Clone();
196 return FilterKeyframe::Create(Time(), Value(), func.Pass());
199 scoped_ptr<KeyframedColorAnimationCurve> KeyframedColorAnimationCurve::
200 Create() {
201 return make_scoped_ptr(new KeyframedColorAnimationCurve);
204 KeyframedColorAnimationCurve::KeyframedColorAnimationCurve() {}
206 KeyframedColorAnimationCurve::~KeyframedColorAnimationCurve() {}
208 void KeyframedColorAnimationCurve::AddKeyframe(
209 scoped_ptr<ColorKeyframe> keyframe) {
210 InsertKeyframe(keyframe.Pass(), &keyframes_);
213 base::TimeDelta KeyframedColorAnimationCurve::Duration() const {
214 return keyframes_.back()->Time() - keyframes_.front()->Time();
217 scoped_ptr<AnimationCurve> KeyframedColorAnimationCurve::Clone() const {
218 scoped_ptr<KeyframedColorAnimationCurve> to_return =
219 KeyframedColorAnimationCurve::Create();
220 for (size_t i = 0; i < keyframes_.size(); ++i)
221 to_return->AddKeyframe(keyframes_[i]->Clone());
223 if (timing_function_)
224 to_return->SetTimingFunction(timing_function_->Clone());
226 return to_return.Pass();
229 SkColor KeyframedColorAnimationCurve::GetValue(base::TimeDelta t) const {
230 if (t <= keyframes_.front()->Time())
231 return keyframes_.front()->Value();
233 if (t >= keyframes_.back()->Time())
234 return keyframes_.back()->Value();
236 t = TransformedAnimationTime(keyframes_, timing_function_, t);
237 size_t i = GetActiveKeyframe(keyframes_, t);
238 double progress = TransformedKeyframeProgress(keyframes_, t, i);
240 return gfx::Tween::ColorValueBetween(
241 progress, keyframes_[i]->Value(), keyframes_[i + 1]->Value());
244 // KeyframedFloatAnimationCurve
246 scoped_ptr<KeyframedFloatAnimationCurve> KeyframedFloatAnimationCurve::
247 Create() {
248 return make_scoped_ptr(new KeyframedFloatAnimationCurve);
251 KeyframedFloatAnimationCurve::KeyframedFloatAnimationCurve() {}
253 KeyframedFloatAnimationCurve::~KeyframedFloatAnimationCurve() {}
255 void KeyframedFloatAnimationCurve::AddKeyframe(
256 scoped_ptr<FloatKeyframe> keyframe) {
257 InsertKeyframe(keyframe.Pass(), &keyframes_);
260 base::TimeDelta KeyframedFloatAnimationCurve::Duration() const {
261 return keyframes_.back()->Time() - keyframes_.front()->Time();
264 scoped_ptr<AnimationCurve> KeyframedFloatAnimationCurve::Clone() const {
265 scoped_ptr<KeyframedFloatAnimationCurve> to_return =
266 KeyframedFloatAnimationCurve::Create();
267 for (size_t i = 0; i < keyframes_.size(); ++i)
268 to_return->AddKeyframe(keyframes_[i]->Clone());
270 if (timing_function_)
271 to_return->SetTimingFunction(timing_function_->Clone());
273 return to_return.Pass();
276 float KeyframedFloatAnimationCurve::GetValue(base::TimeDelta t) const {
277 if (t <= keyframes_.front()->Time())
278 return keyframes_.front()->Value();
280 if (t >= keyframes_.back()->Time())
281 return keyframes_.back()->Value();
283 t = TransformedAnimationTime(keyframes_, timing_function_, t);
284 size_t i = GetActiveKeyframe(keyframes_, t);
285 double progress = TransformedKeyframeProgress(keyframes_, t, i);
287 return keyframes_[i]->Value() +
288 (keyframes_[i+1]->Value() - keyframes_[i]->Value()) * progress;
291 scoped_ptr<KeyframedTransformAnimationCurve> KeyframedTransformAnimationCurve::
292 Create() {
293 return make_scoped_ptr(new KeyframedTransformAnimationCurve);
296 KeyframedTransformAnimationCurve::KeyframedTransformAnimationCurve() {}
298 KeyframedTransformAnimationCurve::~KeyframedTransformAnimationCurve() {}
300 void KeyframedTransformAnimationCurve::AddKeyframe(
301 scoped_ptr<TransformKeyframe> keyframe) {
302 InsertKeyframe(keyframe.Pass(), &keyframes_);
305 base::TimeDelta KeyframedTransformAnimationCurve::Duration() const {
306 return keyframes_.back()->Time() - keyframes_.front()->Time();
309 scoped_ptr<AnimationCurve> KeyframedTransformAnimationCurve::Clone() const {
310 scoped_ptr<KeyframedTransformAnimationCurve> to_return =
311 KeyframedTransformAnimationCurve::Create();
312 for (size_t i = 0; i < keyframes_.size(); ++i)
313 to_return->AddKeyframe(keyframes_[i]->Clone());
315 if (timing_function_)
316 to_return->SetTimingFunction(timing_function_->Clone());
318 return to_return.Pass();
321 gfx::Transform KeyframedTransformAnimationCurve::GetValue(
322 base::TimeDelta t) const {
323 if (t <= keyframes_.front()->Time())
324 return keyframes_.front()->Value().Apply();
326 if (t >= keyframes_.back()->Time())
327 return keyframes_.back()->Value().Apply();
329 t = TransformedAnimationTime(keyframes_, timing_function_, t);
330 size_t i = GetActiveKeyframe(keyframes_, t);
331 double progress = TransformedKeyframeProgress(keyframes_, t, i);
333 return keyframes_[i + 1]->Value().Blend(keyframes_[i]->Value(), progress);
336 bool KeyframedTransformAnimationCurve::AnimatedBoundsForBox(
337 const gfx::BoxF& box,
338 gfx::BoxF* bounds) const {
339 DCHECK_GE(keyframes_.size(), 2ul);
340 *bounds = gfx::BoxF();
341 for (size_t i = 0; i < keyframes_.size() - 1; ++i) {
342 gfx::BoxF bounds_for_step;
343 float min_progress = 0.0;
344 float max_progress = 1.0;
345 if (keyframes_[i]->timing_function())
346 keyframes_[i]->timing_function()->Range(&min_progress, &max_progress);
347 if (!keyframes_[i+1]->Value().BlendedBoundsForBox(box,
348 keyframes_[i]->Value(),
349 min_progress,
350 max_progress,
351 &bounds_for_step))
352 return false;
353 bounds->Union(bounds_for_step);
355 return true;
358 bool KeyframedTransformAnimationCurve::AffectsScale() const {
359 for (size_t i = 0; i < keyframes_.size(); ++i) {
360 if (keyframes_[i]->Value().AffectsScale())
361 return true;
363 return false;
366 bool KeyframedTransformAnimationCurve::PreservesAxisAlignment() const {
367 for (size_t i = 0; i < keyframes_.size(); ++i) {
368 if (!keyframes_[i]->Value().PreservesAxisAlignment())
369 return false;
371 return true;
374 bool KeyframedTransformAnimationCurve::IsTranslation() const {
375 for (size_t i = 0; i < keyframes_.size(); ++i) {
376 if (!keyframes_[i]->Value().IsTranslation() &&
377 !keyframes_[i]->Value().IsIdentity())
378 return false;
380 return true;
383 bool KeyframedTransformAnimationCurve::MaximumTargetScale(
384 bool forward_direction,
385 float* max_scale) const {
386 DCHECK_GE(keyframes_.size(), 2ul);
387 *max_scale = 0.f;
389 // If |forward_direction| is true, then skip the first frame, otherwise
390 // skip the last frame, since that is the original position in the animation.
391 size_t start = 1;
392 size_t end = keyframes_.size();
393 if (!forward_direction) {
394 --start;
395 --end;
398 for (size_t i = start; i < end; ++i) {
399 gfx::Vector3dF target_scale_for_segment;
400 if (!keyframes_[i]->Value().ScaleComponent(&target_scale_for_segment))
401 return false;
402 float max_scale_for_segment =
403 fmax(std::abs(target_scale_for_segment.x()),
404 fmax(std::abs(target_scale_for_segment.y()),
405 std::abs(target_scale_for_segment.z())));
406 *max_scale = fmax(*max_scale, max_scale_for_segment);
408 return true;
411 scoped_ptr<KeyframedFilterAnimationCurve> KeyframedFilterAnimationCurve::
412 Create() {
413 return make_scoped_ptr(new KeyframedFilterAnimationCurve);
416 KeyframedFilterAnimationCurve::KeyframedFilterAnimationCurve() {}
418 KeyframedFilterAnimationCurve::~KeyframedFilterAnimationCurve() {}
420 void KeyframedFilterAnimationCurve::AddKeyframe(
421 scoped_ptr<FilterKeyframe> keyframe) {
422 InsertKeyframe(keyframe.Pass(), &keyframes_);
425 base::TimeDelta KeyframedFilterAnimationCurve::Duration() const {
426 return keyframes_.back()->Time() - keyframes_.front()->Time();
429 scoped_ptr<AnimationCurve> KeyframedFilterAnimationCurve::Clone() const {
430 scoped_ptr<KeyframedFilterAnimationCurve> to_return =
431 KeyframedFilterAnimationCurve::Create();
432 for (size_t i = 0; i < keyframes_.size(); ++i)
433 to_return->AddKeyframe(keyframes_[i]->Clone());
435 if (timing_function_)
436 to_return->SetTimingFunction(timing_function_->Clone());
438 return to_return.Pass();
441 FilterOperations KeyframedFilterAnimationCurve::GetValue(
442 base::TimeDelta t) const {
443 if (t <= keyframes_.front()->Time())
444 return keyframes_.front()->Value();
446 if (t >= keyframes_.back()->Time())
447 return keyframes_.back()->Value();
449 t = TransformedAnimationTime(keyframes_, timing_function_, t);
450 size_t i = GetActiveKeyframe(keyframes_, t);
451 double progress = TransformedKeyframeProgress(keyframes_, t, i);
453 return keyframes_[i + 1]->Value().Blend(keyframes_[i]->Value(), progress);
456 bool KeyframedFilterAnimationCurve::HasFilterThatMovesPixels() const {
457 for (size_t i = 0; i < keyframes_.size(); ++i) {
458 if (keyframes_[i]->Value().HasFilterThatMovesPixels()) {
459 return true;
462 return false;
465 } // namespace cc