1 /*
2  * Copyright 2006 The Android Open Source Project
3  *
4  * Use of this source code is governed by a BSD-style license that can be
5  * found in the LICENSE file.
6  */
7 
8 #include "SkGeometry.h"
9 #include "SkMatrix.h"
10 #include "SkNx.h"
11 
12 #if 0
13 static Sk2s from_point(const SkPoint& point) {
14     return Sk2s::Load(&point.fX);
15 }
16 
17 static SkPoint to_point(const Sk2s& x) {
18     SkPoint point;
19     x.store(&point.fX);
20     return point;
21 }
22 #endif
23 
to_vector(const Sk2s & x)24 static SkVector to_vector(const Sk2s& x) {
25     SkVector vector;
26     x.store(&vector.fX);
27     return vector;
28 }
29 
30 /** If defined, this makes eval_quad and eval_cubic do more setup (sometimes
31     involving integer multiplies by 2 or 3, but fewer calls to SkScalarMul.
32     May also introduce overflow of fixed when we compute our setup.
33 */
34 //    #define DIRECT_EVAL_OF_POLYNOMIALS
35 
36 ////////////////////////////////////////////////////////////////////////
37 
is_not_monotonic(SkScalar a,SkScalar b,SkScalar c)38 static int is_not_monotonic(SkScalar a, SkScalar b, SkScalar c) {
39     SkScalar ab = a - b;
40     SkScalar bc = b - c;
41     if (ab < 0) {
42         bc = -bc;
43     }
44     return ab == 0 || bc < 0;
45 }
46 
47 ////////////////////////////////////////////////////////////////////////
48 
is_unit_interval(SkScalar x)49 static bool is_unit_interval(SkScalar x) {
50     return x > 0 && x < SK_Scalar1;
51 }
52 
valid_unit_divide(SkScalar numer,SkScalar denom,SkScalar * ratio)53 static int valid_unit_divide(SkScalar numer, SkScalar denom, SkScalar* ratio) {
54     SkASSERT(ratio);
55 
56     if (numer < 0) {
57         numer = -numer;
58         denom = -denom;
59     }
60 
61     if (denom == 0 || numer == 0 || numer >= denom) {
62         return 0;
63     }
64 
65     SkScalar r = numer / denom;
66     if (SkScalarIsNaN(r)) {
67         return 0;
68     }
69     SkASSERTF(r >= 0 && r < SK_Scalar1, "numer %f, denom %f, r %f", numer, denom, r);
70     if (r == 0) { // catch underflow if numer <<<< denom
71         return 0;
72     }
73     *ratio = r;
74     return 1;
75 }
76 
77 /** From Numerical Recipes in C.
78 
79     Q = -1/2 (B + sign(B) sqrt[B*B - 4*A*C])
80     x1 = Q / A
81     x2 = C / Q
82 */
SkFindUnitQuadRoots(SkScalar A,SkScalar B,SkScalar C,SkScalar roots[2])83 int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2]) {
84     SkASSERT(roots);
85 
86     if (A == 0) {
87         return valid_unit_divide(-C, B, roots);
88     }
89 
90     SkScalar* r = roots;
91 
92     SkScalar R = B*B - 4*A*C;
93     if (R < 0 || SkScalarIsNaN(R)) {  // complex roots
94         return 0;
95     }
96     R = SkScalarSqrt(R);
97 
98     SkScalar Q = (B < 0) ? -(B-R)/2 : -(B+R)/2;
99     r += valid_unit_divide(Q, A, r);
100     r += valid_unit_divide(C, Q, r);
101     if (r - roots == 2) {
102         if (roots[0] > roots[1])
103             SkTSwap<SkScalar>(roots[0], roots[1]);
104         else if (roots[0] == roots[1])  // nearly-equal?
105             r -= 1; // skip the double root
106     }
107     return (int)(r - roots);
108 }
109 
110 ///////////////////////////////////////////////////////////////////////////////
111 ///////////////////////////////////////////////////////////////////////////////
112 
quad_poly_eval(const Sk2s & A,const Sk2s & B,const Sk2s & C,const Sk2s & t)113 static Sk2s quad_poly_eval(const Sk2s& A, const Sk2s& B, const Sk2s& C, const Sk2s& t) {
114     return (A * t + B) * t + C;
115 }
116 
eval_quad(const SkScalar src[],SkScalar t)117 static SkScalar eval_quad(const SkScalar src[], SkScalar t) {
118     SkASSERT(src);
119     SkASSERT(t >= 0 && t <= SK_Scalar1);
120 
121 #ifdef DIRECT_EVAL_OF_POLYNOMIALS
122     SkScalar    C = src[0];
123     SkScalar    A = src[4] - 2 * src[2] + C;
124     SkScalar    B = 2 * (src[2] - C);
125     return SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C);
126 #else
127     SkScalar    ab = SkScalarInterp(src[0], src[2], t);
128     SkScalar    bc = SkScalarInterp(src[2], src[4], t);
129     return SkScalarInterp(ab, bc, t);
130 #endif
131 }
132 
eval_quad_derivative(const SkScalar src[],SkScalar t)133 static SkScalar eval_quad_derivative(const SkScalar src[], SkScalar t) {
134     SkScalar A = src[4] - 2 * src[2] + src[0];
135     SkScalar B = src[2] - src[0];
136 
137     return 2 * SkScalarMulAdd(A, t, B);
138 }
139 
SkQuadToCoeff(const SkPoint pts[3],SkPoint coeff[3])140 void SkQuadToCoeff(const SkPoint pts[3], SkPoint coeff[3]) {
141     Sk2s p0 = from_point(pts[0]);
142     Sk2s p1 = from_point(pts[1]);
143     Sk2s p2 = from_point(pts[2]);
144 
145     Sk2s p1minus2 = p1 - p0;
146 
147     coeff[0] = to_point(p2 - p1 - p1 + p0);     // A * t^2
148     coeff[1] = to_point(p1minus2 + p1minus2);   // B * t
149     coeff[2] = pts[0];                          // C
150 }
151 
SkEvalQuadAt(const SkPoint src[3],SkScalar t,SkPoint * pt,SkVector * tangent)152 void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint* pt, SkVector* tangent) {
153     SkASSERT(src);
154     SkASSERT(t >= 0 && t <= SK_Scalar1);
155 
156     if (pt) {
157         pt->set(eval_quad(&src[0].fX, t), eval_quad(&src[0].fY, t));
158     }
159     if (tangent) {
160         tangent->set(eval_quad_derivative(&src[0].fX, t),
161                      eval_quad_derivative(&src[0].fY, t));
162     }
163 }
164 
SkEvalQuadAt(const SkPoint src[3],SkScalar t)165 SkPoint SkEvalQuadAt(const SkPoint src[3], SkScalar t) {
166     SkASSERT(src);
167     SkASSERT(t >= 0 && t <= SK_Scalar1);
168 
169     const Sk2s t2(t);
170 
171     Sk2s P0 = from_point(src[0]);
172     Sk2s P1 = from_point(src[1]);
173     Sk2s P2 = from_point(src[2]);
174 
175     Sk2s B = P1 - P0;
176     Sk2s A = P2 - P1 - B;
177 
178     return to_point((A * t2 + B+B) * t2 + P0);
179 }
180 
SkEvalQuadTangentAt(const SkPoint src[3],SkScalar t)181 SkVector SkEvalQuadTangentAt(const SkPoint src[3], SkScalar t) {
182     SkASSERT(src);
183     SkASSERT(t >= 0 && t <= SK_Scalar1);
184 
185     Sk2s P0 = from_point(src[0]);
186     Sk2s P1 = from_point(src[1]);
187     Sk2s P2 = from_point(src[2]);
188 
189     Sk2s B = P1 - P0;
190     Sk2s A = P2 - P1 - B;
191     Sk2s T = A * Sk2s(t) + B;
192 
193     return to_vector(T + T);
194 }
195 
interp(const Sk2s & v0,const Sk2s & v1,const Sk2s & t)196 static inline Sk2s interp(const Sk2s& v0, const Sk2s& v1, const Sk2s& t) {
197     return v0 + (v1 - v0) * t;
198 }
199 
SkChopQuadAt(const SkPoint src[3],SkPoint dst[5],SkScalar t)200 void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t) {
201     SkASSERT(t > 0 && t < SK_Scalar1);
202 
203     Sk2s p0 = from_point(src[0]);
204     Sk2s p1 = from_point(src[1]);
205     Sk2s p2 = from_point(src[2]);
206     Sk2s tt(t);
207 
208     Sk2s p01 = interp(p0, p1, tt);
209     Sk2s p12 = interp(p1, p2, tt);
210 
211     dst[0] = to_point(p0);
212     dst[1] = to_point(p01);
213     dst[2] = to_point(interp(p01, p12, tt));
214     dst[3] = to_point(p12);
215     dst[4] = to_point(p2);
216 }
217 
SkChopQuadAtHalf(const SkPoint src[3],SkPoint dst[5])218 void SkChopQuadAtHalf(const SkPoint src[3], SkPoint dst[5]) {
219     SkChopQuadAt(src, dst, 0.5f); return;
220 }
221 
222 /** Quad'(t) = At + B, where
223     A = 2(a - 2b + c)
224     B = 2(b - a)
225     Solve for t, only if it fits between 0 < t < 1
226 */
SkFindQuadExtrema(SkScalar a,SkScalar b,SkScalar c,SkScalar tValue[1])227 int SkFindQuadExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar tValue[1]) {
228     /*  At + B == 0
229         t = -B / A
230     */
231     return valid_unit_divide(a - b, a - b - b + c, tValue);
232 }
233 
flatten_double_quad_extrema(SkScalar coords[14])234 static inline void flatten_double_quad_extrema(SkScalar coords[14]) {
235     coords[2] = coords[6] = coords[4];
236 }
237 
238 /*  Returns 0 for 1 quad, and 1 for two quads, either way the answer is
239  stored in dst[]. Guarantees that the 1/2 quads will be monotonic.
240  */
SkChopQuadAtYExtrema(const SkPoint src[3],SkPoint dst[5])241 int SkChopQuadAtYExtrema(const SkPoint src[3], SkPoint dst[5]) {
242     SkASSERT(src);
243     SkASSERT(dst);
244 
245     SkScalar a = src[0].fY;
246     SkScalar b = src[1].fY;
247     SkScalar c = src[2].fY;
248 
249     if (is_not_monotonic(a, b, c)) {
250         SkScalar    tValue;
251         if (valid_unit_divide(a - b, a - b - b + c, &tValue)) {
252             SkChopQuadAt(src, dst, tValue);
253             flatten_double_quad_extrema(&dst[0].fY);
254             return 1;
255         }
256         // if we get here, we need to force dst to be monotonic, even though
257         // we couldn't compute a unit_divide value (probably underflow).
258         b = SkScalarAbs(a - b) < SkScalarAbs(b - c) ? a : c;
259     }
260     dst[0].set(src[0].fX, a);
261     dst[1].set(src[1].fX, b);
262     dst[2].set(src[2].fX, c);
263     return 0;
264 }
265 
266 /*  Returns 0 for 1 quad, and 1 for two quads, either way the answer is
267     stored in dst[]. Guarantees that the 1/2 quads will be monotonic.
268  */
SkChopQuadAtXExtrema(const SkPoint src[3],SkPoint dst[5])269 int SkChopQuadAtXExtrema(const SkPoint src[3], SkPoint dst[5]) {
270     SkASSERT(src);
271     SkASSERT(dst);
272 
273     SkScalar a = src[0].fX;
274     SkScalar b = src[1].fX;
275     SkScalar c = src[2].fX;
276 
277     if (is_not_monotonic(a, b, c)) {
278         SkScalar tValue;
279         if (valid_unit_divide(a - b, a - b - b + c, &tValue)) {
280             SkChopQuadAt(src, dst, tValue);
281             flatten_double_quad_extrema(&dst[0].fX);
282             return 1;
283         }
284         // if we get here, we need to force dst to be monotonic, even though
285         // we couldn't compute a unit_divide value (probably underflow).
286         b = SkScalarAbs(a - b) < SkScalarAbs(b - c) ? a : c;
287     }
288     dst[0].set(a, src[0].fY);
289     dst[1].set(b, src[1].fY);
290     dst[2].set(c, src[2].fY);
291     return 0;
292 }
293 
294 //  F(t)    = a (1 - t) ^ 2 + 2 b t (1 - t) + c t ^ 2
295 //  F'(t)   = 2 (b - a) + 2 (a - 2b + c) t
296 //  F''(t)  = 2 (a - 2b + c)
297 //
298 //  A = 2 (b - a)
299 //  B = 2 (a - 2b + c)
300 //
301 //  Maximum curvature for a quadratic means solving
302 //  Fx' Fx'' + Fy' Fy'' = 0
303 //
304 //  t = - (Ax Bx + Ay By) / (Bx ^ 2 + By ^ 2)
305 //
SkFindQuadMaxCurvature(const SkPoint src[3])306 SkScalar SkFindQuadMaxCurvature(const SkPoint src[3]) {
307     SkScalar    Ax = src[1].fX - src[0].fX;
308     SkScalar    Ay = src[1].fY - src[0].fY;
309     SkScalar    Bx = src[0].fX - src[1].fX - src[1].fX + src[2].fX;
310     SkScalar    By = src[0].fY - src[1].fY - src[1].fY + src[2].fY;
311     SkScalar    t = 0;  // 0 means don't chop
312 
313     (void)valid_unit_divide(-(Ax * Bx + Ay * By), Bx * Bx + By * By, &t);
314     return t;
315 }
316 
SkChopQuadAtMaxCurvature(const SkPoint src[3],SkPoint dst[5])317 int SkChopQuadAtMaxCurvature(const SkPoint src[3], SkPoint dst[5]) {
318     SkScalar t = SkFindQuadMaxCurvature(src);
319     if (t == 0) {
320         memcpy(dst, src, 3 * sizeof(SkPoint));
321         return 1;
322     } else {
323         SkChopQuadAt(src, dst, t);
324         return 2;
325     }
326 }
327 
SkConvertQuadToCubic(const SkPoint src[3],SkPoint dst[4])328 void SkConvertQuadToCubic(const SkPoint src[3], SkPoint dst[4]) {
329     Sk2s scale(SkDoubleToScalar(2.0 / 3.0));
330     Sk2s s0 = from_point(src[0]);
331     Sk2s s1 = from_point(src[1]);
332     Sk2s s2 = from_point(src[2]);
333 
334     dst[0] = src[0];
335     dst[1] = to_point(s0 + (s1 - s0) * scale);
336     dst[2] = to_point(s2 + (s1 - s2) * scale);
337     dst[3] = src[2];
338 }
339 
340 //////////////////////////////////////////////////////////////////////////////
341 ///// CUBICS // CUBICS // CUBICS // CUBICS // CUBICS // CUBICS // CUBICS /////
342 //////////////////////////////////////////////////////////////////////////////
343 
eval_cubic(const SkScalar src[],SkScalar t)344 static SkScalar eval_cubic(const SkScalar src[], SkScalar t) {
345     SkASSERT(src);
346     SkASSERT(t >= 0 && t <= SK_Scalar1);
347 
348     if (t == 0) {
349         return src[0];
350     }
351 
352 #ifdef DIRECT_EVAL_OF_POLYNOMIALS
353     SkScalar D = src[0];
354     SkScalar A = src[6] + 3*(src[2] - src[4]) - D;
355     SkScalar B = 3*(src[4] - src[2] - src[2] + D);
356     SkScalar C = 3*(src[2] - D);
357 
358     return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D);
359 #else
360     SkScalar    ab = SkScalarInterp(src[0], src[2], t);
361     SkScalar    bc = SkScalarInterp(src[2], src[4], t);
362     SkScalar    cd = SkScalarInterp(src[4], src[6], t);
363     SkScalar    abc = SkScalarInterp(ab, bc, t);
364     SkScalar    bcd = SkScalarInterp(bc, cd, t);
365     return SkScalarInterp(abc, bcd, t);
366 #endif
367 }
368 
369 /** return At^2 + Bt + C
370 */
eval_quadratic(SkScalar A,SkScalar B,SkScalar C,SkScalar t)371 static SkScalar eval_quadratic(SkScalar A, SkScalar B, SkScalar C, SkScalar t) {
372     SkASSERT(t >= 0 && t <= SK_Scalar1);
373 
374     return SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C);
375 }
376 
eval_cubic_derivative(const SkScalar src[],SkScalar t)377 static SkScalar eval_cubic_derivative(const SkScalar src[], SkScalar t) {
378     SkScalar A = src[6] + 3*(src[2] - src[4]) - src[0];
379     SkScalar B = 2*(src[4] - 2 * src[2] + src[0]);
380     SkScalar C = src[2] - src[0];
381 
382     return eval_quadratic(A, B, C, t);
383 }
384 
eval_cubic_2ndDerivative(const SkScalar src[],SkScalar t)385 static SkScalar eval_cubic_2ndDerivative(const SkScalar src[], SkScalar t) {
386     SkScalar A = src[6] + 3*(src[2] - src[4]) - src[0];
387     SkScalar B = src[4] - 2 * src[2] + src[0];
388 
389     return SkScalarMulAdd(A, t, B);
390 }
391 
SkEvalCubicAt(const SkPoint src[4],SkScalar t,SkPoint * loc,SkVector * tangent,SkVector * curvature)392 void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint* loc,
393                    SkVector* tangent, SkVector* curvature) {
394     SkASSERT(src);
395     SkASSERT(t >= 0 && t <= SK_Scalar1);
396 
397     if (loc) {
398         loc->set(eval_cubic(&src[0].fX, t), eval_cubic(&src[0].fY, t));
399     }
400     if (tangent) {
401         tangent->set(eval_cubic_derivative(&src[0].fX, t),
402                      eval_cubic_derivative(&src[0].fY, t));
403     }
404     if (curvature) {
405         curvature->set(eval_cubic_2ndDerivative(&src[0].fX, t),
406                        eval_cubic_2ndDerivative(&src[0].fY, t));
407     }
408 }
409 
410 /** Cubic'(t) = At^2 + Bt + C, where
411     A = 3(-a + 3(b - c) + d)
412     B = 6(a - 2b + c)
413     C = 3(b - a)
414     Solve for t, keeping only those that fit betwee 0 < t < 1
415 */
SkFindCubicExtrema(SkScalar a,SkScalar b,SkScalar c,SkScalar d,SkScalar tValues[2])416 int SkFindCubicExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar d,
417                        SkScalar tValues[2]) {
418     // we divide A,B,C by 3 to simplify
419     SkScalar A = d - a + 3*(b - c);
420     SkScalar B = 2*(a - b - b + c);
421     SkScalar C = b - a;
422 
423     return SkFindUnitQuadRoots(A, B, C, tValues);
424 }
425 
SkChopCubicAt(const SkPoint src[4],SkPoint dst[7],SkScalar t)426 void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], SkScalar t) {
427     SkASSERT(t > 0 && t < SK_Scalar1);
428 
429     Sk2s    p0 = from_point(src[0]);
430     Sk2s    p1 = from_point(src[1]);
431     Sk2s    p2 = from_point(src[2]);
432     Sk2s    p3 = from_point(src[3]);
433     Sk2s    tt(t);
434 
435     Sk2s    ab = interp(p0, p1, tt);
436     Sk2s    bc = interp(p1, p2, tt);
437     Sk2s    cd = interp(p2, p3, tt);
438     Sk2s    abc = interp(ab, bc, tt);
439     Sk2s    bcd = interp(bc, cd, tt);
440     Sk2s    abcd = interp(abc, bcd, tt);
441 
442     dst[0] = src[0];
443     dst[1] = to_point(ab);
444     dst[2] = to_point(abc);
445     dst[3] = to_point(abcd);
446     dst[4] = to_point(bcd);
447     dst[5] = to_point(cd);
448     dst[6] = src[3];
449 }
450 
SkCubicToCoeff(const SkPoint pts[4],SkPoint coeff[4])451 void SkCubicToCoeff(const SkPoint pts[4], SkPoint coeff[4]) {
452     Sk2s p0 = from_point(pts[0]);
453     Sk2s p1 = from_point(pts[1]);
454     Sk2s p2 = from_point(pts[2]);
455     Sk2s p3 = from_point(pts[3]);
456 
457     const Sk2s three(3);
458     Sk2s p1minusp2 = p1 - p2;
459 
460     Sk2s D = p0;
461     Sk2s A = p3 + three * p1minusp2 - D;
462     Sk2s B = three * (D - p1minusp2 - p1);
463     Sk2s C = three * (p1 - D);
464 
465     coeff[0] = to_point(A);
466     coeff[1] = to_point(B);
467     coeff[2] = to_point(C);
468     coeff[3] = to_point(D);
469 }
470 
471 /*  http://code.google.com/p/skia/issues/detail?id=32
472 
473     This test code would fail when we didn't check the return result of
474     valid_unit_divide in SkChopCubicAt(... tValues[], int roots). The reason is
475     that after the first chop, the parameters to valid_unit_divide are equal
476     (thanks to finite float precision and rounding in the subtracts). Thus
477     even though the 2nd tValue looks < 1.0, after we renormalize it, we end
478     up with 1.0, hence the need to check and just return the last cubic as
479     a degenerate clump of 4 points in the sampe place.
480 
481     static void test_cubic() {
482         SkPoint src[4] = {
483             { 556.25000, 523.03003 },
484             { 556.23999, 522.96002 },
485             { 556.21997, 522.89001 },
486             { 556.21997, 522.82001 }
487         };
488         SkPoint dst[10];
489         SkScalar tval[] = { 0.33333334f, 0.99999994f };
490         SkChopCubicAt(src, dst, tval, 2);
491     }
492  */
493 
SkChopCubicAt(const SkPoint src[4],SkPoint dst[],const SkScalar tValues[],int roots)494 void SkChopCubicAt(const SkPoint src[4], SkPoint dst[],
495                    const SkScalar tValues[], int roots) {
496 #ifdef SK_DEBUG
497     {
498         for (int i = 0; i < roots - 1; i++)
499         {
500             SkASSERT(is_unit_interval(tValues[i]));
501             SkASSERT(is_unit_interval(tValues[i+1]));
502             SkASSERT(tValues[i] < tValues[i+1]);
503         }
504     }
505 #endif
506 
507     if (dst) {
508         if (roots == 0) { // nothing to chop
509             memcpy(dst, src, 4*sizeof(SkPoint));
510         } else {
511             SkScalar    t = tValues[0];
512             SkPoint     tmp[4];
513 
514             for (int i = 0; i < roots; i++) {
515                 SkChopCubicAt(src, dst, t);
516                 if (i == roots - 1) {
517                     break;
518                 }
519 
520                 dst += 3;
521                 // have src point to the remaining cubic (after the chop)
522                 memcpy(tmp, dst, 4 * sizeof(SkPoint));
523                 src = tmp;
524 
525                 // watch out in case the renormalized t isn't in range
526                 if (!valid_unit_divide(tValues[i+1] - tValues[i],
527                                        SK_Scalar1 - tValues[i], &t)) {
528                     // if we can't, just create a degenerate cubic
529                     dst[4] = dst[5] = dst[6] = src[3];
530                     break;
531                 }
532             }
533         }
534     }
535 }
536 
SkChopCubicAtHalf(const SkPoint src[4],SkPoint dst[7])537 void SkChopCubicAtHalf(const SkPoint src[4], SkPoint dst[7]) {
538     SkChopCubicAt(src, dst, 0.5f);
539 }
540 
flatten_double_cubic_extrema(SkScalar coords[14])541 static void flatten_double_cubic_extrema(SkScalar coords[14]) {
542     coords[4] = coords[8] = coords[6];
543 }
544 
545 /** Given 4 points on a cubic bezier, chop it into 1, 2, 3 beziers such that
546     the resulting beziers are monotonic in Y. This is called by the scan
547     converter.  Depending on what is returned, dst[] is treated as follows:
548     0   dst[0..3] is the original cubic
549     1   dst[0..3] and dst[3..6] are the two new cubics
550     2   dst[0..3], dst[3..6], dst[6..9] are the three new cubics
551     If dst == null, it is ignored and only the count is returned.
552 */
SkChopCubicAtYExtrema(const SkPoint src[4],SkPoint dst[10])553 int SkChopCubicAtYExtrema(const SkPoint src[4], SkPoint dst[10]) {
554     SkScalar    tValues[2];
555     int         roots = SkFindCubicExtrema(src[0].fY, src[1].fY, src[2].fY,
556                                            src[3].fY, tValues);
557 
558     SkChopCubicAt(src, dst, tValues, roots);
559     if (dst && roots > 0) {
560         // we do some cleanup to ensure our Y extrema are flat
561         flatten_double_cubic_extrema(&dst[0].fY);
562         if (roots == 2) {
563             flatten_double_cubic_extrema(&dst[3].fY);
564         }
565     }
566     return roots;
567 }
568 
SkChopCubicAtXExtrema(const SkPoint src[4],SkPoint dst[10])569 int SkChopCubicAtXExtrema(const SkPoint src[4], SkPoint dst[10]) {
570     SkScalar    tValues[2];
571     int         roots = SkFindCubicExtrema(src[0].fX, src[1].fX, src[2].fX,
572                                            src[3].fX, tValues);
573 
574     SkChopCubicAt(src, dst, tValues, roots);
575     if (dst && roots > 0) {
576         // we do some cleanup to ensure our Y extrema are flat
577         flatten_double_cubic_extrema(&dst[0].fX);
578         if (roots == 2) {
579             flatten_double_cubic_extrema(&dst[3].fX);
580         }
581     }
582     return roots;
583 }
584 
585 /** http://www.faculty.idc.ac.il/arik/quality/appendixA.html
586 
587     Inflection means that curvature is zero.
588     Curvature is [F' x F''] / [F'^3]
589     So we solve F'x X F''y - F'y X F''y == 0
590     After some canceling of the cubic term, we get
591     A = b - a
592     B = c - 2b + a
593     C = d - 3c + 3b - a
594     (BxCy - ByCx)t^2 + (AxCy - AyCx)t + AxBy - AyBx == 0
595 */
SkFindCubicInflections(const SkPoint src[4],SkScalar tValues[])596 int SkFindCubicInflections(const SkPoint src[4], SkScalar tValues[]) {
597     SkScalar    Ax = src[1].fX - src[0].fX;
598     SkScalar    Ay = src[1].fY - src[0].fY;
599     SkScalar    Bx = src[2].fX - 2 * src[1].fX + src[0].fX;
600     SkScalar    By = src[2].fY - 2 * src[1].fY + src[0].fY;
601     SkScalar    Cx = src[3].fX + 3 * (src[1].fX - src[2].fX) - src[0].fX;
602     SkScalar    Cy = src[3].fY + 3 * (src[1].fY - src[2].fY) - src[0].fY;
603 
604     return SkFindUnitQuadRoots(Bx*Cy - By*Cx,
605                                Ax*Cy - Ay*Cx,
606                                Ax*By - Ay*Bx,
607                                tValues);
608 }
609 
SkChopCubicAtInflections(const SkPoint src[],SkPoint dst[10])610 int SkChopCubicAtInflections(const SkPoint src[], SkPoint dst[10]) {
611     SkScalar    tValues[2];
612     int         count = SkFindCubicInflections(src, tValues);
613 
614     if (dst) {
615         if (count == 0) {
616             memcpy(dst, src, 4 * sizeof(SkPoint));
617         } else {
618             SkChopCubicAt(src, dst, tValues, count);
619         }
620     }
621     return count + 1;
622 }
623 
624 // See http://http.developer.nvidia.com/GPUGems3/gpugems3_ch25.html (from the book GPU Gems 3)
625 // discr(I) = d0^2 * (3*d1^2 - 4*d0*d2)
626 // Classification:
627 // discr(I) > 0        Serpentine
628 // discr(I) = 0        Cusp
629 // discr(I) < 0        Loop
630 // d0 = d1 = 0         Quadratic
631 // d0 = d1 = d2 = 0    Line
632 // p0 = p1 = p2 = p3   Point
classify_cubic(const SkPoint p[4],const SkScalar d[3])633 static SkCubicType classify_cubic(const SkPoint p[4], const SkScalar d[3]) {
634     if (p[0] == p[1] && p[0] == p[2] && p[0] == p[3]) {
635         return kPoint_SkCubicType;
636     }
637     const SkScalar discr = d[0] * d[0] * (3.f * d[1] * d[1] - 4.f * d[0] * d[2]);
638     if (discr > SK_ScalarNearlyZero) {
639         return kSerpentine_SkCubicType;
640     } else if (discr < -SK_ScalarNearlyZero) {
641         return kLoop_SkCubicType;
642     } else {
643         if (0.f == d[0] && 0.f == d[1]) {
644             return (0.f == d[2] ? kLine_SkCubicType : kQuadratic_SkCubicType);
645         } else {
646             return kCusp_SkCubicType;
647         }
648     }
649 }
650 
651 // Assumes the third component of points is 1.
652 // Calcs p0 . (p1 x p2)
calc_dot_cross_cubic(const SkPoint & p0,const SkPoint & p1,const SkPoint & p2)653 static SkScalar calc_dot_cross_cubic(const SkPoint& p0, const SkPoint& p1, const SkPoint& p2) {
654     const SkScalar xComp = p0.fX * (p1.fY - p2.fY);
655     const SkScalar yComp = p0.fY * (p2.fX - p1.fX);
656     const SkScalar wComp = p1.fX * p2.fY - p1.fY * p2.fX;
657     return (xComp + yComp + wComp);
658 }
659 
660 // Calc coefficients of I(s,t) where roots of I are inflection points of curve
661 // I(s,t) = t*(3*d0*s^2 - 3*d1*s*t + d2*t^2)
662 // d0 = a1 - 2*a2+3*a3
663 // d1 = -a2 + 3*a3
664 // d2 = 3*a3
665 // a1 = p0 . (p3 x p2)
666 // a2 = p1 . (p0 x p3)
667 // a3 = p2 . (p1 x p0)
668 // Places the values of d1, d2, d3 in array d passed in
calc_cubic_inflection_func(const SkPoint p[4],SkScalar d[3])669 static void calc_cubic_inflection_func(const SkPoint p[4], SkScalar d[3]) {
670     SkScalar a1 = calc_dot_cross_cubic(p[0], p[3], p[2]);
671     SkScalar a2 = calc_dot_cross_cubic(p[1], p[0], p[3]);
672     SkScalar a3 = calc_dot_cross_cubic(p[2], p[1], p[0]);
673 
674     // need to scale a's or values in later calculations will grow to high
675     SkScalar max = SkScalarAbs(a1);
676     max = SkMaxScalar(max, SkScalarAbs(a2));
677     max = SkMaxScalar(max, SkScalarAbs(a3));
678     max = 1.f/max;
679     a1 = a1 * max;
680     a2 = a2 * max;
681     a3 = a3 * max;
682 
683     d[2] = 3.f * a3;
684     d[1] = d[2] - a2;
685     d[0] = d[1] - a2 + a1;
686 }
687 
SkClassifyCubic(const SkPoint src[4],SkScalar d[3])688 SkCubicType SkClassifyCubic(const SkPoint src[4], SkScalar d[3]) {
689     calc_cubic_inflection_func(src, d);
690     return classify_cubic(src, d);
691 }
692 
bubble_sort(T array[],int count)693 template <typename T> void bubble_sort(T array[], int count) {
694     for (int i = count - 1; i > 0; --i)
695         for (int j = i; j > 0; --j)
696             if (array[j] < array[j-1])
697             {
698                 T   tmp(array[j]);
699                 array[j] = array[j-1];
700                 array[j-1] = tmp;
701             }
702 }
703 
704 /**
705  *  Given an array and count, remove all pair-wise duplicates from the array,
706  *  keeping the existing sorting, and return the new count
707  */
collaps_duplicates(SkScalar array[],int count)708 static int collaps_duplicates(SkScalar array[], int count) {
709     for (int n = count; n > 1; --n) {
710         if (array[0] == array[1]) {
711             for (int i = 1; i < n; ++i) {
712                 array[i - 1] = array[i];
713             }
714             count -= 1;
715         } else {
716             array += 1;
717         }
718     }
719     return count;
720 }
721 
722 #ifdef SK_DEBUG
723 
724 #define TEST_COLLAPS_ENTRY(array)   array, SK_ARRAY_COUNT(array)
725 
test_collaps_duplicates()726 static void test_collaps_duplicates() {
727     static bool gOnce;
728     if (gOnce) { return; }
729     gOnce = true;
730     const SkScalar src0[] = { 0 };
731     const SkScalar src1[] = { 0, 0 };
732     const SkScalar src2[] = { 0, 1 };
733     const SkScalar src3[] = { 0, 0, 0 };
734     const SkScalar src4[] = { 0, 0, 1 };
735     const SkScalar src5[] = { 0, 1, 1 };
736     const SkScalar src6[] = { 0, 1, 2 };
737     const struct {
738         const SkScalar* fData;
739         int fCount;
740         int fCollapsedCount;
741     } data[] = {
742         { TEST_COLLAPS_ENTRY(src0), 1 },
743         { TEST_COLLAPS_ENTRY(src1), 1 },
744         { TEST_COLLAPS_ENTRY(src2), 2 },
745         { TEST_COLLAPS_ENTRY(src3), 1 },
746         { TEST_COLLAPS_ENTRY(src4), 2 },
747         { TEST_COLLAPS_ENTRY(src5), 2 },
748         { TEST_COLLAPS_ENTRY(src6), 3 },
749     };
750     for (size_t i = 0; i < SK_ARRAY_COUNT(data); ++i) {
751         SkScalar dst[3];
752         memcpy(dst, data[i].fData, data[i].fCount * sizeof(dst[0]));
753         int count = collaps_duplicates(dst, data[i].fCount);
754         SkASSERT(data[i].fCollapsedCount == count);
755         for (int j = 1; j < count; ++j) {
756             SkASSERT(dst[j-1] < dst[j]);
757         }
758     }
759 }
760 #endif
761 
SkScalarCubeRoot(SkScalar x)762 static SkScalar SkScalarCubeRoot(SkScalar x) {
763     return SkScalarPow(x, 0.3333333f);
764 }
765 
766 /*  Solve coeff(t) == 0, returning the number of roots that
767     lie withing 0 < t < 1.
768     coeff[0]t^3 + coeff[1]t^2 + coeff[2]t + coeff[3]
769 
770     Eliminates repeated roots (so that all tValues are distinct, and are always
771     in increasing order.
772 */
solve_cubic_poly(const SkScalar coeff[4],SkScalar tValues[3])773 static int solve_cubic_poly(const SkScalar coeff[4], SkScalar tValues[3]) {
774     if (SkScalarNearlyZero(coeff[0])) {  // we're just a quadratic
775         return SkFindUnitQuadRoots(coeff[1], coeff[2], coeff[3], tValues);
776     }
777 
778     SkScalar a, b, c, Q, R;
779 
780     {
781         SkASSERT(coeff[0] != 0);
782 
783         SkScalar inva = SkScalarInvert(coeff[0]);
784         a = coeff[1] * inva;
785         b = coeff[2] * inva;
786         c = coeff[3] * inva;
787     }
788     Q = (a*a - b*3) / 9;
789     R = (2*a*a*a - 9*a*b + 27*c) / 54;
790 
791     SkScalar Q3 = Q * Q * Q;
792     SkScalar R2MinusQ3 = R * R - Q3;
793     SkScalar adiv3 = a / 3;
794 
795     SkScalar*   roots = tValues;
796     SkScalar    r;
797 
798     if (R2MinusQ3 < 0) { // we have 3 real roots
799         SkScalar theta = SkScalarACos(R / SkScalarSqrt(Q3));
800         SkScalar neg2RootQ = -2 * SkScalarSqrt(Q);
801 
802         r = neg2RootQ * SkScalarCos(theta/3) - adiv3;
803         if (is_unit_interval(r)) {
804             *roots++ = r;
805         }
806         r = neg2RootQ * SkScalarCos((theta + 2*SK_ScalarPI)/3) - adiv3;
807         if (is_unit_interval(r)) {
808             *roots++ = r;
809         }
810         r = neg2RootQ * SkScalarCos((theta - 2*SK_ScalarPI)/3) - adiv3;
811         if (is_unit_interval(r)) {
812             *roots++ = r;
813         }
814         SkDEBUGCODE(test_collaps_duplicates();)
815 
816         // now sort the roots
817         int count = (int)(roots - tValues);
818         SkASSERT((unsigned)count <= 3);
819         bubble_sort(tValues, count);
820         count = collaps_duplicates(tValues, count);
821         roots = tValues + count;    // so we compute the proper count below
822     } else {              // we have 1 real root
823         SkScalar A = SkScalarAbs(R) + SkScalarSqrt(R2MinusQ3);
824         A = SkScalarCubeRoot(A);
825         if (R > 0) {
826             A = -A;
827         }
828         if (A != 0) {
829             A += Q / A;
830         }
831         r = A - adiv3;
832         if (is_unit_interval(r)) {
833             *roots++ = r;
834         }
835     }
836 
837     return (int)(roots - tValues);
838 }
839 
840 /*  Looking for F' dot F'' == 0
841 
842     A = b - a
843     B = c - 2b + a
844     C = d - 3c + 3b - a
845 
846     F' = 3Ct^2 + 6Bt + 3A
847     F'' = 6Ct + 6B
848 
849     F' dot F'' -> CCt^3 + 3BCt^2 + (2BB + CA)t + AB
850 */
formulate_F1DotF2(const SkScalar src[],SkScalar coeff[4])851 static void formulate_F1DotF2(const SkScalar src[], SkScalar coeff[4]) {
852     SkScalar    a = src[2] - src[0];
853     SkScalar    b = src[4] - 2 * src[2] + src[0];
854     SkScalar    c = src[6] + 3 * (src[2] - src[4]) - src[0];
855 
856     coeff[0] = c * c;
857     coeff[1] = 3 * b * c;
858     coeff[2] = 2 * b * b + c * a;
859     coeff[3] = a * b;
860 }
861 
862 /*  Looking for F' dot F'' == 0
863 
864     A = b - a
865     B = c - 2b + a
866     C = d - 3c + 3b - a
867 
868     F' = 3Ct^2 + 6Bt + 3A
869     F'' = 6Ct + 6B
870 
871     F' dot F'' -> CCt^3 + 3BCt^2 + (2BB + CA)t + AB
872 */
SkFindCubicMaxCurvature(const SkPoint src[4],SkScalar tValues[3])873 int SkFindCubicMaxCurvature(const SkPoint src[4], SkScalar tValues[3]) {
874     SkScalar coeffX[4], coeffY[4];
875     int      i;
876 
877     formulate_F1DotF2(&src[0].fX, coeffX);
878     formulate_F1DotF2(&src[0].fY, coeffY);
879 
880     for (i = 0; i < 4; i++) {
881         coeffX[i] += coeffY[i];
882     }
883 
884     SkScalar    t[3];
885     int         count = solve_cubic_poly(coeffX, t);
886     int         maxCount = 0;
887 
888     // now remove extrema where the curvature is zero (mins)
889     // !!!! need a test for this !!!!
890     for (i = 0; i < count; i++) {
891         // if (not_min_curvature())
892         if (t[i] > 0 && t[i] < SK_Scalar1) {
893             tValues[maxCount++] = t[i];
894         }
895     }
896     return maxCount;
897 }
898 
SkChopCubicAtMaxCurvature(const SkPoint src[4],SkPoint dst[13],SkScalar tValues[3])899 int SkChopCubicAtMaxCurvature(const SkPoint src[4], SkPoint dst[13],
900                               SkScalar tValues[3]) {
901     SkScalar    t_storage[3];
902 
903     if (tValues == NULL) {
904         tValues = t_storage;
905     }
906 
907     int count = SkFindCubicMaxCurvature(src, tValues);
908 
909     if (dst) {
910         if (count == 0) {
911             memcpy(dst, src, 4 * sizeof(SkPoint));
912         } else {
913             SkChopCubicAt(src, dst, tValues, count);
914         }
915     }
916     return count + 1;
917 }
918 
919 #include "../pathops/SkPathOpsCubic.h"
920 
921 typedef int (SkDCubic::*InterceptProc)(double intercept, double roots[3]) const;
922 
cubic_dchop_at_intercept(const SkPoint src[4],SkScalar intercept,SkPoint dst[7],InterceptProc method)923 static bool cubic_dchop_at_intercept(const SkPoint src[4], SkScalar intercept, SkPoint dst[7],
924                                      InterceptProc method) {
925     SkDCubic cubic;
926     double roots[3];
927     int count = (cubic.set(src).*method)(intercept, roots);
928     if (count > 0) {
929         SkDCubicPair pair = cubic.chopAt(roots[0]);
930         for (int i = 0; i < 7; ++i) {
931             dst[i] = pair.pts[i].asSkPoint();
932         }
933         return true;
934     }
935     return false;
936 }
937 
SkChopMonoCubicAtY(SkPoint src[4],SkScalar y,SkPoint dst[7])938 bool SkChopMonoCubicAtY(SkPoint src[4], SkScalar y, SkPoint dst[7]) {
939     return cubic_dchop_at_intercept(src, y, dst, &SkDCubic::horizontalIntersect);
940 }
941 
SkChopMonoCubicAtX(SkPoint src[4],SkScalar x,SkPoint dst[7])942 bool SkChopMonoCubicAtX(SkPoint src[4], SkScalar x, SkPoint dst[7]) {
943     return cubic_dchop_at_intercept(src, x, dst, &SkDCubic::verticalIntersect);
944 }
945 
946 ///////////////////////////////////////////////////////////////////////////////
947 
948 /*  Find t value for quadratic [a, b, c] = d.
949     Return 0 if there is no solution within [0, 1)
950 */
quad_solve(SkScalar a,SkScalar b,SkScalar c,SkScalar d)951 static SkScalar quad_solve(SkScalar a, SkScalar b, SkScalar c, SkScalar d) {
952     // At^2 + Bt + C = d
953     SkScalar A = a - 2 * b + c;
954     SkScalar B = 2 * (b - a);
955     SkScalar C = a - d;
956 
957     SkScalar    roots[2];
958     int         count = SkFindUnitQuadRoots(A, B, C, roots);
959 
960     SkASSERT(count <= 1);
961     return count == 1 ? roots[0] : 0;
962 }
963 
964 /*  given a quad-curve and a point (x,y), chop the quad at that point and place
965     the new off-curve point and endpoint into 'dest'.
966     Should only return false if the computed pos is the start of the curve
967     (i.e. root == 0)
968 */
truncate_last_curve(const SkPoint quad[3],SkScalar x,SkScalar y,SkPoint * dest)969 static bool truncate_last_curve(const SkPoint quad[3], SkScalar x, SkScalar y,
970                                 SkPoint* dest) {
971     const SkScalar* base;
972     SkScalar        value;
973 
974     if (SkScalarAbs(x) < SkScalarAbs(y)) {
975         base = &quad[0].fX;
976         value = x;
977     } else {
978         base = &quad[0].fY;
979         value = y;
980     }
981 
982     // note: this returns 0 if it thinks value is out of range, meaning the
983     // root might return something outside of [0, 1)
984     SkScalar t = quad_solve(base[0], base[2], base[4], value);
985 
986     if (t > 0) {
987         SkPoint tmp[5];
988         SkChopQuadAt(quad, tmp, t);
989         dest[0] = tmp[1];
990         dest[1].set(x, y);
991         return true;
992     } else {
993         /*  t == 0 means either the value triggered a root outside of [0, 1)
994             For our purposes, we can ignore the <= 0 roots, but we want to
995             catch the >= 1 roots (which given our caller, will basically mean
996             a root of 1, give-or-take numerical instability). If we are in the
997             >= 1 case, return the existing offCurve point.
998 
999             The test below checks to see if we are close to the "end" of the
1000             curve (near base[4]). Rather than specifying a tolerance, I just
1001             check to see if value is on to the right/left of the middle point
1002             (depending on the direction/sign of the end points).
1003         */
1004         if ((base[0] < base[4] && value > base[2]) ||
1005             (base[0] > base[4] && value < base[2]))   // should root have been 1
1006         {
1007             dest[0] = quad[1];
1008             dest[1].set(x, y);
1009             return true;
1010         }
1011     }
1012     return false;
1013 }
1014 
1015 static const SkPoint gQuadCirclePts[kSkBuildQuadArcStorage] = {
1016 // The mid point of the quadratic arc approximation is half way between the two
1017 // control points. The float epsilon adjustment moves the on curve point out by
1018 // two bits, distributing the convex test error between the round rect
1019 // approximation and the convex cross product sign equality test.
1020 #define SK_MID_RRECT_OFFSET \
1021     (SK_Scalar1 + SK_ScalarTanPIOver8 + FLT_EPSILON * 4) / 2
1022     { SK_Scalar1,            0                      },
1023     { SK_Scalar1,            SK_ScalarTanPIOver8    },
1024     { SK_MID_RRECT_OFFSET,   SK_MID_RRECT_OFFSET    },
1025     { SK_ScalarTanPIOver8,   SK_Scalar1             },
1026 
1027     { 0,                     SK_Scalar1             },
1028     { -SK_ScalarTanPIOver8,  SK_Scalar1             },
1029     { -SK_MID_RRECT_OFFSET,  SK_MID_RRECT_OFFSET    },
1030     { -SK_Scalar1,           SK_ScalarTanPIOver8    },
1031 
1032     { -SK_Scalar1,           0                      },
1033     { -SK_Scalar1,           -SK_ScalarTanPIOver8   },
1034     { -SK_MID_RRECT_OFFSET,  -SK_MID_RRECT_OFFSET   },
1035     { -SK_ScalarTanPIOver8,  -SK_Scalar1            },
1036 
1037     { 0,                     -SK_Scalar1            },
1038     { SK_ScalarTanPIOver8,   -SK_Scalar1            },
1039     { SK_MID_RRECT_OFFSET,   -SK_MID_RRECT_OFFSET   },
1040     { SK_Scalar1,            -SK_ScalarTanPIOver8   },
1041 
1042     { SK_Scalar1,            0                      }
1043 #undef SK_MID_RRECT_OFFSET
1044 };
1045 
SkBuildQuadArc(const SkVector & uStart,const SkVector & uStop,SkRotationDirection dir,const SkMatrix * userMatrix,SkPoint quadPoints[])1046 int SkBuildQuadArc(const SkVector& uStart, const SkVector& uStop,
1047                    SkRotationDirection dir, const SkMatrix* userMatrix,
1048                    SkPoint quadPoints[]) {
1049     // rotate by x,y so that uStart is (1.0)
1050     SkScalar x = SkPoint::DotProduct(uStart, uStop);
1051     SkScalar y = SkPoint::CrossProduct(uStart, uStop);
1052 
1053     SkScalar absX = SkScalarAbs(x);
1054     SkScalar absY = SkScalarAbs(y);
1055 
1056     int pointCount;
1057 
1058     // check for (effectively) coincident vectors
1059     // this can happen if our angle is nearly 0 or nearly 180 (y == 0)
1060     // ... we use the dot-prod to distinguish between 0 and 180 (x > 0)
1061     if (absY <= SK_ScalarNearlyZero && x > 0 &&
1062         ((y >= 0 && kCW_SkRotationDirection == dir) ||
1063          (y <= 0 && kCCW_SkRotationDirection == dir))) {
1064 
1065         // just return the start-point
1066         quadPoints[0].set(SK_Scalar1, 0);
1067         pointCount = 1;
1068     } else {
1069         if (dir == kCCW_SkRotationDirection) {
1070             y = -y;
1071         }
1072         // what octant (quadratic curve) is [xy] in?
1073         int oct = 0;
1074         bool sameSign = true;
1075 
1076         if (0 == y) {
1077             oct = 4;        // 180
1078             SkASSERT(SkScalarAbs(x + SK_Scalar1) <= SK_ScalarNearlyZero);
1079         } else if (0 == x) {
1080             SkASSERT(absY - SK_Scalar1 <= SK_ScalarNearlyZero);
1081             oct = y > 0 ? 2 : 6; // 90 : 270
1082         } else {
1083             if (y < 0) {
1084                 oct += 4;
1085             }
1086             if ((x < 0) != (y < 0)) {
1087                 oct += 2;
1088                 sameSign = false;
1089             }
1090             if ((absX < absY) == sameSign) {
1091                 oct += 1;
1092             }
1093         }
1094 
1095         int wholeCount = oct << 1;
1096         memcpy(quadPoints, gQuadCirclePts, (wholeCount + 1) * sizeof(SkPoint));
1097 
1098         const SkPoint* arc = &gQuadCirclePts[wholeCount];
1099         if (truncate_last_curve(arc, x, y, &quadPoints[wholeCount + 1])) {
1100             wholeCount += 2;
1101         }
1102         pointCount = wholeCount + 1;
1103     }
1104 
1105     // now handle counter-clockwise and the initial unitStart rotation
1106     SkMatrix    matrix;
1107     matrix.setSinCos(uStart.fY, uStart.fX);
1108     if (dir == kCCW_SkRotationDirection) {
1109         matrix.preScale(SK_Scalar1, -SK_Scalar1);
1110     }
1111     if (userMatrix) {
1112         matrix.postConcat(*userMatrix);
1113     }
1114     matrix.mapPoints(quadPoints, pointCount);
1115     return pointCount;
1116 }
1117 
1118 
1119 ///////////////////////////////////////////////////////////////////////////////
1120 //
1121 // NURB representation for conics.  Helpful explanations at:
1122 //
1123 // http://citeseerx.ist.psu.edu/viewdoc/
1124 //   download?doi=10.1.1.44.5740&rep=rep1&type=ps
1125 // and
1126 // http://www.cs.mtu.edu/~shene/COURSES/cs3621/NOTES/spline/NURBS/RB-conics.html
1127 //
1128 // F = (A (1 - t)^2 + C t^2 + 2 B (1 - t) t w)
1129 //     ------------------------------------------
1130 //         ((1 - t)^2 + t^2 + 2 (1 - t) t w)
1131 //
1132 //   = {t^2 (P0 + P2 - 2 P1 w), t (-2 P0 + 2 P1 w), P0}
1133 //     ------------------------------------------------
1134 //             {t^2 (2 - 2 w), t (-2 + 2 w), 1}
1135 //
1136 
conic_eval_pos(const SkScalar src[],SkScalar w,SkScalar t)1137 static SkScalar conic_eval_pos(const SkScalar src[], SkScalar w, SkScalar t) {
1138     SkASSERT(src);
1139     SkASSERT(t >= 0 && t <= SK_Scalar1);
1140 
1141     SkScalar    src2w = SkScalarMul(src[2], w);
1142     SkScalar    C = src[0];
1143     SkScalar    A = src[4] - 2 * src2w + C;
1144     SkScalar    B = 2 * (src2w - C);
1145     SkScalar numer = SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C);
1146 
1147     B = 2 * (w - SK_Scalar1);
1148     C = SK_Scalar1;
1149     A = -B;
1150     SkScalar denom = SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C);
1151 
1152     return numer / denom;
1153 }
1154 
1155 // F' = 2 (C t (1 + t (-1 + w)) - A (-1 + t) (t (-1 + w) - w) + B (1 - 2 t) w)
1156 //
1157 //  t^2 : (2 P0 - 2 P2 - 2 P0 w + 2 P2 w)
1158 //  t^1 : (-2 P0 + 2 P2 + 4 P0 w - 4 P1 w)
1159 //  t^0 : -2 P0 w + 2 P1 w
1160 //
1161 //  We disregard magnitude, so we can freely ignore the denominator of F', and
1162 //  divide the numerator by 2
1163 //
1164 //    coeff[0] for t^2
1165 //    coeff[1] for t^1
1166 //    coeff[2] for t^0
1167 //
conic_deriv_coeff(const SkScalar src[],SkScalar w,SkScalar coeff[3])1168 static void conic_deriv_coeff(const SkScalar src[],
1169                               SkScalar w,
1170                               SkScalar coeff[3]) {
1171     const SkScalar P20 = src[4] - src[0];
1172     const SkScalar P10 = src[2] - src[0];
1173     const SkScalar wP10 = w * P10;
1174     coeff[0] = w * P20 - P20;
1175     coeff[1] = P20 - 2 * wP10;
1176     coeff[2] = wP10;
1177 }
1178 
conic_eval_tan(const SkScalar coord[],SkScalar w,SkScalar t)1179 static SkScalar conic_eval_tan(const SkScalar coord[], SkScalar w, SkScalar t) {
1180     SkScalar coeff[3];
1181     conic_deriv_coeff(coord, w, coeff);
1182     return t * (t * coeff[0] + coeff[1]) + coeff[2];
1183 }
1184 
conic_find_extrema(const SkScalar src[],SkScalar w,SkScalar * t)1185 static bool conic_find_extrema(const SkScalar src[], SkScalar w, SkScalar* t) {
1186     SkScalar coeff[3];
1187     conic_deriv_coeff(src, w, coeff);
1188 
1189     SkScalar tValues[2];
1190     int roots = SkFindUnitQuadRoots(coeff[0], coeff[1], coeff[2], tValues);
1191     SkASSERT(0 == roots || 1 == roots);
1192 
1193     if (1 == roots) {
1194         *t = tValues[0];
1195         return true;
1196     }
1197     return false;
1198 }
1199 
1200 struct SkP3D {
1201     SkScalar fX, fY, fZ;
1202 
setSkP3D1203     void set(SkScalar x, SkScalar y, SkScalar z) {
1204         fX = x; fY = y; fZ = z;
1205     }
1206 
projectDownSkP3D1207     void projectDown(SkPoint* dst) const {
1208         dst->set(fX / fZ, fY / fZ);
1209     }
1210 };
1211 
1212 // We only interpolate one dimension at a time (the first, at +0, +3, +6).
p3d_interp(const SkScalar src[7],SkScalar dst[7],SkScalar t)1213 static void p3d_interp(const SkScalar src[7], SkScalar dst[7], SkScalar t) {
1214     SkScalar ab = SkScalarInterp(src[0], src[3], t);
1215     SkScalar bc = SkScalarInterp(src[3], src[6], t);
1216     dst[0] = ab;
1217     dst[3] = SkScalarInterp(ab, bc, t);
1218     dst[6] = bc;
1219 }
1220 
ratquad_mapTo3D(const SkPoint src[3],SkScalar w,SkP3D dst[])1221 static void ratquad_mapTo3D(const SkPoint src[3], SkScalar w, SkP3D dst[]) {
1222     dst[0].set(src[0].fX * 1, src[0].fY * 1, 1);
1223     dst[1].set(src[1].fX * w, src[1].fY * w, w);
1224     dst[2].set(src[2].fX * 1, src[2].fY * 1, 1);
1225 }
1226 
evalAt(SkScalar t,SkPoint * pt,SkVector * tangent) const1227 void SkConic::evalAt(SkScalar t, SkPoint* pt, SkVector* tangent) const {
1228     SkASSERT(t >= 0 && t <= SK_Scalar1);
1229 
1230     if (pt) {
1231         pt->set(conic_eval_pos(&fPts[0].fX, fW, t),
1232                 conic_eval_pos(&fPts[0].fY, fW, t));
1233     }
1234     if (tangent) {
1235         tangent->set(conic_eval_tan(&fPts[0].fX, fW, t),
1236                      conic_eval_tan(&fPts[0].fY, fW, t));
1237     }
1238 }
1239 
chopAt(SkScalar t,SkConic dst[2]) const1240 void SkConic::chopAt(SkScalar t, SkConic dst[2]) const {
1241     SkP3D tmp[3], tmp2[3];
1242 
1243     ratquad_mapTo3D(fPts, fW, tmp);
1244 
1245     p3d_interp(&tmp[0].fX, &tmp2[0].fX, t);
1246     p3d_interp(&tmp[0].fY, &tmp2[0].fY, t);
1247     p3d_interp(&tmp[0].fZ, &tmp2[0].fZ, t);
1248 
1249     dst[0].fPts[0] = fPts[0];
1250     tmp2[0].projectDown(&dst[0].fPts[1]);
1251     tmp2[1].projectDown(&dst[0].fPts[2]); dst[1].fPts[0] = dst[0].fPts[2];
1252     tmp2[2].projectDown(&dst[1].fPts[1]);
1253     dst[1].fPts[2] = fPts[2];
1254 
1255     // to put in "standard form", where w0 and w2 are both 1, we compute the
1256     // new w1 as sqrt(w1*w1/w0*w2)
1257     // or
1258     // w1 /= sqrt(w0*w2)
1259     //
1260     // However, in our case, we know that for dst[0]:
1261     //     w0 == 1, and for dst[1], w2 == 1
1262     //
1263     SkScalar root = SkScalarSqrt(tmp2[1].fZ);
1264     dst[0].fW = tmp2[0].fZ / root;
1265     dst[1].fW = tmp2[2].fZ / root;
1266 }
1267 
times_2(const Sk2s & value)1268 static Sk2s times_2(const Sk2s& value) {
1269     return value + value;
1270 }
1271 
evalAt(SkScalar t) const1272 SkPoint SkConic::evalAt(SkScalar t) const {
1273     Sk2s p0 = from_point(fPts[0]);
1274     Sk2s p1 = from_point(fPts[1]);
1275     Sk2s p2 = from_point(fPts[2]);
1276     Sk2s tt(t);
1277     Sk2s ww(fW);
1278     Sk2s one(1);
1279 
1280     Sk2s p1w = p1 * ww;
1281     Sk2s C = p0;
1282     Sk2s A = p2 - times_2(p1w) + p0;
1283     Sk2s B = times_2(p1w - C);
1284     Sk2s numer = quad_poly_eval(A, B, C, tt);
1285 
1286     B = times_2(ww - one);
1287     A = -B;
1288     Sk2s denom = quad_poly_eval(A, B, one, tt);
1289 
1290     return to_point(numer / denom);
1291 }
1292 
evalTangentAt(SkScalar t) const1293 SkVector SkConic::evalTangentAt(SkScalar t) const {
1294     Sk2s p0 = from_point(fPts[0]);
1295     Sk2s p1 = from_point(fPts[1]);
1296     Sk2s p2 = from_point(fPts[2]);
1297     Sk2s ww(fW);
1298 
1299     Sk2s p20 = p2 - p0;
1300     Sk2s p10 = p1 - p0;
1301 
1302     Sk2s C = ww * p10;
1303     Sk2s A = ww * p20 - p20;
1304     Sk2s B = p20 - C - C;
1305 
1306     return to_vector(quad_poly_eval(A, B, C, Sk2s(t)));
1307 }
1308 
subdivide_w_value(SkScalar w)1309 static SkScalar subdivide_w_value(SkScalar w) {
1310     return SkScalarSqrt(SK_ScalarHalf + w * SK_ScalarHalf);
1311 }
1312 
twice(const Sk2s & value)1313 static Sk2s twice(const Sk2s& value) {
1314     return value + value;
1315 }
1316 
chop(SkConic * SK_RESTRICT dst) const1317 void SkConic::chop(SkConic * SK_RESTRICT dst) const {
1318     Sk2s scale = Sk2s(SkScalarInvert(SK_Scalar1 + fW));
1319     SkScalar newW = subdivide_w_value(fW);
1320 
1321     Sk2s p0 = from_point(fPts[0]);
1322     Sk2s p1 = from_point(fPts[1]);
1323     Sk2s p2 = from_point(fPts[2]);
1324     Sk2s ww(fW);
1325 
1326     Sk2s wp1 = ww * p1;
1327     Sk2s m = (p0 + twice(wp1) + p2) * scale * Sk2s(0.5f);
1328 
1329     dst[0].fPts[0] = fPts[0];
1330     dst[0].fPts[1] = to_point((p0 + wp1) * scale);
1331     dst[0].fPts[2] = dst[1].fPts[0] = to_point(m);
1332     dst[1].fPts[1] = to_point((wp1 + p2) * scale);
1333     dst[1].fPts[2] = fPts[2];
1334 
1335     dst[0].fW = dst[1].fW = newW;
1336 }
1337 
1338 /*
1339  *  "High order approximation of conic sections by quadratic splines"
1340  *      by Michael Floater, 1993
1341  */
1342 #define AS_QUAD_ERROR_SETUP                                         \
1343     SkScalar a = fW - 1;                                            \
1344     SkScalar k = a / (4 * (2 + a));                                 \
1345     SkScalar x = k * (fPts[0].fX - 2 * fPts[1].fX + fPts[2].fX);    \
1346     SkScalar y = k * (fPts[0].fY - 2 * fPts[1].fY + fPts[2].fY);
1347 
computeAsQuadError(SkVector * err) const1348 void SkConic::computeAsQuadError(SkVector* err) const {
1349     AS_QUAD_ERROR_SETUP
1350     err->set(x, y);
1351 }
1352 
asQuadTol(SkScalar tol) const1353 bool SkConic::asQuadTol(SkScalar tol) const {
1354     AS_QUAD_ERROR_SETUP
1355     return (x * x + y * y) <= tol * tol;
1356 }
1357 
1358 // Limit the number of suggested quads to approximate a conic
1359 #define kMaxConicToQuadPOW2     5
1360 
computeQuadPOW2(SkScalar tol) const1361 int SkConic::computeQuadPOW2(SkScalar tol) const {
1362     if (tol < 0 || !SkScalarIsFinite(tol)) {
1363         return 0;
1364     }
1365 
1366     AS_QUAD_ERROR_SETUP
1367 
1368     SkScalar error = SkScalarSqrt(x * x + y * y);
1369     int pow2;
1370     for (pow2 = 0; pow2 < kMaxConicToQuadPOW2; ++pow2) {
1371         if (error <= tol) {
1372             break;
1373         }
1374         error *= 0.25f;
1375     }
1376     // float version -- using ceil gives the same results as the above.
1377     if (false) {
1378         SkScalar err = SkScalarSqrt(x * x + y * y);
1379         if (err <= tol) {
1380             return 0;
1381         }
1382         SkScalar tol2 = tol * tol;
1383         if (tol2 == 0) {
1384             return kMaxConicToQuadPOW2;
1385         }
1386         SkScalar fpow2 = SkScalarLog2((x * x + y * y) / tol2) * 0.25f;
1387         int altPow2 = SkScalarCeilToInt(fpow2);
1388         if (altPow2 != pow2) {
1389             SkDebugf("pow2 %d altPow2 %d fbits %g err %g tol %g\n", pow2, altPow2, fpow2, err, tol);
1390         }
1391         pow2 = altPow2;
1392     }
1393     return pow2;
1394 }
1395 
subdivide(const SkConic & src,SkPoint pts[],int level)1396 static SkPoint* subdivide(const SkConic& src, SkPoint pts[], int level) {
1397     SkASSERT(level >= 0);
1398 
1399     if (0 == level) {
1400         memcpy(pts, &src.fPts[1], 2 * sizeof(SkPoint));
1401         return pts + 2;
1402     } else {
1403         SkConic dst[2];
1404         src.chop(dst);
1405         --level;
1406         pts = subdivide(dst[0], pts, level);
1407         return subdivide(dst[1], pts, level);
1408     }
1409 }
1410 
chopIntoQuadsPOW2(SkPoint pts[],int pow2) const1411 int SkConic::chopIntoQuadsPOW2(SkPoint pts[], int pow2) const {
1412     SkASSERT(pow2 >= 0);
1413     *pts = fPts[0];
1414     SkDEBUGCODE(SkPoint* endPts =) subdivide(*this, pts + 1, pow2);
1415     SkASSERT(endPts - pts == (2 * (1 << pow2) + 1));
1416     return 1 << pow2;
1417 }
1418 
findXExtrema(SkScalar * t) const1419 bool SkConic::findXExtrema(SkScalar* t) const {
1420     return conic_find_extrema(&fPts[0].fX, fW, t);
1421 }
1422 
findYExtrema(SkScalar * t) const1423 bool SkConic::findYExtrema(SkScalar* t) const {
1424     return conic_find_extrema(&fPts[0].fY, fW, t);
1425 }
1426 
chopAtXExtrema(SkConic dst[2]) const1427 bool SkConic::chopAtXExtrema(SkConic dst[2]) const {
1428     SkScalar t;
1429     if (this->findXExtrema(&t)) {
1430         this->chopAt(t, dst);
1431         // now clean-up the middle, since we know t was meant to be at
1432         // an X-extrema
1433         SkScalar value = dst[0].fPts[2].fX;
1434         dst[0].fPts[1].fX = value;
1435         dst[1].fPts[0].fX = value;
1436         dst[1].fPts[1].fX = value;
1437         return true;
1438     }
1439     return false;
1440 }
1441 
chopAtYExtrema(SkConic dst[2]) const1442 bool SkConic::chopAtYExtrema(SkConic dst[2]) const {
1443     SkScalar t;
1444     if (this->findYExtrema(&t)) {
1445         this->chopAt(t, dst);
1446         // now clean-up the middle, since we know t was meant to be at
1447         // an Y-extrema
1448         SkScalar value = dst[0].fPts[2].fY;
1449         dst[0].fPts[1].fY = value;
1450         dst[1].fPts[0].fY = value;
1451         dst[1].fPts[1].fY = value;
1452         return true;
1453     }
1454     return false;
1455 }
1456 
computeTightBounds(SkRect * bounds) const1457 void SkConic::computeTightBounds(SkRect* bounds) const {
1458     SkPoint pts[4];
1459     pts[0] = fPts[0];
1460     pts[1] = fPts[2];
1461     int count = 2;
1462 
1463     SkScalar t;
1464     if (this->findXExtrema(&t)) {
1465         this->evalAt(t, &pts[count++]);
1466     }
1467     if (this->findYExtrema(&t)) {
1468         this->evalAt(t, &pts[count++]);
1469     }
1470     bounds->set(pts, count);
1471 }
1472 
computeFastBounds(SkRect * bounds) const1473 void SkConic::computeFastBounds(SkRect* bounds) const {
1474     bounds->set(fPts, 3);
1475 }
1476 
findMaxCurvature(SkScalar * t) const1477 bool SkConic::findMaxCurvature(SkScalar* t) const {
1478     // TODO: Implement me
1479     return false;
1480 }
1481 
TransformW(const SkPoint pts[],SkScalar w,const SkMatrix & matrix)1482 SkScalar SkConic::TransformW(const SkPoint pts[], SkScalar w,
1483                              const SkMatrix& matrix) {
1484     if (!matrix.hasPerspective()) {
1485         return w;
1486     }
1487 
1488     SkP3D src[3], dst[3];
1489 
1490     ratquad_mapTo3D(pts, w, src);
1491 
1492     matrix.mapHomogeneousPoints(&dst[0].fX, &src[0].fX, 3);
1493 
1494     // w' = sqrt(w1*w1/w0*w2)
1495     SkScalar w0 = dst[0].fZ;
1496     SkScalar w1 = dst[1].fZ;
1497     SkScalar w2 = dst[2].fZ;
1498     w = SkScalarSqrt((w1 * w1) / (w0 * w2));
1499     return w;
1500 }
1501 
BuildUnitArc(const SkVector & uStart,const SkVector & uStop,SkRotationDirection dir,const SkMatrix * userMatrix,SkConic dst[kMaxConicsForArc])1502 int SkConic::BuildUnitArc(const SkVector& uStart, const SkVector& uStop, SkRotationDirection dir,
1503                           const SkMatrix* userMatrix, SkConic dst[kMaxConicsForArc]) {
1504     // rotate by x,y so that uStart is (1.0)
1505     SkScalar x = SkPoint::DotProduct(uStart, uStop);
1506     SkScalar y = SkPoint::CrossProduct(uStart, uStop);
1507 
1508     SkScalar absY = SkScalarAbs(y);
1509 
1510     // check for (effectively) coincident vectors
1511     // this can happen if our angle is nearly 0 or nearly 180 (y == 0)
1512     // ... we use the dot-prod to distinguish between 0 and 180 (x > 0)
1513     if (absY <= SK_ScalarNearlyZero && x > 0 && ((y >= 0 && kCW_SkRotationDirection == dir) ||
1514                                                  (y <= 0 && kCCW_SkRotationDirection == dir))) {
1515         return 0;
1516     }
1517 
1518     if (dir == kCCW_SkRotationDirection) {
1519         y = -y;
1520     }
1521 
1522     // We decide to use 1-conic per quadrant of a circle. What quadrant does [xy] lie in?
1523     //      0 == [0  .. 90)
1524     //      1 == [90 ..180)
1525     //      2 == [180..270)
1526     //      3 == [270..360)
1527     //
1528     int quadrant = 0;
1529     if (0 == y) {
1530         quadrant = 2;        // 180
1531         SkASSERT(SkScalarAbs(x + SK_Scalar1) <= SK_ScalarNearlyZero);
1532     } else if (0 == x) {
1533         SkASSERT(absY - SK_Scalar1 <= SK_ScalarNearlyZero);
1534         quadrant = y > 0 ? 1 : 3; // 90 : 270
1535     } else {
1536         if (y < 0) {
1537             quadrant += 2;
1538         }
1539         if ((x < 0) != (y < 0)) {
1540             quadrant += 1;
1541         }
1542     }
1543 
1544     const SkPoint quadrantPts[] = {
1545         { 1, 0 }, { 1, 1 }, { 0, 1 }, { -1, 1 }, { -1, 0 }, { -1, -1 }, { 0, -1 }, { 1, -1 }
1546     };
1547     const SkScalar quadrantWeight = SK_ScalarRoot2Over2;
1548 
1549     int conicCount = quadrant;
1550     for (int i = 0; i < conicCount; ++i) {
1551         dst[i].set(&quadrantPts[i * 2], quadrantWeight);
1552     }
1553 
1554     // Now compute any remaing (sub-90-degree) arc for the last conic
1555     const SkPoint finalP = { x, y };
1556     const SkPoint& lastQ = quadrantPts[quadrant * 2];  // will already be a unit-vector
1557     const SkScalar dot = SkVector::DotProduct(lastQ, finalP);
1558     SkASSERT(0 <= dot && dot <= SK_Scalar1 + SK_ScalarNearlyZero);
1559 
1560     if (dot < 1) {
1561         SkVector offCurve = { lastQ.x() + x, lastQ.y() + y };
1562         // compute the bisector vector, and then rescale to be the off-curve point.
1563         // we compute its length from cos(theta/2) = length / 1, using half-angle identity we get
1564         // length = sqrt(2 / (1 + cos(theta)). We already have cos() when to computed the dot.
1565         // This is nice, since our computed weight is cos(theta/2) as well!
1566         //
1567         const SkScalar cosThetaOver2 = SkScalarSqrt((1 + dot) / 2);
1568         offCurve.setLength(SkScalarInvert(cosThetaOver2));
1569         dst[conicCount].set(lastQ, offCurve, finalP, cosThetaOver2);
1570         conicCount += 1;
1571     }
1572 
1573     // now handle counter-clockwise and the initial unitStart rotation
1574     SkMatrix    matrix;
1575     matrix.setSinCos(uStart.fY, uStart.fX);
1576     if (dir == kCCW_SkRotationDirection) {
1577         matrix.preScale(SK_Scalar1, -SK_Scalar1);
1578     }
1579     if (userMatrix) {
1580         matrix.postConcat(*userMatrix);
1581     }
1582     for (int i = 0; i < conicCount; ++i) {
1583         matrix.mapPoints(dst[i].fPts, 3);
1584     }
1585     return conicCount;
1586 }
1587