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 "cc/timing_function.h"
7 #include "third_party/skia/include/core/SkMath.h"
9 // TODO(danakj) These methods come from SkInterpolator.cpp. When such a method
10 // is available in the public Skia API, we should switch to using that.
11 // http://crbug.com/159735
14 // Dot14 has 14 bits for decimal places, and the remainder for whole numbers.
16 #define DOT14_ONE (1 << 14)
17 #define DOT14_HALF (1 << 13)
19 #define Dot14ToFloat(x) ((x) / 16384.f)
21 static inline Dot14
Dot14Mul(Dot14 a
, Dot14 b
) {
22 return (a
* b
+ DOT14_HALF
) >> 14;
25 static inline Dot14
EvalCubic(Dot14 t
, Dot14 A
, Dot14 B
, Dot14 C
) {
26 return Dot14Mul(Dot14Mul(Dot14Mul(C
, t
) + B
, t
) + A
, t
);
29 static inline Dot14
PinAndConvert(SkScalar x
) {
34 return SkScalarToFixed(x
) >> 2;
37 SkScalar
SkUnitCubicInterp(SkScalar bx
, SkScalar by
,
38 SkScalar cx
, SkScalar cy
,
40 Dot14 x
= PinAndConvert(value
);
43 if (x
== DOT14_ONE
) return SK_Scalar1
;
45 Dot14 b
= PinAndConvert(bx
);
46 Dot14 c
= PinAndConvert(cx
);
48 // Now compute our coefficients from the control points.
53 Dot14 B
= 3 * (c
- 2 * b
);
54 Dot14 C
= 3 * (b
- c
) + DOT14_ONE
;
56 // Now search for a t value given x.
58 Dot14 dt
= DOT14_HALF
;
59 for (int i
= 0; i
< 13; i
++) {
61 Dot14 guess
= EvalCubic(t
, A
, B
, C
);
68 // Now we have t, so compute the coefficient for Y and evaluate.
69 b
= PinAndConvert(by
);
70 c
= PinAndConvert(cy
);
73 C
= 3 * (b
- c
) + DOT14_ONE
;
74 return SkFixedToScalar(EvalCubic(t
, A
, B
, C
) << 2);
81 TimingFunction::TimingFunction() {
84 TimingFunction::~TimingFunction() {
87 double TimingFunction::duration() const {
91 scoped_ptr
<CubicBezierTimingFunction
> CubicBezierTimingFunction::create(
92 double x1
, double y1
, double x2
, double y2
) {
93 return make_scoped_ptr(new CubicBezierTimingFunction(x1
, y1
, x2
, y2
));
96 CubicBezierTimingFunction::CubicBezierTimingFunction(double x1
, double y1
,
98 : x1_(SkDoubleToScalar(x1
)),
99 y1_(SkDoubleToScalar(y1
)),
100 x2_(SkDoubleToScalar(x2
)),
101 y2_(SkDoubleToScalar(y2
)) {
104 CubicBezierTimingFunction::~CubicBezierTimingFunction() {
107 float CubicBezierTimingFunction::getValue(double x
) const {
108 SkScalar value
= SkUnitCubicInterp(x1_
, y1_
, x2_
, y2_
, x
);
109 return SkScalarToFloat(value
);
112 scoped_ptr
<AnimationCurve
> CubicBezierTimingFunction::clone() const {
113 return make_scoped_ptr(
114 new CubicBezierTimingFunction(*this)).PassAs
<AnimationCurve
>();
117 // These numbers come from http://www.w3.org/TR/css3-transitions/#transition-timing-function_tag.
118 scoped_ptr
<TimingFunction
> EaseTimingFunction::create() {
119 return CubicBezierTimingFunction::create(
120 0.25, 0.1, 0.25, 1).PassAs
<TimingFunction
>();
123 scoped_ptr
<TimingFunction
> EaseInTimingFunction::create() {
124 return CubicBezierTimingFunction::create(
125 0.42, 0, 1.0, 1).PassAs
<TimingFunction
>();
128 scoped_ptr
<TimingFunction
> EaseOutTimingFunction::create() {
129 return CubicBezierTimingFunction::create(
130 0, 0, 0.58, 1).PassAs
<TimingFunction
>();
133 scoped_ptr
<TimingFunction
> EaseInOutTimingFunction::create() {
134 return CubicBezierTimingFunction::create(
135 0.42, 0, 0.58, 1).PassAs
<TimingFunction
>();