Index: cc/timing_function.cc |
diff --git a/cc/timing_function.cc b/cc/timing_function.cc |
index 6588d36d9649c51aa57bce41f1832389a638ced5..7aef57ebb9cab0d00c2385f54bb1600ec1666eb8 100644 |
--- a/cc/timing_function.cc |
+++ b/cc/timing_function.cc |
@@ -5,10 +5,79 @@ |
#include "config.h" |
#include "cc/timing_function.h" |
+#include "third_party/skia/include/core/SkMath.h" |
+// TODO(danakj) These methods come from SkInterpolator.cpp. When such a method |
+// is available in the public Skia API, we should switch to using that. |
+// http://crbug.com/159735 |
namespace { |
-const double epsilon = 1e-6; |
-} // namespace |
+ |
+// Dot14 has 14 bits for decimal places, and the remainder for whole numbers. |
+typedef int Dot14; |
+#define DOT14_ONE (1 << 14) |
+#define DOT14_HALF (1 << 13) |
+ |
+#define Dot14ToFloat(x) ((x) / 16384.f) |
+ |
+static inline Dot14 Dot14Mul(Dot14 a, Dot14 b) |
+{ |
+ return (a * b + DOT14_HALF) >> 14; |
+} |
+ |
+static inline Dot14 EvalCubic(Dot14 t, Dot14 A, Dot14 B, Dot14 C) |
+{ |
+ return Dot14Mul(Dot14Mul(Dot14Mul(C, t) + B, t) + A, t); |
+} |
+ |
+static inline Dot14 PinAndConvert(SkScalar x) |
+{ |
+ if (x <= 0) |
+ return 0; |
+ if (x >= SK_Scalar1) |
+ return DOT14_ONE; |
+ return SkScalarToFixed(x) >> 2; |
+} |
+ |
+SkScalar SkUnitCubicInterp(SkScalar bx, SkScalar by, SkScalar cx, SkScalar cy, SkScalar value) |
+{ |
+ Dot14 x = PinAndConvert(value); |
+ |
+ if (x == 0) return 0; |
+ if (x == DOT14_ONE) return SK_Scalar1; |
+ |
+ Dot14 b = PinAndConvert(bx); |
+ Dot14 c = PinAndConvert(cx); |
+ |
+ // Now compute our coefficients from the control points. |
+ // t -> 3b |
+ // t^2 -> 3c - 6b |
+ // t^3 -> 3b - 3c + 1 |
+ Dot14 A = 3 * b; |
+ Dot14 B = 3 * (c - 2 * b); |
+ Dot14 C = 3 * (b - c) + DOT14_ONE; |
+ |
+ // Now search for a t value given x. |
+ Dot14 t = DOT14_HALF; |
+ Dot14 dt = DOT14_HALF; |
+ for (int i = 0; i < 13; i++) { |
+ dt >>= 1; |
+ Dot14 guess = EvalCubic(t, A, B, C); |
+ if (x < guess) |
+ t -= dt; |
+ else |
+ t += dt; |
+ } |
+ |
+ // Now we have t, so compute the coefficient for Y and evaluate. |
+ b = PinAndConvert(by); |
+ c = PinAndConvert(cy); |
+ A = 3 * b; |
+ B = 3 * (c - 2 * b); |
+ C = 3 * (b - c) + DOT14_ONE; |
+ return SkFixedToScalar(EvalCubic(t, A, B, C) << 2); |
+} |
+ |
+} // anonymous namespace |
namespace cc { |
@@ -31,7 +100,10 @@ scoped_ptr<CubicBezierTimingFunction> CubicBezierTimingFunction::create(double x |
} |
CubicBezierTimingFunction::CubicBezierTimingFunction(double x1, double y1, double x2, double y2) |
- : m_curve(x1, y1, x2, y2) |
+ : m_x1(SkDoubleToScalar(x1)) |
+ , m_y1(SkDoubleToScalar(y1)) |
+ , m_x2(SkDoubleToScalar(x2)) |
+ , m_y2(SkDoubleToScalar(y2)) |
{ |
} |
@@ -41,8 +113,8 @@ CubicBezierTimingFunction::~CubicBezierTimingFunction() |
float CubicBezierTimingFunction::getValue(double x) const |
{ |
- UnitBezier temp(m_curve); |
- return static_cast<float>(temp.solve(x, epsilon)); |
+ SkScalar value = SkUnitCubicInterp(m_x1, m_y1, m_x2, m_y2, x); |
+ return SkScalarToFloat(value); |
} |
scoped_ptr<AnimationCurve> CubicBezierTimingFunction::clone() const |