LCOV - code coverage report
Current view: directory - gfx/skia/src/core - SkGeometry.cpp (source / functions) Found Hit Coverage
Test: app.info Lines: 544 0 0.0 %
Date: 2012-06-02 Functions: 46 0 0.0 %

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

Generated by: LCOV version 1.7