Home | History | Annotate | Download | only in core
      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 bool 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 
     84 static bool is_unit_interval(SkScalar x)
     85 {
     86     return x > 0 && x < SK_Scalar1;
     87 }
     88 
     89 static 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 */
    119 int 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 */
    163 static 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 
    179 static 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 
    196 static 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 
    204 static 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 
    211 void 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 
    223 void 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 
    240 static 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 
    252 void 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 
    260 void 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 */
    279 int 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 
    291 static 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  */
    299 int 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  */
    343 int 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 //
    381 int 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 
    427 void 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 
    445 static 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 
    453 void 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 
    463 static 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 */
    490 static 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 
    497 static 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 
    506 static 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 
    514 void 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 */
    535 int 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 
    550 static 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 
    568 void 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 
    599 void 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 
    644 void 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 
    667 static 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 */
    680 int 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 
    696 int 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 */
    723 int 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 
    756 int 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 
    771 template <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
    787 static 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 */
    827 static 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 */
    912 static 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 */
    944 int 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 
    970 int 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 
    989 bool 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 
   1061 int 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 */
   1081 static 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 */
   1099 static 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 
   1144 static 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 
   1168 int 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