1 #include "SkCubicInterval.h" 2 3 static SkScalar eval_cubic(SkScalar c1, SkScalar c2, SkScalar c3, 4 SkScalar t) { 5 return SkScalarMul(SkScalarMul(SkScalarMul(c3, t) + c2, t) + c1, t); 6 } 7 8 static SkScalar find_cubic_t(SkScalar c1, SkScalar c2, SkScalar c3, 9 SkScalar targetX) { 10 SkScalar minT = 0; 11 SkScalar maxT = SK_Scalar1; 12 SkScalar t; 13 14 for (;;) { 15 t = SkScalarAve(minT, maxT); 16 SkScalar x = eval_cubic(c1, c2, c3, t); 17 if (SkScalarNearlyZero(x - targetX)) { 18 break; 19 } 20 // subdivide the range and try again 21 if (x < targetX) { 22 minT = t; 23 } else { 24 maxT = t; 25 } 26 } 27 return t; 28 } 29 30 /* 31 a(1-t)^3 + 3bt(1-t)^2 + 3ct^2(1-t) + dt^3 32 a: [0, 0] 33 d: [1, 1] 34 35 3bt - 6bt^2 + 3bt^3 + 3ct^2 - 3ct^3 + t^3 36 C1 = t^1: 3b 37 C2 = t^2: 3c - 6b 38 C3 = t^3: 3b - 3c + 1 39 40 ((C3*t + C2)*t + C1)*t 41 */ 42 SkScalar SkEvalCubicInterval(SkScalar x1, SkScalar y1, 43 SkScalar x2, SkScalar y2, 44 SkScalar unitX) { 45 x1 = SkScalarPin(x1, 0, SK_Scalar1); 46 x2 = SkScalarPin(x2, 0, SK_Scalar1); 47 unitX = SkScalarPin(unitX, 0, SK_Scalar1); 48 49 // First compute our coefficients in X 50 x1 *= 3; 51 x2 *= 3; 52 53 // now search for t given unitX 54 SkScalar t = find_cubic_t(x1, x2 - 2*x1, x1 - x2 + SK_Scalar1, unitX); 55 56 // now evaluate the cubic in Y 57 y1 *= 3; 58 y2 *= 3; 59 return eval_cubic(y1, y2 - 2*y1, y1 - y2 + SK_Scalar1, t); 60 } 61 62