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