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