• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* libs/graphics/sgl/SkGeometry.cpp
2 **
3 ** Copyright 2006, The Android Open Source Project
4 **
5 ** Licensed under the Apache License, Version 2.0 (the "License");
6 ** you may not use this file except in compliance with the License.
7 ** You may obtain a copy of the License at
8 **
9 **     http://www.apache.org/licenses/LICENSE-2.0
10 **
11 ** Unless required by applicable law or agreed to in writing, software
12 ** distributed under the License is distributed on an "AS IS" BASIS,
13 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 ** See the License for the specific language governing permissions and
15 ** limitations under the License.
16 */
17 
18 #include "SkGeometry.h"
19 #include "Sk64.h"
20 #include "SkMatrix.h"
21 
SkXRayCrossesLine(const SkXRay & pt,const SkPoint pts[2],bool * ambiguous)22 bool SkXRayCrossesLine(const SkXRay& pt, const SkPoint pts[2], bool* ambiguous) {
23     if (ambiguous) {
24         *ambiguous = false;
25     }
26     // Determine quick discards.
27     // Consider query line going exactly through point 0 to not
28     // intersect, for symmetry with SkXRayCrossesMonotonicCubic.
29     if (pt.fY == pts[0].fY) {
30         if (ambiguous) {
31             *ambiguous = true;
32         }
33         return false;
34     }
35     if (pt.fY < pts[0].fY && pt.fY < pts[1].fY)
36         return false;
37     if (pt.fY > pts[0].fY && pt.fY > pts[1].fY)
38         return false;
39     if (pt.fX > pts[0].fX && pt.fX > pts[1].fX)
40         return false;
41     // Determine degenerate cases
42     if (SkScalarNearlyZero(pts[0].fY - pts[1].fY))
43         return false;
44     if (SkScalarNearlyZero(pts[0].fX - pts[1].fX)) {
45         // We've already determined the query point lies within the
46         // vertical range of the line segment.
47         if (pt.fX <= pts[0].fX) {
48             if (ambiguous) {
49                 *ambiguous = (pt.fY == pts[1].fY);
50             }
51             return true;
52         }
53         return false;
54     }
55     // Ambiguity check
56     if (pt.fY == pts[1].fY) {
57         if (pt.fX <= pts[1].fX) {
58             if (ambiguous) {
59                 *ambiguous = true;
60             }
61             return true;
62         }
63         return false;
64     }
65     // Full line segment evaluation
66     SkScalar delta_y = pts[1].fY - pts[0].fY;
67     SkScalar delta_x = pts[1].fX - pts[0].fX;
68     SkScalar slope = SkScalarDiv(delta_y, delta_x);
69     SkScalar b = pts[0].fY - SkScalarMul(slope, pts[0].fX);
70     // Solve for x coordinate at y = pt.fY
71     SkScalar x = SkScalarDiv(pt.fY - b, slope);
72     return pt.fX <= x;
73 }
74 
75 /** If defined, this makes eval_quad and eval_cubic do more setup (sometimes
76     involving integer multiplies by 2 or 3, but fewer calls to SkScalarMul.
77     May also introduce overflow of fixed when we compute our setup.
78 */
79 #ifdef SK_SCALAR_IS_FIXED
80     #define DIRECT_EVAL_OF_POLYNOMIALS
81 #endif
82 
83 ////////////////////////////////////////////////////////////////////////
84 
85 #ifdef SK_SCALAR_IS_FIXED
is_not_monotonic(int a,int b,int c,int d)86     static int is_not_monotonic(int a, int b, int c, int d)
87     {
88         return (((a - b) | (b - c) | (c - d)) & ((b - a) | (c - b) | (d - c))) >> 31;
89     }
90 
is_not_monotonic(int a,int b,int c)91     static int is_not_monotonic(int a, int b, int c)
92     {
93         return (((a - b) | (b - c)) & ((b - a) | (c - b))) >> 31;
94     }
95 #else
is_not_monotonic(float a,float b,float c)96     static int is_not_monotonic(float a, float b, float c)
97     {
98         float ab = a - b;
99         float bc = b - c;
100         if (ab < 0)
101             bc = -bc;
102         return ab == 0 || bc < 0;
103     }
104 #endif
105 
106 ////////////////////////////////////////////////////////////////////////
107 
is_unit_interval(SkScalar x)108 static bool is_unit_interval(SkScalar x)
109 {
110     return x > 0 && x < SK_Scalar1;
111 }
112 
valid_unit_divide(SkScalar numer,SkScalar denom,SkScalar * ratio)113 static int valid_unit_divide(SkScalar numer, SkScalar denom, SkScalar* ratio)
114 {
115     SkASSERT(ratio);
116 
117     if (numer < 0)
118     {
119         numer = -numer;
120         denom = -denom;
121     }
122 
123     if (denom == 0 || numer == 0 || numer >= denom)
124         return 0;
125 
126     SkScalar r = SkScalarDiv(numer, denom);
127     if (SkScalarIsNaN(r)) {
128         return 0;
129     }
130     SkASSERT(r >= 0 && r < SK_Scalar1);
131     if (r == 0) // catch underflow if numer <<<< denom
132         return 0;
133     *ratio = r;
134     return 1;
135 }
136 
137 /** From Numerical Recipes in C.
138 
139     Q = -1/2 (B + sign(B) sqrt[B*B - 4*A*C])
140     x1 = Q / A
141     x2 = C / Q
142 */
SkFindUnitQuadRoots(SkScalar A,SkScalar B,SkScalar C,SkScalar roots[2])143 int SkFindUnitQuadRoots(SkScalar A, SkScalar B, SkScalar C, SkScalar roots[2])
144 {
145     SkASSERT(roots);
146 
147     if (A == 0)
148         return valid_unit_divide(-C, B, roots);
149 
150     SkScalar* r = roots;
151 
152 #ifdef SK_SCALAR_IS_FLOAT
153     float R = B*B - 4*A*C;
154     if (R < 0 || SkScalarIsNaN(R)) {  // complex roots
155         return 0;
156     }
157     R = sk_float_sqrt(R);
158 #else
159     Sk64    RR, tmp;
160 
161     RR.setMul(B,B);
162     tmp.setMul(A,C);
163     tmp.shiftLeft(2);
164     RR.sub(tmp);
165     if (RR.isNeg())
166         return 0;
167     SkFixed R = RR.getSqrt();
168 #endif
169 
170     SkScalar Q = (B < 0) ? -(B-R)/2 : -(B+R)/2;
171     r += valid_unit_divide(Q, A, r);
172     r += valid_unit_divide(C, Q, r);
173     if (r - roots == 2)
174     {
175         if (roots[0] > roots[1])
176             SkTSwap<SkScalar>(roots[0], roots[1]);
177         else if (roots[0] == roots[1])  // nearly-equal?
178             r -= 1; // skip the double root
179     }
180     return (int)(r - roots);
181 }
182 
183 #ifdef SK_SCALAR_IS_FIXED
184 /** Trim A/B/C down so that they are all <= 32bits
185     and then call SkFindUnitQuadRoots()
186 */
Sk64FindFixedQuadRoots(const Sk64 & A,const Sk64 & B,const Sk64 & C,SkFixed roots[2])187 static int Sk64FindFixedQuadRoots(const Sk64& A, const Sk64& B, const Sk64& C, SkFixed roots[2])
188 {
189     int na = A.shiftToMake32();
190     int nb = B.shiftToMake32();
191     int nc = C.shiftToMake32();
192 
193     int shift = SkMax32(na, SkMax32(nb, nc));
194     SkASSERT(shift >= 0);
195 
196     return SkFindUnitQuadRoots(A.getShiftRight(shift), B.getShiftRight(shift), C.getShiftRight(shift), roots);
197 }
198 #endif
199 
200 /////////////////////////////////////////////////////////////////////////////////////
201 /////////////////////////////////////////////////////////////////////////////////////
202 
eval_quad(const SkScalar src[],SkScalar t)203 static SkScalar eval_quad(const SkScalar src[], SkScalar t)
204 {
205     SkASSERT(src);
206     SkASSERT(t >= 0 && t <= SK_Scalar1);
207 
208 #ifdef DIRECT_EVAL_OF_POLYNOMIALS
209     SkScalar    C = src[0];
210     SkScalar    A = src[4] - 2 * src[2] + C;
211     SkScalar    B = 2 * (src[2] - C);
212     return SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C);
213 #else
214     SkScalar    ab = SkScalarInterp(src[0], src[2], t);
215     SkScalar    bc = SkScalarInterp(src[2], src[4], t);
216     return SkScalarInterp(ab, bc, t);
217 #endif
218 }
219 
eval_quad_derivative(const SkScalar src[],SkScalar t)220 static SkScalar eval_quad_derivative(const SkScalar src[], SkScalar t)
221 {
222     SkScalar A = src[4] - 2 * src[2] + src[0];
223     SkScalar B = src[2] - src[0];
224 
225     return 2 * SkScalarMulAdd(A, t, B);
226 }
227 
eval_quad_derivative_at_half(const SkScalar src[])228 static SkScalar eval_quad_derivative_at_half(const SkScalar src[])
229 {
230     SkScalar A = src[4] - 2 * src[2] + src[0];
231     SkScalar B = src[2] - src[0];
232     return A + 2 * B;
233 }
234 
SkEvalQuadAt(const SkPoint src[3],SkScalar t,SkPoint * pt,SkVector * tangent)235 void SkEvalQuadAt(const SkPoint src[3], SkScalar t, SkPoint* pt, SkVector* tangent)
236 {
237     SkASSERT(src);
238     SkASSERT(t >= 0 && t <= SK_Scalar1);
239 
240     if (pt)
241         pt->set(eval_quad(&src[0].fX, t), eval_quad(&src[0].fY, t));
242     if (tangent)
243         tangent->set(eval_quad_derivative(&src[0].fX, t),
244                      eval_quad_derivative(&src[0].fY, t));
245 }
246 
SkEvalQuadAtHalf(const SkPoint src[3],SkPoint * pt,SkVector * tangent)247 void SkEvalQuadAtHalf(const SkPoint src[3], SkPoint* pt, SkVector* tangent)
248 {
249     SkASSERT(src);
250 
251     if (pt)
252     {
253         SkScalar x01 = SkScalarAve(src[0].fX, src[1].fX);
254         SkScalar y01 = SkScalarAve(src[0].fY, src[1].fY);
255         SkScalar x12 = SkScalarAve(src[1].fX, src[2].fX);
256         SkScalar y12 = SkScalarAve(src[1].fY, src[2].fY);
257         pt->set(SkScalarAve(x01, x12), SkScalarAve(y01, y12));
258     }
259     if (tangent)
260         tangent->set(eval_quad_derivative_at_half(&src[0].fX),
261                      eval_quad_derivative_at_half(&src[0].fY));
262 }
263 
interp_quad_coords(const SkScalar * src,SkScalar * dst,SkScalar t)264 static void interp_quad_coords(const SkScalar* src, SkScalar* dst, SkScalar t)
265 {
266     SkScalar    ab = SkScalarInterp(src[0], src[2], t);
267     SkScalar    bc = SkScalarInterp(src[2], src[4], t);
268 
269     dst[0] = src[0];
270     dst[2] = ab;
271     dst[4] = SkScalarInterp(ab, bc, t);
272     dst[6] = bc;
273     dst[8] = src[4];
274 }
275 
SkChopQuadAt(const SkPoint src[3],SkPoint dst[5],SkScalar t)276 void SkChopQuadAt(const SkPoint src[3], SkPoint dst[5], SkScalar t)
277 {
278     SkASSERT(t > 0 && t < SK_Scalar1);
279 
280     interp_quad_coords(&src[0].fX, &dst[0].fX, t);
281     interp_quad_coords(&src[0].fY, &dst[0].fY, t);
282 }
283 
SkChopQuadAtHalf(const SkPoint src[3],SkPoint dst[5])284 void SkChopQuadAtHalf(const SkPoint src[3], SkPoint dst[5])
285 {
286     SkScalar x01 = SkScalarAve(src[0].fX, src[1].fX);
287     SkScalar y01 = SkScalarAve(src[0].fY, src[1].fY);
288     SkScalar x12 = SkScalarAve(src[1].fX, src[2].fX);
289     SkScalar y12 = SkScalarAve(src[1].fY, src[2].fY);
290 
291     dst[0] = src[0];
292     dst[1].set(x01, y01);
293     dst[2].set(SkScalarAve(x01, x12), SkScalarAve(y01, y12));
294     dst[3].set(x12, y12);
295     dst[4] = src[2];
296 }
297 
298 /** Quad'(t) = At + B, where
299     A = 2(a - 2b + c)
300     B = 2(b - a)
301     Solve for t, only if it fits between 0 < t < 1
302 */
SkFindQuadExtrema(SkScalar a,SkScalar b,SkScalar c,SkScalar tValue[1])303 int SkFindQuadExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar tValue[1])
304 {
305     /*  At + B == 0
306         t = -B / A
307     */
308 #ifdef SK_SCALAR_IS_FIXED
309     return is_not_monotonic(a, b, c) && valid_unit_divide(a - b, a - b - b + c, tValue);
310 #else
311     return valid_unit_divide(a - b, a - b - b + c, tValue);
312 #endif
313 }
314 
flatten_double_quad_extrema(SkScalar coords[14])315 static inline void flatten_double_quad_extrema(SkScalar coords[14])
316 {
317     coords[2] = coords[6] = coords[4];
318 }
319 
320 /*  Returns 0 for 1 quad, and 1 for two quads, either way the answer is
321  stored in dst[]. Guarantees that the 1/2 quads will be monotonic.
322  */
SkChopQuadAtYExtrema(const SkPoint src[3],SkPoint dst[5])323 int SkChopQuadAtYExtrema(const SkPoint src[3], SkPoint dst[5])
324 {
325     SkASSERT(src);
326     SkASSERT(dst);
327 
328 #if 0
329     static bool once = true;
330     if (once)
331     {
332         once = false;
333         SkPoint s[3] = { 0, 26398, 0, 26331, 0, 20621428 };
334         SkPoint d[6];
335 
336         int n = SkChopQuadAtYExtrema(s, d);
337         SkDebugf("chop=%d, Y=[%x %x %x %x %x %x]\n", n, d[0].fY, d[1].fY, d[2].fY, d[3].fY, d[4].fY, d[5].fY);
338     }
339 #endif
340 
341     SkScalar a = src[0].fY;
342     SkScalar b = src[1].fY;
343     SkScalar c = src[2].fY;
344 
345     if (is_not_monotonic(a, b, c))
346     {
347         SkScalar    tValue;
348         if (valid_unit_divide(a - b, a - b - b + c, &tValue))
349         {
350             SkChopQuadAt(src, dst, tValue);
351             flatten_double_quad_extrema(&dst[0].fY);
352             return 1;
353         }
354         // if we get here, we need to force dst to be monotonic, even though
355         // we couldn't compute a unit_divide value (probably underflow).
356         b = SkScalarAbs(a - b) < SkScalarAbs(b - c) ? a : c;
357     }
358     dst[0].set(src[0].fX, a);
359     dst[1].set(src[1].fX, b);
360     dst[2].set(src[2].fX, c);
361     return 0;
362 }
363 
364 /*  Returns 0 for 1 quad, and 1 for two quads, either way the answer is
365     stored in dst[]. Guarantees that the 1/2 quads will be monotonic.
366  */
SkChopQuadAtXExtrema(const SkPoint src[3],SkPoint dst[5])367 int SkChopQuadAtXExtrema(const SkPoint src[3], SkPoint dst[5])
368 {
369     SkASSERT(src);
370     SkASSERT(dst);
371 
372     SkScalar a = src[0].fX;
373     SkScalar b = src[1].fX;
374     SkScalar c = src[2].fX;
375 
376     if (is_not_monotonic(a, b, c)) {
377         SkScalar tValue;
378         if (valid_unit_divide(a - b, a - b - b + c, &tValue)) {
379             SkChopQuadAt(src, dst, tValue);
380             flatten_double_quad_extrema(&dst[0].fX);
381             return 1;
382         }
383         // if we get here, we need to force dst to be monotonic, even though
384         // we couldn't compute a unit_divide value (probably underflow).
385         b = SkScalarAbs(a - b) < SkScalarAbs(b - c) ? a : c;
386     }
387     dst[0].set(a, src[0].fY);
388     dst[1].set(b, src[1].fY);
389     dst[2].set(c, src[2].fY);
390     return 0;
391 }
392 
393 //  F(t)    = a (1 - t) ^ 2 + 2 b t (1 - t) + c t ^ 2
394 //  F'(t)   = 2 (b - a) + 2 (a - 2b + c) t
395 //  F''(t)  = 2 (a - 2b + c)
396 //
397 //  A = 2 (b - a)
398 //  B = 2 (a - 2b + c)
399 //
400 //  Maximum curvature for a quadratic means solving
401 //  Fx' Fx'' + Fy' Fy'' = 0
402 //
403 //  t = - (Ax Bx + Ay By) / (Bx ^ 2 + By ^ 2)
404 //
SkChopQuadAtMaxCurvature(const SkPoint src[3],SkPoint dst[5])405 int SkChopQuadAtMaxCurvature(const SkPoint src[3], SkPoint dst[5])
406 {
407     SkScalar    Ax = src[1].fX - src[0].fX;
408     SkScalar    Ay = src[1].fY - src[0].fY;
409     SkScalar    Bx = src[0].fX - src[1].fX - src[1].fX + src[2].fX;
410     SkScalar    By = src[0].fY - src[1].fY - src[1].fY + src[2].fY;
411     SkScalar    t = 0;  // 0 means don't chop
412 
413 #ifdef SK_SCALAR_IS_FLOAT
414     (void)valid_unit_divide(-(Ax * Bx + Ay * By), Bx * Bx + By * By, &t);
415 #else
416     // !!! should I use SkFloat here? seems like it
417     Sk64    numer, denom, tmp;
418 
419     numer.setMul(Ax, -Bx);
420     tmp.setMul(Ay, -By);
421     numer.add(tmp);
422 
423     if (numer.isPos())  // do nothing if numer <= 0
424     {
425         denom.setMul(Bx, Bx);
426         tmp.setMul(By, By);
427         denom.add(tmp);
428         SkASSERT(!denom.isNeg());
429         if (numer < denom)
430         {
431             t = numer.getFixedDiv(denom);
432             SkASSERT(t >= 0 && t <= SK_Fixed1);     // assert that we're numerically stable (ha!)
433             if ((unsigned)t >= SK_Fixed1)           // runtime check for numerical stability
434                 t = 0;  // ignore the chop
435         }
436     }
437 #endif
438 
439     if (t == 0)
440     {
441         memcpy(dst, src, 3 * sizeof(SkPoint));
442         return 1;
443     }
444     else
445     {
446         SkChopQuadAt(src, dst, t);
447         return 2;
448     }
449 }
450 
SkConvertQuadToCubic(const SkPoint src[3],SkPoint dst[4])451 void SkConvertQuadToCubic(const SkPoint src[3], SkPoint dst[4])
452 {
453     SkScalar two = SkIntToScalar(2);
454     SkScalar one_third = SkScalarDiv(SK_Scalar1, SkIntToScalar(3));
455     dst[0].set(src[0].fX, src[0].fY);
456     dst[1].set(
457         SkScalarMul(SkScalarMulAdd(src[1].fX, two, src[0].fX), one_third),
458         SkScalarMul(SkScalarMulAdd(src[1].fY, two, src[0].fY), one_third));
459     dst[2].set(
460         SkScalarMul(SkScalarMulAdd(src[1].fX, two, src[2].fX), one_third),
461         SkScalarMul(SkScalarMulAdd(src[1].fY, two, src[2].fY), one_third));
462     dst[3].set(src[2].fX, src[2].fY);
463 }
464 
465 ////////////////////////////////////////////////////////////////////////////////////////
466 ///// CUBICS // CUBICS // CUBICS // CUBICS // CUBICS // CUBICS // CUBICS // CUBICS /////
467 ////////////////////////////////////////////////////////////////////////////////////////
468 
get_cubic_coeff(const SkScalar pt[],SkScalar coeff[4])469 static void get_cubic_coeff(const SkScalar pt[], SkScalar coeff[4])
470 {
471     coeff[0] = pt[6] + 3*(pt[2] - pt[4]) - pt[0];
472     coeff[1] = 3*(pt[4] - pt[2] - pt[2] + pt[0]);
473     coeff[2] = 3*(pt[2] - pt[0]);
474     coeff[3] = pt[0];
475 }
476 
SkGetCubicCoeff(const SkPoint pts[4],SkScalar cx[4],SkScalar cy[4])477 void SkGetCubicCoeff(const SkPoint pts[4], SkScalar cx[4], SkScalar cy[4])
478 {
479     SkASSERT(pts);
480 
481     if (cx)
482         get_cubic_coeff(&pts[0].fX, cx);
483     if (cy)
484         get_cubic_coeff(&pts[0].fY, cy);
485 }
486 
eval_cubic(const SkScalar src[],SkScalar t)487 static SkScalar eval_cubic(const SkScalar src[], SkScalar t)
488 {
489     SkASSERT(src);
490     SkASSERT(t >= 0 && t <= SK_Scalar1);
491 
492     if (t == 0)
493         return src[0];
494 
495 #ifdef DIRECT_EVAL_OF_POLYNOMIALS
496     SkScalar D = src[0];
497     SkScalar A = src[6] + 3*(src[2] - src[4]) - D;
498     SkScalar B = 3*(src[4] - src[2] - src[2] + D);
499     SkScalar C = 3*(src[2] - D);
500 
501     return SkScalarMulAdd(SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C), t, D);
502 #else
503     SkScalar    ab = SkScalarInterp(src[0], src[2], t);
504     SkScalar    bc = SkScalarInterp(src[2], src[4], t);
505     SkScalar    cd = SkScalarInterp(src[4], src[6], t);
506     SkScalar    abc = SkScalarInterp(ab, bc, t);
507     SkScalar    bcd = SkScalarInterp(bc, cd, t);
508     return SkScalarInterp(abc, bcd, t);
509 #endif
510 }
511 
512 /** return At^2 + Bt + C
513 */
eval_quadratic(SkScalar A,SkScalar B,SkScalar C,SkScalar t)514 static SkScalar eval_quadratic(SkScalar A, SkScalar B, SkScalar C, SkScalar t)
515 {
516     SkASSERT(t >= 0 && t <= SK_Scalar1);
517 
518     return SkScalarMulAdd(SkScalarMulAdd(A, t, B), t, C);
519 }
520 
eval_cubic_derivative(const SkScalar src[],SkScalar t)521 static SkScalar eval_cubic_derivative(const SkScalar src[], SkScalar t)
522 {
523     SkScalar A = src[6] + 3*(src[2] - src[4]) - src[0];
524     SkScalar B = 2*(src[4] - 2 * src[2] + src[0]);
525     SkScalar C = src[2] - src[0];
526 
527     return eval_quadratic(A, B, C, t);
528 }
529 
eval_cubic_2ndDerivative(const SkScalar src[],SkScalar t)530 static SkScalar eval_cubic_2ndDerivative(const SkScalar src[], SkScalar t)
531 {
532     SkScalar A = src[6] + 3*(src[2] - src[4]) - src[0];
533     SkScalar B = src[4] - 2 * src[2] + src[0];
534 
535     return SkScalarMulAdd(A, t, B);
536 }
537 
SkEvalCubicAt(const SkPoint src[4],SkScalar t,SkPoint * loc,SkVector * tangent,SkVector * curvature)538 void SkEvalCubicAt(const SkPoint src[4], SkScalar t, SkPoint* loc, SkVector* tangent, SkVector* curvature)
539 {
540     SkASSERT(src);
541     SkASSERT(t >= 0 && t <= SK_Scalar1);
542 
543     if (loc)
544         loc->set(eval_cubic(&src[0].fX, t), eval_cubic(&src[0].fY, t));
545     if (tangent)
546         tangent->set(eval_cubic_derivative(&src[0].fX, t),
547                      eval_cubic_derivative(&src[0].fY, t));
548     if (curvature)
549         curvature->set(eval_cubic_2ndDerivative(&src[0].fX, t),
550                        eval_cubic_2ndDerivative(&src[0].fY, t));
551 }
552 
553 /** Cubic'(t) = At^2 + Bt + C, where
554     A = 3(-a + 3(b - c) + d)
555     B = 6(a - 2b + c)
556     C = 3(b - a)
557     Solve for t, keeping only those that fit betwee 0 < t < 1
558 */
SkFindCubicExtrema(SkScalar a,SkScalar b,SkScalar c,SkScalar d,SkScalar tValues[2])559 int SkFindCubicExtrema(SkScalar a, SkScalar b, SkScalar c, SkScalar d, SkScalar tValues[2])
560 {
561 #ifdef SK_SCALAR_IS_FIXED
562     if (!is_not_monotonic(a, b, c, d))
563         return 0;
564 #endif
565 
566     // we divide A,B,C by 3 to simplify
567     SkScalar A = d - a + 3*(b - c);
568     SkScalar B = 2*(a - b - b + c);
569     SkScalar C = b - a;
570 
571     return SkFindUnitQuadRoots(A, B, C, tValues);
572 }
573 
interp_cubic_coords(const SkScalar * src,SkScalar * dst,SkScalar t)574 static void interp_cubic_coords(const SkScalar* src, SkScalar* dst, SkScalar t)
575 {
576     SkScalar    ab = SkScalarInterp(src[0], src[2], t);
577     SkScalar    bc = SkScalarInterp(src[2], src[4], t);
578     SkScalar    cd = SkScalarInterp(src[4], src[6], t);
579     SkScalar    abc = SkScalarInterp(ab, bc, t);
580     SkScalar    bcd = SkScalarInterp(bc, cd, t);
581     SkScalar    abcd = SkScalarInterp(abc, bcd, t);
582 
583     dst[0] = src[0];
584     dst[2] = ab;
585     dst[4] = abc;
586     dst[6] = abcd;
587     dst[8] = bcd;
588     dst[10] = cd;
589     dst[12] = src[6];
590 }
591 
SkChopCubicAt(const SkPoint src[4],SkPoint dst[7],SkScalar t)592 void SkChopCubicAt(const SkPoint src[4], SkPoint dst[7], SkScalar t)
593 {
594     SkASSERT(t > 0 && t < SK_Scalar1);
595 
596     interp_cubic_coords(&src[0].fX, &dst[0].fX, t);
597     interp_cubic_coords(&src[0].fY, &dst[0].fY, t);
598 }
599 
600 /*  http://code.google.com/p/skia/issues/detail?id=32
601 
602     This test code would fail when we didn't check the return result of
603     valid_unit_divide in SkChopCubicAt(... tValues[], int roots). The reason is
604     that after the first chop, the parameters to valid_unit_divide are equal
605     (thanks to finite float precision and rounding in the subtracts). Thus
606     even though the 2nd tValue looks < 1.0, after we renormalize it, we end
607     up with 1.0, hence the need to check and just return the last cubic as
608     a degenerate clump of 4 points in the sampe place.
609 
610     static void test_cubic() {
611         SkPoint src[4] = {
612             { 556.25000, 523.03003 },
613             { 556.23999, 522.96002 },
614             { 556.21997, 522.89001 },
615             { 556.21997, 522.82001 }
616         };
617         SkPoint dst[10];
618         SkScalar tval[] = { 0.33333334f, 0.99999994f };
619         SkChopCubicAt(src, dst, tval, 2);
620     }
621  */
622 
SkChopCubicAt(const SkPoint src[4],SkPoint dst[],const SkScalar tValues[],int roots)623 void SkChopCubicAt(const SkPoint src[4], SkPoint dst[], const SkScalar tValues[], int roots)
624 {
625 #ifdef SK_DEBUG
626     {
627         for (int i = 0; i < roots - 1; i++)
628         {
629             SkASSERT(is_unit_interval(tValues[i]));
630             SkASSERT(is_unit_interval(tValues[i+1]));
631             SkASSERT(tValues[i] < tValues[i+1]);
632         }
633     }
634 #endif
635 
636     if (dst)
637     {
638         if (roots == 0) // nothing to chop
639             memcpy(dst, src, 4*sizeof(SkPoint));
640         else
641         {
642             SkScalar    t = tValues[0];
643             SkPoint     tmp[4];
644 
645             for (int i = 0; i < roots; i++)
646             {
647                 SkChopCubicAt(src, dst, t);
648                 if (i == roots - 1)
649                     break;
650 
651                 dst += 3;
652                 // have src point to the remaining cubic (after the chop)
653                 memcpy(tmp, dst, 4 * sizeof(SkPoint));
654                 src = tmp;
655 
656                 // watch out in case the renormalized t isn't in range
657                 if (!valid_unit_divide(tValues[i+1] - tValues[i],
658                                        SK_Scalar1 - tValues[i], &t)) {
659                     // if we can't, just create a degenerate cubic
660                     dst[4] = dst[5] = dst[6] = src[3];
661                     break;
662                 }
663             }
664         }
665     }
666 }
667 
SkChopCubicAtHalf(const SkPoint src[4],SkPoint dst[7])668 void SkChopCubicAtHalf(const SkPoint src[4], SkPoint dst[7])
669 {
670     SkScalar x01 = SkScalarAve(src[0].fX, src[1].fX);
671     SkScalar y01 = SkScalarAve(src[0].fY, src[1].fY);
672     SkScalar x12 = SkScalarAve(src[1].fX, src[2].fX);
673     SkScalar y12 = SkScalarAve(src[1].fY, src[2].fY);
674     SkScalar x23 = SkScalarAve(src[2].fX, src[3].fX);
675     SkScalar y23 = SkScalarAve(src[2].fY, src[3].fY);
676 
677     SkScalar x012 = SkScalarAve(x01, x12);
678     SkScalar y012 = SkScalarAve(y01, y12);
679     SkScalar x123 = SkScalarAve(x12, x23);
680     SkScalar y123 = SkScalarAve(y12, y23);
681 
682     dst[0] = src[0];
683     dst[1].set(x01, y01);
684     dst[2].set(x012, y012);
685     dst[3].set(SkScalarAve(x012, x123), SkScalarAve(y012, y123));
686     dst[4].set(x123, y123);
687     dst[5].set(x23, y23);
688     dst[6] = src[3];
689 }
690 
flatten_double_cubic_extrema(SkScalar coords[14])691 static void flatten_double_cubic_extrema(SkScalar coords[14])
692 {
693     coords[4] = coords[8] = coords[6];
694 }
695 
696 /** Given 4 points on a cubic bezier, chop it into 1, 2, 3 beziers such that
697     the resulting beziers are monotonic in Y. This is called by the scan converter.
698     Depending on what is returned, dst[] is treated as follows
699     0   dst[0..3] is the original cubic
700     1   dst[0..3] and dst[3..6] are the two new cubics
701     2   dst[0..3], dst[3..6], dst[6..9] are the three new cubics
702     If dst == null, it is ignored and only the count is returned.
703 */
SkChopCubicAtYExtrema(const SkPoint src[4],SkPoint dst[10])704 int SkChopCubicAtYExtrema(const SkPoint src[4], SkPoint dst[10]) {
705     SkScalar    tValues[2];
706     int         roots = SkFindCubicExtrema(src[0].fY, src[1].fY, src[2].fY,
707                                            src[3].fY, tValues);
708 
709     SkChopCubicAt(src, dst, tValues, roots);
710     if (dst && roots > 0) {
711         // we do some cleanup to ensure our Y extrema are flat
712         flatten_double_cubic_extrema(&dst[0].fY);
713         if (roots == 2) {
714             flatten_double_cubic_extrema(&dst[3].fY);
715         }
716     }
717     return roots;
718 }
719 
SkChopCubicAtXExtrema(const SkPoint src[4],SkPoint dst[10])720 int SkChopCubicAtXExtrema(const SkPoint src[4], SkPoint dst[10]) {
721     SkScalar    tValues[2];
722     int         roots = SkFindCubicExtrema(src[0].fX, src[1].fX, src[2].fX,
723                                            src[3].fX, tValues);
724 
725     SkChopCubicAt(src, dst, tValues, roots);
726     if (dst && roots > 0) {
727         // we do some cleanup to ensure our Y extrema are flat
728         flatten_double_cubic_extrema(&dst[0].fX);
729         if (roots == 2) {
730             flatten_double_cubic_extrema(&dst[3].fX);
731         }
732     }
733     return roots;
734 }
735 
736 /** http://www.faculty.idc.ac.il/arik/quality/appendixA.html
737 
738     Inflection means that curvature is zero.
739     Curvature is [F' x F''] / [F'^3]
740     So we solve F'x X F''y - F'y X F''y == 0
741     After some canceling of the cubic term, we get
742     A = b - a
743     B = c - 2b + a
744     C = d - 3c + 3b - a
745     (BxCy - ByCx)t^2 + (AxCy - AyCx)t + AxBy - AyBx == 0
746 */
SkFindCubicInflections(const SkPoint src[4],SkScalar tValues[])747 int SkFindCubicInflections(const SkPoint src[4], SkScalar tValues[])
748 {
749     SkScalar    Ax = src[1].fX - src[0].fX;
750     SkScalar    Ay = src[1].fY - src[0].fY;
751     SkScalar    Bx = src[2].fX - 2 * src[1].fX + src[0].fX;
752     SkScalar    By = src[2].fY - 2 * src[1].fY + src[0].fY;
753     SkScalar    Cx = src[3].fX + 3 * (src[1].fX - src[2].fX) - src[0].fX;
754     SkScalar    Cy = src[3].fY + 3 * (src[1].fY - src[2].fY) - src[0].fY;
755     int         count;
756 
757 #ifdef SK_SCALAR_IS_FLOAT
758     count = SkFindUnitQuadRoots(Bx*Cy - By*Cx, Ax*Cy - Ay*Cx, Ax*By - Ay*Bx, tValues);
759 #else
760     Sk64    A, B, C, tmp;
761 
762     A.setMul(Bx, Cy);
763     tmp.setMul(By, Cx);
764     A.sub(tmp);
765 
766     B.setMul(Ax, Cy);
767     tmp.setMul(Ay, Cx);
768     B.sub(tmp);
769 
770     C.setMul(Ax, By);
771     tmp.setMul(Ay, Bx);
772     C.sub(tmp);
773 
774     count = Sk64FindFixedQuadRoots(A, B, C, tValues);
775 #endif
776 
777     return count;
778 }
779 
SkChopCubicAtInflections(const SkPoint src[],SkPoint dst[10])780 int SkChopCubicAtInflections(const SkPoint src[], SkPoint dst[10])
781 {
782     SkScalar    tValues[2];
783     int         count = SkFindCubicInflections(src, tValues);
784 
785     if (dst)
786     {
787         if (count == 0)
788             memcpy(dst, src, 4 * sizeof(SkPoint));
789         else
790             SkChopCubicAt(src, dst, tValues, count);
791     }
792     return count + 1;
793 }
794 
bubble_sort(T array[],int count)795 template <typename T> void bubble_sort(T array[], int count)
796 {
797     for (int i = count - 1; i > 0; --i)
798         for (int j = i; j > 0; --j)
799             if (array[j] < array[j-1])
800             {
801                 T   tmp(array[j]);
802                 array[j] = array[j-1];
803                 array[j-1] = tmp;
804             }
805 }
806 
807 #include "SkFP.h"
808 
809 // newton refinement
810 #if 0
811 static SkScalar refine_cubic_root(const SkFP coeff[4], SkScalar root)
812 {
813     //  x1 = x0 - f(t) / f'(t)
814 
815     SkFP    T = SkScalarToFloat(root);
816     SkFP    N, D;
817 
818     // f' = 3*coeff[0]*T^2 + 2*coeff[1]*T + coeff[2]
819     D = SkFPMul(SkFPMul(coeff[0], SkFPMul(T,T)), 3);
820     D = SkFPAdd(D, SkFPMulInt(SkFPMul(coeff[1], T), 2));
821     D = SkFPAdd(D, coeff[2]);
822 
823     if (D == 0)
824         return root;
825 
826     // f = coeff[0]*T^3 + coeff[1]*T^2 + coeff[2]*T + coeff[3]
827     N = SkFPMul(SkFPMul(SkFPMul(T, T), T), coeff[0]);
828     N = SkFPAdd(N, SkFPMul(SkFPMul(T, T), coeff[1]));
829     N = SkFPAdd(N, SkFPMul(T, coeff[2]));
830     N = SkFPAdd(N, coeff[3]);
831 
832     if (N)
833     {
834         SkScalar delta = SkFPToScalar(SkFPDiv(N, D));
835 
836         if (delta)
837             root -= delta;
838     }
839     return root;
840 }
841 #endif
842 
843 #if defined _WIN32 && _MSC_VER >= 1300  && defined SK_SCALAR_IS_FIXED // disable warning : unreachable code if building fixed point for windows desktop
844 #pragma warning ( disable : 4702 )
845 #endif
846 
847 /*  Solve coeff(t) == 0, returning the number of roots that
848     lie withing 0 < t < 1.
849     coeff[0]t^3 + coeff[1]t^2 + coeff[2]t + coeff[3]
850 */
solve_cubic_polynomial(const SkFP coeff[4],SkScalar tValues[3])851 static int solve_cubic_polynomial(const SkFP coeff[4], SkScalar tValues[3])
852 {
853 #ifndef SK_SCALAR_IS_FLOAT
854     return 0;   // this is not yet implemented for software float
855 #endif
856 
857     if (SkScalarNearlyZero(coeff[0]))   // we're just a quadratic
858     {
859         return SkFindUnitQuadRoots(coeff[1], coeff[2], coeff[3], tValues);
860     }
861 
862     SkFP    a, b, c, Q, R;
863 
864     {
865         SkASSERT(coeff[0] != 0);
866 
867         SkFP inva = SkFPInvert(coeff[0]);
868         a = SkFPMul(coeff[1], inva);
869         b = SkFPMul(coeff[2], inva);
870         c = SkFPMul(coeff[3], inva);
871     }
872     Q = SkFPDivInt(SkFPSub(SkFPMul(a,a), SkFPMulInt(b, 3)), 9);
873 //  R = (2*a*a*a - 9*a*b + 27*c) / 54;
874     R = SkFPMulInt(SkFPMul(SkFPMul(a, a), a), 2);
875     R = SkFPSub(R, SkFPMulInt(SkFPMul(a, b), 9));
876     R = SkFPAdd(R, SkFPMulInt(c, 27));
877     R = SkFPDivInt(R, 54);
878 
879     SkFP Q3 = SkFPMul(SkFPMul(Q, Q), Q);
880     SkFP R2MinusQ3 = SkFPSub(SkFPMul(R,R), Q3);
881     SkFP adiv3 = SkFPDivInt(a, 3);
882 
883     SkScalar*   roots = tValues;
884     SkScalar    r;
885 
886     if (SkFPLT(R2MinusQ3, 0))   // we have 3 real roots
887     {
888 #ifdef SK_SCALAR_IS_FLOAT
889         float theta = sk_float_acos(R / sk_float_sqrt(Q3));
890         float neg2RootQ = -2 * sk_float_sqrt(Q);
891 
892         r = neg2RootQ * sk_float_cos(theta/3) - adiv3;
893         if (is_unit_interval(r))
894             *roots++ = r;
895 
896         r = neg2RootQ * sk_float_cos((theta + 2*SK_ScalarPI)/3) - adiv3;
897         if (is_unit_interval(r))
898             *roots++ = r;
899 
900         r = neg2RootQ * sk_float_cos((theta - 2*SK_ScalarPI)/3) - adiv3;
901         if (is_unit_interval(r))
902             *roots++ = r;
903 
904         // now sort the roots
905         bubble_sort(tValues, (int)(roots - tValues));
906 #endif
907     }
908     else                // we have 1 real root
909     {
910         SkFP A = SkFPAdd(SkFPAbs(R), SkFPSqrt(R2MinusQ3));
911         A = SkFPCubeRoot(A);
912         if (SkFPGT(R, 0))
913             A = SkFPNeg(A);
914 
915         if (A != 0)
916             A = SkFPAdd(A, SkFPDiv(Q, A));
917         r = SkFPToScalar(SkFPSub(A, adiv3));
918         if (is_unit_interval(r))
919             *roots++ = r;
920     }
921 
922     return (int)(roots - tValues);
923 }
924 
925 /*  Looking for F' dot F'' == 0
926 
927     A = b - a
928     B = c - 2b + a
929     C = d - 3c + 3b - a
930 
931     F' = 3Ct^2 + 6Bt + 3A
932     F'' = 6Ct + 6B
933 
934     F' dot F'' -> CCt^3 + 3BCt^2 + (2BB + CA)t + AB
935 */
formulate_F1DotF2(const SkScalar src[],SkFP coeff[4])936 static void formulate_F1DotF2(const SkScalar src[], SkFP coeff[4])
937 {
938     SkScalar    a = src[2] - src[0];
939     SkScalar    b = src[4] - 2 * src[2] + src[0];
940     SkScalar    c = src[6] + 3 * (src[2] - src[4]) - src[0];
941 
942     SkFP    A = SkScalarToFP(a);
943     SkFP    B = SkScalarToFP(b);
944     SkFP    C = SkScalarToFP(c);
945 
946     coeff[0] = SkFPMul(C, C);
947     coeff[1] = SkFPMulInt(SkFPMul(B, C), 3);
948     coeff[2] = SkFPMulInt(SkFPMul(B, B), 2);
949     coeff[2] = SkFPAdd(coeff[2], SkFPMul(C, A));
950     coeff[3] = SkFPMul(A, B);
951 }
952 
953 // EXPERIMENTAL: can set this to zero to accept all t-values 0 < t < 1
954 //#define kMinTValueForChopping (SK_Scalar1 / 256)
955 #define kMinTValueForChopping   0
956 
957 /*  Looking for F' dot F'' == 0
958 
959     A = b - a
960     B = c - 2b + a
961     C = d - 3c + 3b - a
962 
963     F' = 3Ct^2 + 6Bt + 3A
964     F'' = 6Ct + 6B
965 
966     F' dot F'' -> CCt^3 + 3BCt^2 + (2BB + CA)t + AB
967 */
SkFindCubicMaxCurvature(const SkPoint src[4],SkScalar tValues[3])968 int SkFindCubicMaxCurvature(const SkPoint src[4], SkScalar tValues[3])
969 {
970     SkFP    coeffX[4], coeffY[4];
971     int     i;
972 
973     formulate_F1DotF2(&src[0].fX, coeffX);
974     formulate_F1DotF2(&src[0].fY, coeffY);
975 
976     for (i = 0; i < 4; i++)
977         coeffX[i] = SkFPAdd(coeffX[i],coeffY[i]);
978 
979     SkScalar    t[3];
980     int         count = solve_cubic_polynomial(coeffX, t);
981     int         maxCount = 0;
982 
983     // now remove extrema where the curvature is zero (mins)
984     // !!!! need a test for this !!!!
985     for (i = 0; i < count; i++)
986     {
987         // if (not_min_curvature())
988         if (t[i] > kMinTValueForChopping && t[i] < SK_Scalar1 - kMinTValueForChopping)
989             tValues[maxCount++] = t[i];
990     }
991     return maxCount;
992 }
993 
SkChopCubicAtMaxCurvature(const SkPoint src[4],SkPoint dst[13],SkScalar tValues[3])994 int SkChopCubicAtMaxCurvature(const SkPoint src[4], SkPoint dst[13], SkScalar tValues[3])
995 {
996     SkScalar    t_storage[3];
997 
998     if (tValues == NULL)
999         tValues = t_storage;
1000 
1001     int count = SkFindCubicMaxCurvature(src, tValues);
1002 
1003     if (dst)
1004     {
1005         if (count == 0)
1006             memcpy(dst, src, 4 * sizeof(SkPoint));
1007         else
1008             SkChopCubicAt(src, dst, tValues, count);
1009     }
1010     return count + 1;
1011 }
1012 
SkXRayCrossesMonotonicCubic(const SkXRay & pt,const SkPoint cubic[4],bool * ambiguous)1013 bool SkXRayCrossesMonotonicCubic(const SkXRay& pt, const SkPoint cubic[4], bool* ambiguous) {
1014     if (ambiguous) {
1015         *ambiguous = false;
1016     }
1017 
1018     // Find the minimum and maximum y of the extrema, which are the
1019     // first and last points since this cubic is monotonic
1020     SkScalar min_y = SkMinScalar(cubic[0].fY, cubic[3].fY);
1021     SkScalar max_y = SkMaxScalar(cubic[0].fY, cubic[3].fY);
1022 
1023     if (pt.fY == cubic[0].fY
1024         || pt.fY < min_y
1025         || pt.fY > max_y) {
1026         // The query line definitely does not cross the curve
1027         if (ambiguous) {
1028             *ambiguous = (pt.fY == cubic[0].fY);
1029         }
1030         return false;
1031     }
1032 
1033     bool pt_at_extremum = (pt.fY == cubic[3].fY);
1034 
1035     SkScalar min_x =
1036         SkMinScalar(
1037             SkMinScalar(
1038                 SkMinScalar(cubic[0].fX, cubic[1].fX),
1039                 cubic[2].fX),
1040             cubic[3].fX);
1041     if (pt.fX < min_x) {
1042         // The query line definitely crosses the curve
1043         if (ambiguous) {
1044             *ambiguous = pt_at_extremum;
1045         }
1046         return true;
1047     }
1048 
1049     SkScalar max_x =
1050         SkMaxScalar(
1051             SkMaxScalar(
1052                 SkMaxScalar(cubic[0].fX, cubic[1].fX),
1053                 cubic[2].fX),
1054             cubic[3].fX);
1055     if (pt.fX > max_x) {
1056         // The query line definitely does not cross the curve
1057         return false;
1058     }
1059 
1060     // Do a binary search to find the parameter value which makes y as
1061     // close as possible to the query point. See whether the query
1062     // line's origin is to the left of the associated x coordinate.
1063 
1064     // kMaxIter is chosen as the number of mantissa bits for a float,
1065     // since there's no way we are going to get more precision by
1066     // iterating more times than that.
1067     const int kMaxIter = 23;
1068     SkPoint eval;
1069     int iter = 0;
1070     SkScalar upper_t;
1071     SkScalar lower_t;
1072     // Need to invert direction of t parameter if cubic goes up
1073     // instead of down
1074     if (cubic[3].fY > cubic[0].fY) {
1075         upper_t = SK_Scalar1;
1076         lower_t = SkFloatToScalar(0);
1077     } else {
1078         upper_t = SkFloatToScalar(0);
1079         lower_t = SK_Scalar1;
1080     }
1081     do {
1082         SkScalar t = SkScalarAve(upper_t, lower_t);
1083         SkEvalCubicAt(cubic, t, &eval, NULL, NULL);
1084         if (pt.fY > eval.fY) {
1085             lower_t = t;
1086         } else {
1087             upper_t = t;
1088         }
1089     } while (++iter < kMaxIter
1090              && !SkScalarNearlyZero(eval.fY - pt.fY));
1091     if (pt.fX <= eval.fX) {
1092         if (ambiguous) {
1093             *ambiguous = pt_at_extremum;
1094         }
1095         return true;
1096     }
1097     return false;
1098 }
1099 
SkNumXRayCrossingsForCubic(const SkXRay & pt,const SkPoint cubic[4],bool * ambiguous)1100 int SkNumXRayCrossingsForCubic(const SkXRay& pt, const SkPoint cubic[4], bool* ambiguous) {
1101     int num_crossings = 0;
1102     SkPoint monotonic_cubics[10];
1103     int num_monotonic_cubics = SkChopCubicAtYExtrema(cubic, monotonic_cubics);
1104     if (ambiguous) {
1105         *ambiguous = false;
1106     }
1107     bool locally_ambiguous;
1108     if (SkXRayCrossesMonotonicCubic(pt, &monotonic_cubics[0], &locally_ambiguous))
1109         ++num_crossings;
1110     if (ambiguous) {
1111         *ambiguous |= locally_ambiguous;
1112     }
1113     if (num_monotonic_cubics > 0)
1114         if (SkXRayCrossesMonotonicCubic(pt, &monotonic_cubics[3], &locally_ambiguous))
1115             ++num_crossings;
1116     if (ambiguous) {
1117         *ambiguous |= locally_ambiguous;
1118     }
1119     if (num_monotonic_cubics > 1)
1120         if (SkXRayCrossesMonotonicCubic(pt, &monotonic_cubics[6], &locally_ambiguous))
1121             ++num_crossings;
1122     if (ambiguous) {
1123         *ambiguous |= locally_ambiguous;
1124     }
1125     return num_crossings;
1126 }
1127 
1128 ////////////////////////////////////////////////////////////////////////////////
1129 
1130 /*  Find t value for quadratic [a, b, c] = d.
1131     Return 0 if there is no solution within [0, 1)
1132 */
quad_solve(SkScalar a,SkScalar b,SkScalar c,SkScalar d)1133 static SkScalar quad_solve(SkScalar a, SkScalar b, SkScalar c, SkScalar d)
1134 {
1135     // At^2 + Bt + C = d
1136     SkScalar A = a - 2 * b + c;
1137     SkScalar B = 2 * (b - a);
1138     SkScalar C = a - d;
1139 
1140     SkScalar    roots[2];
1141     int         count = SkFindUnitQuadRoots(A, B, C, roots);
1142 
1143     SkASSERT(count <= 1);
1144     return count == 1 ? roots[0] : 0;
1145 }
1146 
1147 /*  given a quad-curve and a point (x,y), chop the quad at that point and return
1148     the new quad's offCurve point. Should only return false if the computed pos
1149     is the start of the curve (i.e. root == 0)
1150 */
quad_pt2OffCurve(const SkPoint quad[3],SkScalar x,SkScalar y,SkPoint * offCurve)1151 static bool quad_pt2OffCurve(const SkPoint quad[3], SkScalar x, SkScalar y, SkPoint* offCurve)
1152 {
1153     const SkScalar* base;
1154     SkScalar        value;
1155 
1156     if (SkScalarAbs(x) < SkScalarAbs(y)) {
1157         base = &quad[0].fX;
1158         value = x;
1159     } else {
1160         base = &quad[0].fY;
1161         value = y;
1162     }
1163 
1164     // note: this returns 0 if it thinks value is out of range, meaning the
1165     // root might return something outside of [0, 1)
1166     SkScalar t = quad_solve(base[0], base[2], base[4], value);
1167 
1168     if (t > 0)
1169     {
1170         SkPoint tmp[5];
1171         SkChopQuadAt(quad, tmp, t);
1172         *offCurve = tmp[1];
1173         return true;
1174     } else {
1175         /*  t == 0 means either the value triggered a root outside of [0, 1)
1176             For our purposes, we can ignore the <= 0 roots, but we want to
1177             catch the >= 1 roots (which given our caller, will basically mean
1178             a root of 1, give-or-take numerical instability). If we are in the
1179             >= 1 case, return the existing offCurve point.
1180 
1181             The test below checks to see if we are close to the "end" of the
1182             curve (near base[4]). Rather than specifying a tolerance, I just
1183             check to see if value is on to the right/left of the middle point
1184             (depending on the direction/sign of the end points).
1185         */
1186         if ((base[0] < base[4] && value > base[2]) ||
1187             (base[0] > base[4] && value < base[2]))   // should root have been 1
1188         {
1189             *offCurve = quad[1];
1190             return true;
1191         }
1192     }
1193     return false;
1194 }
1195 
1196 static const SkPoint gQuadCirclePts[kSkBuildQuadArcStorage] = {
1197     { SK_Scalar1,           0               },
1198     { SK_Scalar1,           SK_ScalarTanPIOver8 },
1199     { SK_ScalarRoot2Over2,  SK_ScalarRoot2Over2 },
1200     { SK_ScalarTanPIOver8,  SK_Scalar1          },
1201 
1202     { 0,                    SK_Scalar1      },
1203     { -SK_ScalarTanPIOver8, SK_Scalar1  },
1204     { -SK_ScalarRoot2Over2, SK_ScalarRoot2Over2 },
1205     { -SK_Scalar1,          SK_ScalarTanPIOver8 },
1206 
1207     { -SK_Scalar1,          0               },
1208     { -SK_Scalar1,          -SK_ScalarTanPIOver8    },
1209     { -SK_ScalarRoot2Over2, -SK_ScalarRoot2Over2    },
1210     { -SK_ScalarTanPIOver8, -SK_Scalar1     },
1211 
1212     { 0,                    -SK_Scalar1     },
1213     { SK_ScalarTanPIOver8,  -SK_Scalar1     },
1214     { SK_ScalarRoot2Over2,  -SK_ScalarRoot2Over2    },
1215     { SK_Scalar1,           -SK_ScalarTanPIOver8    },
1216 
1217     { SK_Scalar1,           0   }
1218 };
1219 
SkBuildQuadArc(const SkVector & uStart,const SkVector & uStop,SkRotationDirection dir,const SkMatrix * userMatrix,SkPoint quadPoints[])1220 int SkBuildQuadArc(const SkVector& uStart, const SkVector& uStop,
1221                    SkRotationDirection dir, const SkMatrix* userMatrix,
1222                    SkPoint quadPoints[])
1223 {
1224     // rotate by x,y so that uStart is (1.0)
1225     SkScalar x = SkPoint::DotProduct(uStart, uStop);
1226     SkScalar y = SkPoint::CrossProduct(uStart, uStop);
1227 
1228     SkScalar absX = SkScalarAbs(x);
1229     SkScalar absY = SkScalarAbs(y);
1230 
1231     int pointCount;
1232 
1233     // check for (effectively) coincident vectors
1234     // this can happen if our angle is nearly 0 or nearly 180 (y == 0)
1235     // ... we use the dot-prod to distinguish between 0 and 180 (x > 0)
1236     if (absY <= SK_ScalarNearlyZero && x > 0 &&
1237         ((y >= 0 && kCW_SkRotationDirection == dir) ||
1238          (y <= 0 && kCCW_SkRotationDirection == dir))) {
1239 
1240         // just return the start-point
1241         quadPoints[0].set(SK_Scalar1, 0);
1242         pointCount = 1;
1243     } else {
1244         if (dir == kCCW_SkRotationDirection)
1245             y = -y;
1246 
1247         // what octant (quadratic curve) is [xy] in?
1248         int oct = 0;
1249         bool sameSign = true;
1250 
1251         if (0 == y)
1252         {
1253             oct = 4;        // 180
1254             SkASSERT(SkScalarAbs(x + SK_Scalar1) <= SK_ScalarNearlyZero);
1255         }
1256         else if (0 == x)
1257         {
1258             SkASSERT(absY - SK_Scalar1 <= SK_ScalarNearlyZero);
1259             if (y > 0)
1260                 oct = 2;    // 90
1261             else
1262                 oct = 6;    // 270
1263         }
1264         else
1265         {
1266             if (y < 0)
1267                 oct += 4;
1268             if ((x < 0) != (y < 0))
1269             {
1270                 oct += 2;
1271                 sameSign = false;
1272             }
1273             if ((absX < absY) == sameSign)
1274                 oct += 1;
1275         }
1276 
1277         int wholeCount = oct << 1;
1278         memcpy(quadPoints, gQuadCirclePts, (wholeCount + 1) * sizeof(SkPoint));
1279 
1280         const SkPoint* arc = &gQuadCirclePts[wholeCount];
1281         if (quad_pt2OffCurve(arc, x, y, &quadPoints[wholeCount + 1]))
1282         {
1283             quadPoints[wholeCount + 2].set(x, y);
1284             wholeCount += 2;
1285         }
1286         pointCount = wholeCount + 1;
1287     }
1288 
1289     // now handle counter-clockwise and the initial unitStart rotation
1290     SkMatrix    matrix;
1291     matrix.setSinCos(uStart.fY, uStart.fX);
1292     if (dir == kCCW_SkRotationDirection) {
1293         matrix.preScale(SK_Scalar1, -SK_Scalar1);
1294     }
1295     if (userMatrix) {
1296         matrix.postConcat(*userMatrix);
1297     }
1298     matrix.mapPoints(quadPoints, pointCount);
1299     return pointCount;
1300 }
1301 
1302