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 "base/logging.h"
8 #include "cc/animation/timing_function.h"
14 static const double BEZIER_EPSILON
= 1e-7;
15 static const int MAX_STEPS
= 30;
17 static double eval_bezier(double x1
, double x2
, double t
) {
18 const double x1_times_3
= 3.0 * x1
;
19 const double x2_times_3
= 3.0 * x2
;
20 const double h3
= x1_times_3
;
21 const double h1
= x1_times_3
- x2_times_3
+ 1.0;
22 const double h2
= x2_times_3
- 6.0 * x1
;
23 return t
* (t
* (t
* h1
+ h2
) + h3
);
26 static double bezier_interp(double x1
,
36 x1
= std::min(std::max(x1
, 0.0), 1.0);
37 x2
= std::min(std::max(x2
, 0.0), 1.0);
38 x
= std::min(std::max(x
, 0.0), 1.0);
40 // Step 1. Find the t corresponding to the given x. I.e., we want t such that
41 // eval_bezier(x1, x2, t) = x. There is a unique solution if x1 and x2 lie
44 // We're just going to do bisection for now (for simplicity), but we could
45 // easily do some newton steps if this turns out to be a bottleneck.
48 for (int i
= 0; i
< MAX_STEPS
; ++i
, step
*= 0.5) {
49 const double error
= eval_bezier(x1
, x2
, t
) - x
;
50 if (fabs(error
) < BEZIER_EPSILON
)
52 t
+= error
> 0.0 ? -step
: step
;
55 // We should have terminated the above loop because we got close to x, not
56 // because we exceeded MAX_STEPS. Do a DCHECK here to confirm.
57 DCHECK_GT(BEZIER_EPSILON
, fabs(eval_bezier(x1
, x2
, t
) - x
));
59 // Step 2. Return the interpolated y values at the t we computed above.
60 return eval_bezier(y1
, y2
, t
);
65 TimingFunction::TimingFunction() {}
67 TimingFunction::~TimingFunction() {}
69 double TimingFunction::Duration() const {
73 scoped_ptr
<CubicBezierTimingFunction
> CubicBezierTimingFunction::Create(
74 double x1
, double y1
, double x2
, double y2
) {
75 return make_scoped_ptr(new CubicBezierTimingFunction(x1
, y1
, x2
, y2
));
78 CubicBezierTimingFunction::CubicBezierTimingFunction(double x1
,
82 : x1_(x1
), y1_(y1
), x2_(x2
), y2_(y2
) {}
84 CubicBezierTimingFunction::~CubicBezierTimingFunction() {}
86 float CubicBezierTimingFunction::GetValue(double x
) const {
87 return static_cast<float>(bezier_interp(x1_
, y1_
, x2_
, y2_
, x
));
90 scoped_ptr
<AnimationCurve
> CubicBezierTimingFunction::Clone() const {
91 return make_scoped_ptr(
92 new CubicBezierTimingFunction(*this)).PassAs
<AnimationCurve
>();
95 // These numbers come from
96 // http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag.
97 scoped_ptr
<TimingFunction
> EaseTimingFunction::Create() {
98 return CubicBezierTimingFunction::Create(
99 0.25, 0.1, 0.25, 1.0).PassAs
<TimingFunction
>();
102 scoped_ptr
<TimingFunction
> EaseInTimingFunction::Create() {
103 return CubicBezierTimingFunction::Create(
104 0.42, 0.0, 1.0, 1.0).PassAs
<TimingFunction
>();
107 scoped_ptr
<TimingFunction
> EaseOutTimingFunction::Create() {
108 return CubicBezierTimingFunction::Create(
109 0.0, 0.0, 0.58, 1.0).PassAs
<TimingFunction
>();
112 scoped_ptr
<TimingFunction
> EaseInOutTimingFunction::Create() {
113 return CubicBezierTimingFunction::Create(
114 0.42, 0.0, 0.58, 1).PassAs
<TimingFunction
>();