Home | History | Annotate | Download | only in Intersection
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "Simplify.h"
      9 
     10 #undef SkASSERT
     11 #define SkASSERT(cond) while (!(cond)) { sk_throw(); }
     12 
     13 // FIXME: remove once debugging is complete
     14 #if 01 // set to 1 for no debugging whatsoever
     15 
     16 //const bool gRunTestsInOneThread = false;
     17 
     18 #define DEBUG_ACTIVE_LESS_THAN 0
     19 #define DEBUG_ADD 0
     20 #define DEBUG_ADD_BOTTOM_TS 0
     21 #define DEBUG_ADD_INTERSECTING_TS 0
     22 #define DEBUG_ADJUST_COINCIDENT 0
     23 #define DEBUG_ASSEMBLE 0
     24 #define DEBUG_BOTTOM 0
     25 #define DEBUG_BRIDGE 0
     26 #define DEBUG_DUMP 0
     27 #define DEBUG_SORT_HORIZONTAL 0
     28 #define DEBUG_OUT 0
     29 #define DEBUG_OUT_LESS_THAN 0
     30 #define DEBUG_SPLIT 0
     31 #define DEBUG_STITCH_EDGE 0
     32 #define DEBUG_TRIM_LINE 0
     33 
     34 #else
     35 
     36 //const bool gRunTestsInOneThread = true;
     37 
     38 #define DEBUG_ACTIVE_LESS_THAN 0
     39 #define DEBUG_ADD 01
     40 #define DEBUG_ADD_BOTTOM_TS 0
     41 #define DEBUG_ADD_INTERSECTING_TS 0
     42 #define DEBUG_ADJUST_COINCIDENT 1
     43 #define DEBUG_ASSEMBLE 1
     44 #define DEBUG_BOTTOM 0
     45 #define DEBUG_BRIDGE 1
     46 #define DEBUG_DUMP 1
     47 #define DEBUG_SORT_HORIZONTAL 01
     48 #define DEBUG_OUT 01
     49 #define DEBUG_OUT_LESS_THAN 0
     50 #define DEBUG_SPLIT 1
     51 #define DEBUG_STITCH_EDGE 1
     52 #define DEBUG_TRIM_LINE 1
     53 
     54 #endif
     55 
     56 #if DEBUG_ASSEMBLE || DEBUG_BRIDGE
     57 static const char* kLVerbStr[] = {"", "line", "quad", "cubic"};
     58 #endif
     59 #if DEBUG_STITCH_EDGE
     60 static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"};
     61 #endif
     62 
     63 static int LineIntersect(const SkPoint a[2], const SkPoint b[2],
     64         Intersections& intersections) {
     65     const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
     66     const _Line bLine = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}};
     67     return intersect(aLine, bLine, intersections);
     68 }
     69 
     70 static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2],
     71         Intersections& intersections) {
     72     const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
     73     const _Line bLine = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}};
     74     intersect(aQuad, bLine, intersections);
     75     return intersections.fUsed;
     76 }
     77 
     78 static int CubicLineIntersect(const SkPoint a[2], const SkPoint b[3],
     79         Intersections& intersections) {
     80     const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
     81             {a[3].fX, a[3].fY}};
     82     const _Line bLine = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}};
     83     return intersect(aCubic, bLine, intersections);
     84 }
     85 
     86 static int QuadIntersect(const SkPoint a[3], const SkPoint b[3],
     87         Intersections& intersections) {
     88     const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
     89     const Quadratic bQuad = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}, {b[2].fX, b[2].fY}};
     90     intersect2(aQuad, bQuad, intersections);
     91     return intersections.fUsed;
     92 }
     93 
     94 static int CubicIntersect(const SkPoint a[4], const SkPoint b[4],
     95         Intersections& intersections) {
     96     const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
     97             {a[3].fX, a[3].fY}};
     98     const Cubic bCubic = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}, {b[2].fX, b[2].fY},
     99             {b[3].fX, b[3].fY}};
    100     intersect(aCubic, bCubic, intersections);
    101     return intersections.fUsed;
    102 }
    103 
    104 static int LineIntersect(const SkPoint a[2], SkScalar left, SkScalar right,
    105         SkScalar y, double aRange[2]) {
    106     const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
    107     return horizontalLineIntersect(aLine, left, right, y, aRange);
    108 }
    109 
    110 static int QuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right,
    111         SkScalar y, double aRange[3]) {
    112     const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
    113     return horizontalIntersect(aQuad, left, right, y, aRange);
    114 }
    115 
    116 static int CubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right,
    117         SkScalar y, double aRange[4]) {
    118     const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
    119             {a[3].fX, a[3].fY}};
    120     return horizontalIntersect(aCubic, left, right, y, aRange);
    121 }
    122 
    123 static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) {
    124     const _Line line = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
    125     double x, y;
    126     xy_at_t(line, t, x, y);
    127     out->fX = SkDoubleToScalar(x);
    128     out->fY = SkDoubleToScalar(y);
    129 }
    130 
    131 static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) {
    132     const Quadratic quad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
    133     double x, y;
    134     xy_at_t(quad, t, x, y);
    135     out->fX = SkDoubleToScalar(x);
    136     out->fY = SkDoubleToScalar(y);
    137 }
    138 
    139 static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) {
    140     const Cubic cubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
    141             {a[3].fX, a[3].fY}};
    142     double x, y;
    143     xy_at_t(cubic, t, x, y);
    144     out->fX = SkDoubleToScalar(x);
    145     out->fY = SkDoubleToScalar(y);
    146 }
    147 
    148 static SkScalar LineYAtT(const SkPoint a[2], double t) {
    149     const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
    150     double y;
    151     xy_at_t(aLine, t, *(double*) 0, y);
    152     return SkDoubleToScalar(y);
    153 }
    154 
    155 static SkScalar QuadYAtT(const SkPoint a[3], double t) {
    156     const Quadratic quad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}};
    157     double y;
    158     xy_at_t(quad, t, *(double*) 0, y);
    159     return SkDoubleToScalar(y);
    160 }
    161 
    162 static SkScalar CubicYAtT(const SkPoint a[4], double t) {
    163     const Cubic cubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY},
    164             {a[3].fX, a[3].fY}};
    165     double y;
    166     xy_at_t(cubic, t, *(double*) 0, y);
    167     return SkDoubleToScalar(y);
    168 }
    169 
    170 static void LineSubDivide(const SkPoint a[2], double startT, double endT,
    171         SkPoint sub[2]) {
    172     const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
    173     _Line dst;
    174     sub_divide(aLine, startT, endT, dst);
    175     sub[0].fX = SkDoubleToScalar(dst[0].x);
    176     sub[0].fY = SkDoubleToScalar(dst[0].y);
    177     sub[1].fX = SkDoubleToScalar(dst[1].x);
    178     sub[1].fY = SkDoubleToScalar(dst[1].y);
    179 }
    180 
    181 static void QuadSubDivide(const SkPoint a[3], double startT, double endT,
    182         SkPoint sub[3]) {
    183     const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY},
    184             {a[2].fX, a[2].fY}};
    185     Quadratic dst;
    186     sub_divide(aQuad, startT, endT, dst);
    187     sub[0].fX = SkDoubleToScalar(dst[0].x);
    188     sub[0].fY = SkDoubleToScalar(dst[0].y);
    189     sub[1].fX = SkDoubleToScalar(dst[1].x);
    190     sub[1].fY = SkDoubleToScalar(dst[1].y);
    191     sub[2].fX = SkDoubleToScalar(dst[2].x);
    192     sub[2].fY = SkDoubleToScalar(dst[2].y);
    193 }
    194 
    195 static void CubicSubDivide(const SkPoint a[4], double startT, double endT,
    196         SkPoint sub[4]) {
    197     const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY},
    198             {a[2].fX, a[2].fY}, {a[3].fX, a[3].fY}};
    199     Cubic dst;
    200     sub_divide(aCubic, startT, endT, dst);
    201     sub[0].fX = SkDoubleToScalar(dst[0].x);
    202     sub[0].fY = SkDoubleToScalar(dst[0].y);
    203     sub[1].fX = SkDoubleToScalar(dst[1].x);
    204     sub[1].fY = SkDoubleToScalar(dst[1].y);
    205     sub[2].fX = SkDoubleToScalar(dst[2].x);
    206     sub[2].fY = SkDoubleToScalar(dst[2].y);
    207     sub[3].fX = SkDoubleToScalar(dst[3].x);
    208     sub[3].fY = SkDoubleToScalar(dst[3].y);
    209 }
    210 
    211 static void QuadSubBounds(const SkPoint a[3], double startT, double endT,
    212         SkRect& bounds) {
    213     SkPoint dst[3];
    214     QuadSubDivide(a, startT, endT, dst);
    215     bounds.fLeft = bounds.fRight = dst[0].fX;
    216     bounds.fTop = bounds.fBottom = dst[0].fY;
    217     for (int index = 1; index < 3; ++index) {
    218         bounds.growToInclude(dst[index].fX, dst[index].fY);
    219     }
    220 }
    221 
    222 static void CubicSubBounds(const SkPoint a[4], double startT, double endT,
    223         SkRect& bounds) {
    224     SkPoint dst[4];
    225     CubicSubDivide(a, startT, endT, dst);
    226     bounds.fLeft = bounds.fRight = dst[0].fX;
    227     bounds.fTop = bounds.fBottom = dst[0].fY;
    228     for (int index = 1; index < 4; ++index) {
    229         bounds.growToInclude(dst[index].fX, dst[index].fY);
    230     }
    231 }
    232 
    233 static SkPath::Verb QuadReduceOrder(SkPoint a[4]) {
    234     const Quadratic aQuad =  {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY},
    235             {a[2].fX, a[2].fY}};
    236     Quadratic dst;
    237     int order = reduceOrder(aQuad, dst, kReduceOrder_TreatAsFill);
    238     for (int index = 0; index < order; ++index) {
    239         a[index].fX = SkDoubleToScalar(dst[index].x);
    240         a[index].fY = SkDoubleToScalar(dst[index].y);
    241     }
    242     if (order == 1) { // FIXME: allow returning points, caller should discard
    243         a[1] = a[0];
    244         return (SkPath::Verb) order;
    245     }
    246     return (SkPath::Verb) (order - 1);
    247 }
    248 
    249 static SkPath::Verb CubicReduceOrder(SkPoint a[4]) {
    250     const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY},
    251             {a[2].fX, a[2].fY}, {a[3].fX, a[3].fY}};
    252     Cubic dst;
    253     int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed, kReduceOrder_TreatAsFill);
    254     for (int index = 0; index < order; ++index) {
    255         a[index].fX = SkDoubleToScalar(dst[index].x);
    256         a[index].fY = SkDoubleToScalar(dst[index].y);
    257     }
    258     if (order == 1) { // FIXME: allow returning points, caller should discard
    259         a[1] = a[0];
    260         return (SkPath::Verb) order;
    261     }
    262     return (SkPath::Verb) (order - 1);
    263 }
    264 
    265 static bool IsCoincident(const SkPoint a[2], const SkPoint& above,
    266         const SkPoint& below) {
    267     const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}};
    268     const _Line bLine = {{above.fX, above.fY}, {below.fX, below.fY}};
    269     return implicit_matches_ulps(aLine, bLine, 32);
    270 }
    271 
    272 /*
    273 list of edges
    274 bounds for edge
    275 sort
    276 active T
    277 
    278 if a contour's bounds is outside of the active area, no need to create edges
    279 */
    280 
    281 /* given one or more paths,
    282  find the bounds of each contour, select the active contours
    283  for each active contour, compute a set of edges
    284  each edge corresponds to one or more lines and curves
    285  leave edges unbroken as long as possible
    286  when breaking edges, compute the t at the break but leave the control points alone
    287 
    288  */
    289 
    290 void contourBounds(const SkPath& path, SkTDArray<SkRect>& boundsArray) {
    291     SkPath::Iter iter(path, false);
    292     SkPoint pts[4];
    293     SkPath::Verb verb;
    294     SkRect bounds;
    295     bounds.setEmpty();
    296     int count = 0;
    297     while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
    298         switch (verb) {
    299             case SkPath::kMove_Verb:
    300                 if (!bounds.isEmpty()) {
    301                     *boundsArray.append() = bounds;
    302                 }
    303                 bounds.set(pts[0].fX, pts[0].fY, pts[0].fX, pts[0].fY);
    304                 count = 0;
    305                 break;
    306             case SkPath::kLine_Verb:
    307                 count = 1;
    308                 break;
    309             case SkPath::kQuad_Verb:
    310                 count = 2;
    311                 break;
    312             case SkPath::kCubic_Verb:
    313                 count = 3;
    314                 break;
    315             case SkPath::kClose_Verb:
    316                 count = 0;
    317                 break;
    318             default:
    319                 SkDEBUGFAIL("bad verb");
    320                 return;
    321         }
    322         for (int i = 1; i <= count; ++i) {
    323             bounds.growToInclude(pts[i].fX, pts[i].fY);
    324         }
    325     }
    326 }
    327 
    328 static bool extendLine(const SkPoint line[2], const SkPoint& add) {
    329     // FIXME: allow this to extend lines that have slopes that are nearly equal
    330     SkScalar dx1 = line[1].fX - line[0].fX;
    331     SkScalar dy1 = line[1].fY - line[0].fY;
    332     SkScalar dx2 = add.fX - line[0].fX;
    333     SkScalar dy2 = add.fY - line[0].fY;
    334     return dx1 * dy2 == dx2 * dy1;
    335 }
    336 
    337 // OPTIMIZATION: this should point to a list of input data rather than duplicating
    338 // the line data here. This would reduce the need to assemble the results.
    339 struct OutEdge {
    340     bool operator<(const OutEdge& rh) const {
    341         const SkPoint& first = fPts[0];
    342         const SkPoint& rhFirst = rh.fPts[0];
    343         return first.fY == rhFirst.fY
    344                 ? first.fX < rhFirst.fX
    345                 : first.fY < rhFirst.fY;
    346     }
    347 
    348     SkPoint fPts[4];
    349     int fID; // id of edge generating data
    350     uint8_t fVerb; // FIXME: not read from everywhere
    351     bool fCloseCall; // edge is trimmable if not originally coincident
    352 };
    353 
    354 class OutEdgeBuilder {
    355 public:
    356     OutEdgeBuilder(bool fill)
    357         : fFill(fill) {
    358         }
    359 
    360     void addCurve(const SkPoint line[4], SkPath::Verb verb, int id,
    361             bool closeCall) {
    362         OutEdge& newEdge = fEdges.push_back();
    363         memcpy(newEdge.fPts, line, (verb + 1) * sizeof(SkPoint));
    364         newEdge.fVerb = verb;
    365         newEdge.fID = id;
    366         newEdge.fCloseCall = closeCall;
    367     }
    368 
    369     bool trimLine(SkScalar y, int id) {
    370         size_t count = fEdges.count();
    371         while (count-- != 0) {
    372             OutEdge& edge = fEdges[count];
    373             if (edge.fID != id) {
    374                 continue;
    375             }
    376             if (edge.fCloseCall) {
    377                 return false;
    378             }
    379             SkASSERT(edge.fPts[0].fY <= y);
    380             if (edge.fPts[1].fY <= y) {
    381                 continue;
    382             }
    383             edge.fPts[1].fX = edge.fPts[0].fX + (y - edge.fPts[0].fY)
    384                     * (edge.fPts[1].fX - edge.fPts[0].fX)
    385                     / (edge.fPts[1].fY - edge.fPts[0].fY);
    386             edge.fPts[1].fY = y;
    387 #if DEBUG_TRIM_LINE
    388             SkDebugf("%s edge=%d %1.9g,%1.9g\n", __FUNCTION__, id,
    389                     edge.fPts[1].fX, y);
    390 #endif
    391             return true;
    392         }
    393         return false;
    394     }
    395 
    396     void assemble(SkPath& simple) {
    397         size_t listCount = fEdges.count();
    398         if (listCount == 0) {
    399             return;
    400         }
    401         do {
    402             size_t listIndex = 0;
    403             int advance = 1;
    404             while (listIndex < listCount && fTops[listIndex] == 0) {
    405                 ++listIndex;
    406             }
    407             if (listIndex >= listCount) {
    408                 break;
    409             }
    410             int closeEdgeIndex = -listIndex - 1;
    411             // the curve is deferred and not added right away because the
    412             // following edge may extend the first curve.
    413             SkPoint firstPt, lastCurve[4];
    414             uint8_t lastVerb;
    415 #if DEBUG_ASSEMBLE
    416             int firstIndex, lastIndex;
    417             const int tab = 8;
    418 #endif
    419             bool doMove = true;
    420             int edgeIndex;
    421             do {
    422                 SkPoint* ptArray = fEdges[listIndex].fPts;
    423                 uint8_t verb = fEdges[listIndex].fVerb;
    424                 SkPoint* curve[4];
    425                 if (advance < 0) {
    426                     curve[0] = &ptArray[verb];
    427                     if (verb == SkPath::kCubic_Verb) {
    428                         curve[1] = &ptArray[2];
    429                         curve[2] = &ptArray[1];
    430                     }
    431                     curve[verb] = &ptArray[0];
    432                 } else {
    433                     curve[0] = &ptArray[0];
    434                     if (verb == SkPath::kCubic_Verb) {
    435                         curve[1] = &ptArray[1];
    436                         curve[2] = &ptArray[2];
    437                     }
    438                     curve[verb] = &ptArray[verb];
    439                 }
    440                 if (verb == SkPath::kQuad_Verb) {
    441                     curve[1] = &ptArray[1];
    442                 }
    443                 if (doMove) {
    444                     firstPt = *curve[0];
    445                     simple.moveTo(curve[0]->fX, curve[0]->fY);
    446 #if DEBUG_ASSEMBLE
    447                     SkDebugf("%s %d moveTo (%g,%g)\n", __FUNCTION__,
    448                             listIndex + 1, curve[0]->fX, curve[0]->fY);
    449                     firstIndex = listIndex;
    450 #endif
    451                     for (int index = 0; index <= verb; ++index) {
    452                         lastCurve[index] = *curve[index];
    453                     }
    454                     doMove = false;
    455                 } else {
    456                     bool gap = lastCurve[lastVerb] != *curve[0];
    457                     if (gap || lastVerb != SkPath::kLine_Verb) { // output the accumulated curve before the gap
    458                         // FIXME: see comment in bridge -- this probably
    459                         // conceals errors
    460                         SkASSERT(fFill && UlpsDiff(lastCurve[lastVerb].fY,
    461                                 curve[0]->fY) <= 10);
    462                         switch (lastVerb) {
    463                             case SkPath::kLine_Verb:
    464                                 simple.lineTo(lastCurve[1].fX, lastCurve[1].fY);
    465                                 break;
    466                             case SkPath::kQuad_Verb:
    467                                 simple.quadTo(lastCurve[1].fX, lastCurve[1].fY,
    468                                         lastCurve[2].fX, lastCurve[2].fY);
    469                                 break;
    470                             case SkPath::kCubic_Verb:
    471                                 simple.cubicTo(lastCurve[1].fX, lastCurve[1].fY,
    472                                         lastCurve[2].fX, lastCurve[2].fY,
    473                                         lastCurve[3].fX, lastCurve[3].fY);
    474                                 break;
    475                         }
    476 #if DEBUG_ASSEMBLE
    477                         SkDebugf("%*s %d %sTo (%g,%g)\n", tab, "", lastIndex + 1,
    478                                 kLVerbStr[lastVerb], lastCurve[lastVerb].fX,
    479                                 lastCurve[lastVerb].fY);
    480 #endif
    481                     }
    482                     int firstCopy = 1;
    483                     if (gap || (lastVerb == SkPath::kLine_Verb
    484                              && (verb != SkPath::kLine_Verb
    485                              || !extendLine(lastCurve, *curve[verb])))) {
    486                         // FIXME: see comment in bridge -- this probably
    487                         // conceals errors
    488                         SkASSERT(lastCurve[lastVerb] == *curve[0] ||
    489                                 (fFill && UlpsDiff(lastCurve[lastVerb].fY,
    490                                 curve[0]->fY) <= 10));
    491                         simple.lineTo(curve[0]->fX, curve[0]->fY);
    492 #if DEBUG_ASSEMBLE
    493                         SkDebugf("%*s %d gap lineTo (%g,%g)\n", tab, "",
    494                                 lastIndex + 1, curve[0]->fX, curve[0]->fY);
    495 #endif
    496                         firstCopy = 0;
    497                     } else if (lastVerb != SkPath::kLine_Verb) {
    498                         firstCopy = 0;
    499                     }
    500                     for (int index = firstCopy; index <= verb; ++index) {
    501                         lastCurve[index] = *curve[index];
    502                     }
    503                 }
    504                 lastVerb = verb;
    505 #if DEBUG_ASSEMBLE
    506                 lastIndex = listIndex;
    507 #endif
    508                 if (advance < 0) {
    509                     edgeIndex = fTops[listIndex];
    510                     fTops[listIndex] = 0;
    511                 } else {
    512                     edgeIndex = fBottoms[listIndex];
    513                     fBottoms[listIndex] = 0;
    514                 }
    515                 if (edgeIndex) {
    516                     listIndex = abs(edgeIndex) - 1;
    517                     if (edgeIndex < 0) {
    518                         fTops[listIndex] = 0;
    519                     } else {
    520                         fBottoms[listIndex] = 0;
    521                     }
    522                 }
    523                 if (edgeIndex == closeEdgeIndex || edgeIndex == 0) {
    524                     switch (lastVerb) {
    525                         case SkPath::kLine_Verb:
    526                             simple.lineTo(lastCurve[1].fX, lastCurve[1].fY);
    527                             break;
    528                         case SkPath::kQuad_Verb:
    529                             simple.quadTo(lastCurve[1].fX, lastCurve[1].fY,
    530                                     lastCurve[2].fX, lastCurve[2].fY);
    531                             break;
    532                         case SkPath::kCubic_Verb:
    533                             simple.cubicTo(lastCurve[1].fX, lastCurve[1].fY,
    534                                     lastCurve[2].fX, lastCurve[2].fY,
    535                                     lastCurve[3].fX, lastCurve[3].fY);
    536                             break;
    537                     }
    538 #if DEBUG_ASSEMBLE
    539                     SkDebugf("%*s %d %sTo last (%g, %g)\n", tab, "",
    540                             lastIndex + 1, kLVerbStr[lastVerb],
    541                             lastCurve[lastVerb].fX, lastCurve[lastVerb].fY);
    542 #endif
    543                     if (lastCurve[lastVerb] != firstPt) {
    544                         simple.lineTo(firstPt.fX, firstPt.fY);
    545 #if DEBUG_ASSEMBLE
    546                         SkDebugf("%*s %d final line (%g, %g)\n", tab, "",
    547                                 firstIndex + 1, firstPt.fX, firstPt.fY);
    548 #endif
    549                     }
    550                     simple.close();
    551 #if DEBUG_ASSEMBLE
    552                     SkDebugf("%*s   close\n", tab, "");
    553 #endif
    554                     break;
    555                 }
    556                 // if this and next edge go different directions
    557 #if DEBUG_ASSEMBLE
    558                 SkDebugf("%*s   advance=%d edgeIndex=%d flip=%s\n", tab, "",
    559                         advance, edgeIndex, advance > 0 ^ edgeIndex < 0 ?
    560                         "true" : "false");
    561 #endif
    562                 if (advance > 0 ^ edgeIndex < 0) {
    563                     advance = -advance;
    564                 }
    565             } while (edgeIndex);
    566         } while (true);
    567     }
    568 
    569     // sort points by y, then x
    570     // if x/y is identical, sort bottoms before tops
    571     // if identical and both tops/bottoms, sort by angle
    572     static bool lessThan(SkTArray<OutEdge>& edges, const int one,
    573             const int two) {
    574         const OutEdge& oneEdge = edges[abs(one) - 1];
    575         int oneIndex = one < 0 ? 0 : oneEdge.fVerb;
    576         const SkPoint& startPt1 = oneEdge.fPts[oneIndex];
    577         const OutEdge& twoEdge = edges[abs(two) - 1];
    578         int twoIndex = two < 0 ? 0 : twoEdge.fVerb;
    579         const SkPoint& startPt2 = twoEdge.fPts[twoIndex];
    580         if (startPt1.fY != startPt2.fY) {
    581     #if DEBUG_OUT_LESS_THAN
    582             SkDebugf("%s %d<%d (%g,%g) %s startPt1.fY < startPt2.fY\n", __FUNCTION__,
    583                     one, two, startPt1.fY, startPt2.fY,
    584                     startPt1.fY < startPt2.fY ? "true" : "false");
    585     #endif
    586             return startPt1.fY < startPt2.fY;
    587         }
    588         if (startPt1.fX != startPt2.fX) {
    589     #if DEBUG_OUT_LESS_THAN
    590             SkDebugf("%s %d<%d (%g,%g) %s startPt1.fX < startPt2.fX\n", __FUNCTION__,
    591                     one, two, startPt1.fX, startPt2.fX,
    592                     startPt1.fX < startPt2.fX ? "true" : "false");
    593     #endif
    594             return startPt1.fX < startPt2.fX;
    595         }
    596         const SkPoint& endPt1 = oneEdge.fPts[oneIndex ^ oneEdge.fVerb];
    597         const SkPoint& endPt2 = twoEdge.fPts[twoIndex ^ twoEdge.fVerb];
    598         SkScalar dy1 = startPt1.fY - endPt1.fY;
    599         SkScalar dy2 = startPt2.fY - endPt2.fY;
    600         SkScalar dy1y2 = dy1 * dy2;
    601         if (dy1y2 < 0) { // different signs
    602     #if DEBUG_OUT_LESS_THAN
    603                 SkDebugf("%s %d<%d %s dy1 > 0\n", __FUNCTION__, one, two,
    604                         dy1 > 0 ? "true" : "false");
    605     #endif
    606             return dy1 > 0; // one < two if one goes up and two goes down
    607         }
    608         if (dy1y2 == 0) {
    609     #if DEBUG_OUT_LESS_THAN
    610             SkDebugf("%s %d<%d %s endPt1.fX < endPt2.fX\n", __FUNCTION__,
    611                     one, two, endPt1.fX < endPt2.fX ? "true" : "false");
    612     #endif
    613             return endPt1.fX < endPt2.fX;
    614         }
    615         SkScalar dx1y2 = (startPt1.fX - endPt1.fX) * dy2;
    616         SkScalar dx2y1 = (startPt2.fX - endPt2.fX) * dy1;
    617     #if DEBUG_OUT_LESS_THAN
    618         SkDebugf("%s %d<%d %s dy2 < 0 ^ dx1y2 < dx2y1\n", __FUNCTION__,
    619                 one, two, dy2 < 0 ^ dx1y2 < dx2y1 ? "true" : "false");
    620     #endif
    621         return dy2 > 0 ^ dx1y2 < dx2y1;
    622     }
    623 
    624     // Sort the indices of paired points and then create more indices so
    625     // assemble() can find the next edge and connect the top or bottom
    626     void bridge() {
    627         size_t index;
    628         size_t count = fEdges.count();
    629         if (!count) {
    630             return;
    631         }
    632         SkASSERT(!fFill || count > 1);
    633         fTops.setCount(count);
    634         sk_bzero(fTops.begin(), sizeof(fTops[0]) * count);
    635         fBottoms.setCount(count);
    636         sk_bzero(fBottoms.begin(), sizeof(fBottoms[0]) * count);
    637         SkTDArray<int> order;
    638         for (index = 1; index <= count; ++index) {
    639             *order.append() = -index;
    640         }
    641         for (index = 1; index <= count; ++index) {
    642             *order.append() = index;
    643         }
    644         QSort<SkTArray<OutEdge>, int>(fEdges, order.begin(), order.end() - 1, lessThan);
    645         int* lastPtr = order.end() - 1;
    646         int* leftPtr = order.begin();
    647         while (leftPtr < lastPtr) {
    648             int leftIndex = *leftPtr;
    649             int leftOutIndex = abs(leftIndex) - 1;
    650             const OutEdge& left = fEdges[leftOutIndex];
    651             int* rightPtr = leftPtr + 1;
    652             int rightIndex = *rightPtr;
    653             int rightOutIndex = abs(rightIndex) - 1;
    654             const OutEdge& right = fEdges[rightOutIndex];
    655             bool pairUp = fFill;
    656             if (!pairUp) {
    657                 const SkPoint& leftMatch =
    658                         left.fPts[leftIndex < 0 ? 0 : left.fVerb];
    659                 const SkPoint& rightMatch =
    660                         right.fPts[rightIndex < 0 ? 0 : right.fVerb];
    661                 pairUp = leftMatch == rightMatch;
    662             } else {
    663         #if DEBUG_OUT
    664         // FIXME : not happy that error in low bit is allowed
    665         // this probably conceals error elsewhere
    666                 if (UlpsDiff(left.fPts[leftIndex < 0 ? 0 : left.fVerb].fY,
    667                         right.fPts[rightIndex < 0 ? 0 : right.fVerb].fY) > 1) {
    668                     *fMismatches.append() = leftIndex;
    669                     if (rightPtr == lastPtr) {
    670                         *fMismatches.append() = rightIndex;
    671                     }
    672                     pairUp = false;
    673                 }
    674         #else
    675                 SkASSERT(UlpsDiff(left.fPts[leftIndex < 0 ? 0 : left.fVerb].fY,
    676                         right.fPts[rightIndex < 0 ? 0 : right.fVerb].fY) <= 10);
    677         #endif
    678             }
    679             if (pairUp) {
    680                 if (leftIndex < 0) {
    681                     fTops[leftOutIndex] = rightIndex;
    682                 } else {
    683                     fBottoms[leftOutIndex] = rightIndex;
    684                 }
    685                 if (rightIndex < 0) {
    686                     fTops[rightOutIndex] = leftIndex;
    687                 } else {
    688                     fBottoms[rightOutIndex] = leftIndex;
    689                 }
    690                 ++rightPtr;
    691             }
    692             leftPtr = rightPtr;
    693         }
    694 #if DEBUG_OUT
    695         int* mismatch = fMismatches.begin();
    696         while (mismatch != fMismatches.end()) {
    697             int leftIndex = *mismatch++;
    698             int leftOutIndex = abs(leftIndex) - 1;
    699             const OutEdge& left = fEdges[leftOutIndex];
    700             const SkPoint& leftPt = left.fPts[leftIndex < 0 ? 0 : left.fVerb];
    701             SkDebugf("%s left=%d %s (%1.9g,%1.9g)\n",
    702                     __FUNCTION__, left.fID, leftIndex < 0 ? "top" : "bot",
    703                     leftPt.fX, leftPt.fY);
    704         }
    705         SkASSERT(fMismatches.count() == 0);
    706 #endif
    707 #if DEBUG_BRIDGE
    708     for (index = 0; index < count; ++index) {
    709         const OutEdge& edge = fEdges[index];
    710         uint8_t verb = edge.fVerb;
    711         SkDebugf("%s %d edge=%d %s (%1.9g,%1.9g) (%1.9g,%1.9g)\n",
    712                 index == 0 ? __FUNCTION__ : "      ",
    713                 index + 1, edge.fID, kLVerbStr[verb], edge.fPts[0].fX,
    714                 edge.fPts[0].fY, edge.fPts[verb].fX, edge.fPts[verb].fY);
    715     }
    716     for (index = 0; index < count; ++index) {
    717         SkDebugf("       top    of % 2d connects to %s of % 2d\n", index + 1,
    718                 fTops[index] < 0 ? "top   " : "bottom", abs(fTops[index]));
    719         SkDebugf("       bottom of % 2d connects to %s of % 2d\n", index + 1,
    720                 fBottoms[index] < 0 ? "top   " : "bottom", abs(fBottoms[index]));
    721     }
    722 #endif
    723     }
    724 
    725 protected:
    726     SkTArray<OutEdge> fEdges;
    727     SkTDArray<int> fTops;
    728     SkTDArray<int> fBottoms;
    729     bool fFill;
    730 #if DEBUG_OUT
    731     SkTDArray<int> fMismatches;
    732 #endif
    733 };
    734 
    735 // Bounds, unlike Rect, does not consider a vertical line to be empty.
    736 struct Bounds : public SkRect {
    737     static bool Intersects(const Bounds& a, const Bounds& b) {
    738         return a.fLeft <= b.fRight && b.fLeft <= a.fRight &&
    739                 a.fTop <= b.fBottom && b.fTop <= a.fBottom;
    740     }
    741 
    742     bool isEmpty() {
    743         return fLeft > fRight || fTop > fBottom
    744                 || (fLeft == fRight && fTop == fBottom)
    745                 || isnan(fLeft) || isnan(fRight)
    746                 || isnan(fTop) || isnan(fBottom);
    747     }
    748 };
    749 
    750 class Intercepts {
    751 public:
    752     Intercepts()
    753         : fTopIntercepts(0)
    754         , fBottomIntercepts(0)
    755         , fExplicit(false) {
    756     }
    757 
    758     Intercepts& operator=(const Intercepts& src) {
    759         fTs = src.fTs;
    760         fTopIntercepts = src.fTopIntercepts;
    761         fBottomIntercepts = src.fBottomIntercepts;
    762         return *this;
    763     }
    764 
    765     // OPTIMIZATION: remove this function if it's never called
    766     double t(int tIndex) const {
    767         if (tIndex == 0) {
    768             return 0;
    769         }
    770         if (tIndex > fTs.count()) {
    771             return 1;
    772         }
    773         return fTs[tIndex - 1];
    774     }
    775 
    776 #if DEBUG_DUMP
    777     void dump(const SkPoint* pts, SkPath::Verb verb) {
    778         const char className[] = "Intercepts";
    779         const int tab = 8;
    780         for (int i = 0; i < fTs.count(); ++i) {
    781             SkPoint out;
    782             switch (verb) {
    783                 case SkPath::kLine_Verb:
    784                     LineXYAtT(pts, fTs[i], &out);
    785                     break;
    786                 case SkPath::kQuad_Verb:
    787                     QuadXYAtT(pts, fTs[i], &out);
    788                     break;
    789                 case SkPath::kCubic_Verb:
    790                     CubicXYAtT(pts, fTs[i], &out);
    791                     break;
    792                 default:
    793                     SkASSERT(0);
    794             }
    795             SkDebugf("%*s.fTs[%d]=%1.9g (%1.9g,%1.9g)\n", tab + sizeof(className),
    796                     className, i, fTs[i], out.fX, out.fY);
    797         }
    798         SkDebugf("%*s.fTopIntercepts=%u\n", tab + sizeof(className),
    799                 className, fTopIntercepts);
    800         SkDebugf("%*s.fBottomIntercepts=%u\n", tab + sizeof(className),
    801                 className, fBottomIntercepts);
    802         SkDebugf("%*s.fExplicit=%d\n", tab + sizeof(className),
    803                 className, fExplicit);
    804     }
    805 #endif
    806 
    807     SkTDArray<double> fTs;
    808     unsigned char fTopIntercepts; // 0=init state 1=1 edge >1=multiple edges
    809     unsigned char fBottomIntercepts;
    810     bool fExplicit; // if set, suppress 0 and 1
    811 
    812 };
    813 
    814 struct HorizontalEdge {
    815     bool operator<(const HorizontalEdge& rh) const {
    816         return fY == rh.fY ? fLeft == rh.fLeft ? fRight < rh.fRight
    817                 : fLeft < rh.fLeft : fY < rh.fY;
    818     }
    819 
    820 #if DEBUG_DUMP
    821     void dump() {
    822         const char className[] = "HorizontalEdge";
    823         const int tab = 4;
    824         SkDebugf("%*s.fLeft=%1.9g\n", tab + sizeof(className), className, fLeft);
    825         SkDebugf("%*s.fRight=%1.9g\n", tab + sizeof(className), className, fRight);
    826         SkDebugf("%*s.fY=%1.9g\n", tab + sizeof(className), className, fY);
    827     }
    828 #endif
    829 
    830     SkScalar fLeft;
    831     SkScalar fRight;
    832     SkScalar fY;
    833 };
    834 
    835 struct InEdge {
    836     bool operator<(const InEdge& rh) const {
    837         return fBounds.fTop == rh.fBounds.fTop
    838                 ? fBounds.fLeft < rh.fBounds.fLeft
    839                 : fBounds.fTop < rh.fBounds.fTop;
    840     }
    841 
    842     // Avoid collapsing t values that are close to the same since
    843     // we walk ts to describe consecutive intersections. Since a pair of ts can
    844     // be nearly equal, any problems caused by this should be taken care
    845     // of later.
    846     int add(double* ts, size_t count, ptrdiff_t verbIndex) {
    847         // FIXME: in the pathological case where there is a ton of intercepts, binary search?
    848         bool foundIntercept = false;
    849         int insertedAt = -1;
    850         Intercepts& intercepts = fIntercepts[verbIndex];
    851         for (size_t index = 0; index < count; ++index) {
    852             double t = ts[index];
    853             if (t <= 0) {
    854                 intercepts.fTopIntercepts <<= 1;
    855                 fContainsIntercepts |= ++intercepts.fTopIntercepts > 1;
    856                 continue;
    857             }
    858             if (t >= 1) {
    859                 intercepts.fBottomIntercepts <<= 1;
    860                 fContainsIntercepts |= ++intercepts.fBottomIntercepts > 1;
    861                 continue;
    862             }
    863             fIntersected = true;
    864             foundIntercept = true;
    865             size_t tCount = intercepts.fTs.count();
    866             double delta;
    867             for (size_t idx2 = 0; idx2 < tCount; ++idx2) {
    868                 if (t <= intercepts.fTs[idx2]) {
    869                     // FIXME: ?  if (t < intercepts.fTs[idx2]) // failed
    870                     delta = intercepts.fTs[idx2] - t;
    871                     if (delta > 0) {
    872                         insertedAt = idx2;
    873                         *intercepts.fTs.insert(idx2) = t;
    874                     }
    875                     goto nextPt;
    876                 }
    877             }
    878             if (tCount == 0 || (delta = t - intercepts.fTs[tCount - 1]) > 0) {
    879                 insertedAt = tCount;
    880                 *intercepts.fTs.append() = t;
    881             }
    882     nextPt:
    883             ;
    884         }
    885         fContainsIntercepts |= foundIntercept;
    886         return insertedAt;
    887     }
    888 
    889     void addPartial(SkTArray<InEdge>& edges, int ptStart, int ptEnd,
    890             int verbStart, int verbEnd) {
    891         InEdge* edge = edges.push_back_n(1);
    892         int verbCount = verbEnd - verbStart;
    893         edge->fIntercepts.push_back_n(verbCount);
    894      //   uint8_t* verbs = &fVerbs[verbStart];
    895         for (int ceptIdx = 0; ceptIdx < verbCount; ++ceptIdx) {
    896             edge->fIntercepts[ceptIdx] = fIntercepts[verbStart + ceptIdx];
    897         }
    898         edge->fPts.append(ptEnd - ptStart, &fPts[ptStart]);
    899         edge->fVerbs.append(verbCount, &fVerbs[verbStart]);
    900         edge->setBounds();
    901         edge->fWinding = fWinding;
    902         edge->fContainsIntercepts = fContainsIntercepts; // FIXME: may not be correct -- but do we need to know?
    903     }
    904 
    905     void addSplit(SkTArray<InEdge>& edges, SkPoint* pts, uint8_t verb,
    906             Intercepts& intercepts, int firstT, int lastT, bool flipped) {
    907         InEdge* edge = edges.push_back_n(1);
    908         edge->fIntercepts.push_back_n(1);
    909         if (firstT == 0) {
    910             *edge->fIntercepts[0].fTs.append() = 0;
    911         } else {
    912             *edge->fIntercepts[0].fTs.append() = intercepts.fTs[firstT - 1];
    913         }
    914         bool add1 = lastT == intercepts.fTs.count();
    915         edge->fIntercepts[0].fTs.append(lastT - firstT, &intercepts.fTs[firstT]);
    916         if (add1) {
    917             *edge->fIntercepts[0].fTs.append() = 1;
    918         }
    919         edge->fIntercepts[0].fExplicit = true;
    920         edge->fPts.append(verb + 1, pts);
    921         edge->fVerbs.append(1, &verb);
    922         // FIXME: bounds could be better for partial Ts
    923         edge->setSubBounds();
    924         edge->fContainsIntercepts = fContainsIntercepts; // FIXME: may not be correct -- but do we need to know?
    925         if (flipped) {
    926             edge->flipTs();
    927             edge->fWinding = -fWinding;
    928         } else {
    929             edge->fWinding = fWinding;
    930         }
    931     }
    932 
    933     bool cached(const InEdge* edge) {
    934         // FIXME: in the pathological case where there is a ton of edges, binary search?
    935         size_t count = fCached.count();
    936         for (size_t index = 0; index < count; ++index) {
    937             if (edge == fCached[index]) {
    938                 return true;
    939             }
    940             if (edge < fCached[index]) {
    941                 *fCached.insert(index) = edge;
    942                 return false;
    943             }
    944         }
    945         *fCached.append() = edge;
    946         return false;
    947     }
    948 
    949     void complete(signed char winding) {
    950         setBounds();
    951         fIntercepts.push_back_n(fVerbs.count());
    952         if ((fWinding = winding) < 0) { // reverse verbs, pts, if bottom to top
    953             flip();
    954         }
    955         fContainsIntercepts = fIntersected = false;
    956     }
    957 
    958     void flip() {
    959         size_t index;
    960         size_t last = fPts.count() - 1;
    961         for (index = 0; index < last; ++index, --last) {
    962             SkTSwap<SkPoint>(fPts[index], fPts[last]);
    963         }
    964         last = fVerbs.count() - 1;
    965         for (index = 0; index < last; ++index, --last) {
    966             SkTSwap<uint8_t>(fVerbs[index], fVerbs[last]);
    967         }
    968     }
    969 
    970     void flipTs() {
    971         SkASSERT(fIntercepts.count() == 1);
    972         Intercepts& intercepts = fIntercepts[0];
    973         SkASSERT(intercepts.fExplicit);
    974         SkTDArray<double>& ts = intercepts.fTs;
    975         size_t index;
    976         size_t last = ts.count() - 1;
    977         for (index = 0; index < last; ++index, --last) {
    978             SkTSwap<double>(ts[index], ts[last]);
    979         }
    980     }
    981 
    982     void reset() {
    983         fCached.reset();
    984         fIntercepts.reset();
    985         fPts.reset();
    986         fVerbs.reset();
    987         fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
    988         fWinding = 0;
    989         fContainsIntercepts = false;
    990         fIntersected = false;
    991     }
    992 
    993     void setBounds() {
    994         SkPoint* ptPtr = fPts.begin();
    995         SkPoint* ptLast = fPts.end();
    996         if (ptPtr == ptLast) {
    997             SkDebugf("%s empty edge\n", __FUNCTION__);
    998             SkASSERT(0);
    999             // FIXME: delete empty edge?
   1000             return;
   1001         }
   1002         fBounds.set(ptPtr->fX, ptPtr->fY, ptPtr->fX, ptPtr->fY);
   1003         ++ptPtr;
   1004         while (ptPtr != ptLast) {
   1005             fBounds.growToInclude(ptPtr->fX, ptPtr->fY);
   1006             ++ptPtr;
   1007         }
   1008     }
   1009 
   1010     // recompute bounds based on subrange of T values
   1011     void setSubBounds() {
   1012         SkASSERT(fIntercepts.count() == 1);
   1013         Intercepts& intercepts = fIntercepts[0];
   1014         SkASSERT(intercepts.fExplicit);
   1015         SkASSERT(fVerbs.count() == 1);
   1016         SkTDArray<double>& ts = intercepts.fTs;
   1017         if (fVerbs[0] == SkPath::kQuad_Verb) {
   1018             SkASSERT(fPts.count() == 3);
   1019             QuadSubBounds(fPts.begin(), ts[0], ts[ts.count() - 1], fBounds);
   1020         } else {
   1021             SkASSERT(fVerbs[0] == SkPath::kCubic_Verb);
   1022             SkASSERT(fPts.count() == 4);
   1023             CubicSubBounds(fPts.begin(), ts[0], ts[ts.count() - 1], fBounds);
   1024         }
   1025     }
   1026 
   1027     void splitInflectionPts(SkTArray<InEdge>& edges) {
   1028         if (!fIntersected) {
   1029             return;
   1030         }
   1031         uint8_t* verbs = fVerbs.begin();
   1032         SkPoint* pts = fPts.begin();
   1033         int lastVerb = 0;
   1034         int lastPt = 0;
   1035         uint8_t verb;
   1036         bool edgeSplit = false;
   1037         for (int ceptIdx = 0; ceptIdx < fIntercepts.count(); ++ceptIdx, pts += verb) {
   1038             Intercepts& intercepts = fIntercepts[ceptIdx];
   1039             verb = *verbs++;
   1040             if (verb <= SkPath::kLine_Verb) {
   1041                 continue;
   1042             }
   1043             size_t tCount = intercepts.fTs.count();
   1044             if (!tCount) {
   1045                 continue;
   1046             }
   1047             size_t tIndex = (size_t) -1;
   1048             SkScalar y = pts[0].fY;
   1049             int lastSplit = 0;
   1050             int firstSplit = -1;
   1051             bool curveSplit = false;
   1052             while (++tIndex < tCount) {
   1053                 double nextT = intercepts.fTs[tIndex];
   1054                 SkScalar nextY = verb == SkPath::kQuad_Verb
   1055                         ? QuadYAtT(pts, nextT) : CubicYAtT(pts, nextT);
   1056                 if (nextY < y) {
   1057                     edgeSplit = curveSplit = true;
   1058                     if (firstSplit < 0) {
   1059                         firstSplit = tIndex;
   1060                         int nextPt = pts - fPts.begin();
   1061                         int nextVerb = verbs - 1 - fVerbs.begin();
   1062                         if (lastVerb < nextVerb) {
   1063                             addPartial(edges, lastPt, nextPt, lastVerb, nextVerb);
   1064             #if DEBUG_SPLIT
   1065                             SkDebugf("%s addPartial 1\n", __FUNCTION__);
   1066             #endif
   1067                         }
   1068                         lastPt = nextPt;
   1069                         lastVerb = nextVerb;
   1070                     }
   1071                 } else {
   1072                     if (firstSplit >= 0) {
   1073                         if (lastSplit < firstSplit) {
   1074                             addSplit(edges, pts, verb, intercepts,
   1075                                     lastSplit, firstSplit, false);
   1076             #if DEBUG_SPLIT
   1077                             SkDebugf("%s addSplit 1 tIndex=%d,%d\n",
   1078                                     __FUNCTION__, lastSplit, firstSplit);
   1079             #endif
   1080                         }
   1081                         addSplit(edges, pts, verb, intercepts,
   1082                                 firstSplit, tIndex, true);
   1083             #if DEBUG_SPLIT
   1084                         SkDebugf("%s addSplit 2 tIndex=%d,%d flip\n",
   1085                                 __FUNCTION__, firstSplit, tIndex);
   1086             #endif
   1087                         lastSplit = tIndex;
   1088                         firstSplit = -1;
   1089                     }
   1090                 }
   1091                 y = nextY;
   1092             }
   1093             if (curveSplit) {
   1094                 if (firstSplit < 0) {
   1095                     firstSplit = lastSplit;
   1096                 } else {
   1097                     addSplit(edges, pts, verb, intercepts, lastSplit,
   1098                             firstSplit, false);
   1099             #if DEBUG_SPLIT
   1100                     SkDebugf("%s addSplit 3 tIndex=%d,%d\n", __FUNCTION__,
   1101                             lastSplit, firstSplit);
   1102             #endif
   1103                 }
   1104                 addSplit(edges, pts, verb, intercepts, firstSplit,
   1105                         tIndex, pts[verb].fY < y);
   1106             #if DEBUG_SPLIT
   1107                 SkDebugf("%s addSplit 4 tIndex=%d,%d %s\n", __FUNCTION__,
   1108                         firstSplit, tIndex, pts[verb].fY < y ? "flip" : "");
   1109             #endif
   1110             }
   1111         }
   1112         // collapse remainder -- if there's nothing left, clear it somehow?
   1113         if (edgeSplit) {
   1114             int nextVerb = verbs - 1 - fVerbs.begin();
   1115             if (lastVerb < nextVerb) {
   1116                 int nextPt = pts - fPts.begin();
   1117                 addPartial(edges, lastPt, nextPt, lastVerb, nextVerb);
   1118             #if DEBUG_SPLIT
   1119                 SkDebugf("%s addPartial 2\n", __FUNCTION__);
   1120             #endif
   1121             }
   1122             // OPTIMIZATION: reuse the edge instead of marking it empty
   1123             reset();
   1124         }
   1125     }
   1126 
   1127 #if DEBUG_DUMP
   1128     void dump() {
   1129         int i;
   1130         const char className[] = "InEdge";
   1131         const int tab = 4;
   1132         SkDebugf("InEdge %p (edge=%d)\n", this, fID);
   1133         for (i = 0; i < fCached.count(); ++i) {
   1134             SkDebugf("%*s.fCached[%d]=0x%08x\n", tab + sizeof(className),
   1135                     className, i, fCached[i]);
   1136         }
   1137         uint8_t* verbs = fVerbs.begin();
   1138         SkPoint* pts = fPts.begin();
   1139         for (i = 0; i < fIntercepts.count(); ++i) {
   1140             SkDebugf("%*s.fIntercepts[%d]:\n", tab + sizeof(className),
   1141                     className, i);
   1142             fIntercepts[i].dump(pts, (SkPath::Verb) *verbs);
   1143             pts += *verbs++;
   1144         }
   1145         for (i = 0; i < fPts.count(); ++i) {
   1146             SkDebugf("%*s.fPts[%d]=(%1.9g,%1.9g)\n", tab + sizeof(className),
   1147                     className, i, fPts[i].fX, fPts[i].fY);
   1148         }
   1149         for (i = 0; i < fVerbs.count(); ++i) {
   1150             SkDebugf("%*s.fVerbs[%d]=%d\n", tab + sizeof(className),
   1151                     className, i, fVerbs[i]);
   1152         }
   1153         SkDebugf("%*s.fBounds=(%1.9g, %1.9g, %1.9g, %1.9g)\n", tab + sizeof(className),
   1154                 className, fBounds.fLeft, fBounds.fTop,
   1155                 fBounds.fRight, fBounds.fBottom);
   1156         SkDebugf("%*s.fWinding=%d\n", tab + sizeof(className), className,
   1157                 fWinding);
   1158         SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className),
   1159                 className, fContainsIntercepts);
   1160         SkDebugf("%*s.fIntersected=%d\n", tab + sizeof(className),
   1161                 className, fIntersected);
   1162     }
   1163 #endif
   1164 
   1165     // FIXME: temporary data : move this to a separate struct?
   1166     SkTDArray<const InEdge*> fCached; // list of edges already intercepted
   1167     SkTArray<Intercepts> fIntercepts; // one per verb
   1168 
   1169     // persistent data
   1170     SkTDArray<SkPoint> fPts;
   1171     SkTDArray<uint8_t> fVerbs;
   1172     Bounds fBounds;
   1173     int fID;
   1174     signed char fWinding;
   1175     bool fContainsIntercepts;
   1176     bool fIntersected;
   1177 };
   1178 
   1179 class InEdgeBuilder {
   1180 public:
   1181 
   1182 InEdgeBuilder(const SkPath& path, bool ignoreHorizontal, SkTArray<InEdge>& edges,
   1183         SkTDArray<HorizontalEdge>& horizontalEdges)
   1184     : fPath(path)
   1185     , fCurrentEdge(NULL)
   1186     , fEdges(edges)
   1187     , fHorizontalEdges(horizontalEdges)
   1188     , fIgnoreHorizontal(ignoreHorizontal)
   1189     , fContainsCurves(false)
   1190 {
   1191     walk();
   1192 }
   1193 
   1194 bool containsCurves() const {
   1195     return fContainsCurves;
   1196 }
   1197 
   1198 protected:
   1199 
   1200 void addEdge() {
   1201     SkASSERT(fCurrentEdge);
   1202     fCurrentEdge->fPts.append(fPtCount - fPtOffset, &fPts[fPtOffset]);
   1203     fPtOffset = 1;
   1204     *fCurrentEdge->fVerbs.append() = fVerb;
   1205 }
   1206 
   1207 bool complete() {
   1208     if (fCurrentEdge && fCurrentEdge->fVerbs.count()) {
   1209         fCurrentEdge->complete(fWinding);
   1210         fCurrentEdge = NULL;
   1211         return true;
   1212     }
   1213     return false;
   1214 }
   1215 
   1216 int direction(SkPath::Verb verb) {
   1217     fPtCount = verb + 1;
   1218     if (fIgnoreHorizontal && isHorizontal()) {
   1219         return 0;
   1220     }
   1221     return fPts[0].fY == fPts[verb].fY
   1222             ? fPts[0].fX == fPts[verb].fX ? 0 : fPts[0].fX < fPts[verb].fX
   1223             ? 1 : -1 : fPts[0].fY < fPts[verb].fY ? 1 : -1;
   1224 }
   1225 
   1226 bool isHorizontal() {
   1227     SkScalar y = fPts[0].fY;
   1228     for (int i = 1; i < fPtCount; ++i) {
   1229         if (fPts[i].fY != y) {
   1230             return false;
   1231         }
   1232     }
   1233     return true;
   1234 }
   1235 
   1236 void startEdge() {
   1237     if (!fCurrentEdge) {
   1238         fCurrentEdge = fEdges.push_back_n(1);
   1239     }
   1240     fWinding = 0;
   1241     fPtOffset = 0;
   1242 }
   1243 
   1244 void walk() {
   1245     SkPath::Iter iter(fPath, true);
   1246     int winding = 0;
   1247     while ((fVerb = iter.next(fPts)) != SkPath::kDone_Verb) {
   1248         switch (fVerb) {
   1249             case SkPath::kMove_Verb:
   1250                 startEdge();
   1251                 continue;
   1252             case SkPath::kLine_Verb:
   1253                 winding = direction(SkPath::kLine_Verb);
   1254                 break;
   1255             case SkPath::kQuad_Verb:
   1256                 fVerb = QuadReduceOrder(fPts);
   1257                 winding = direction(fVerb);
   1258                 fContainsCurves |= fVerb == SkPath::kQuad_Verb;
   1259                 break;
   1260             case SkPath::kCubic_Verb:
   1261                 fVerb = CubicReduceOrder(fPts);
   1262                 winding = direction(fVerb);
   1263                 fContainsCurves |= fVerb >= SkPath::kQuad_Verb;
   1264                 break;
   1265             case SkPath::kClose_Verb:
   1266                 SkASSERT(fCurrentEdge);
   1267                 complete();
   1268                 continue;
   1269             default:
   1270                 SkDEBUGFAIL("bad verb");
   1271                 return;
   1272         }
   1273         if (winding == 0) {
   1274             HorizontalEdge* horizontalEdge = fHorizontalEdges.append();
   1275             // FIXME: for degenerate quads and cubics, compute x extremes
   1276             horizontalEdge->fLeft = fPts[0].fX;
   1277             horizontalEdge->fRight = fPts[fVerb].fX;
   1278             horizontalEdge->fY = fPts[0].fY;
   1279             if (horizontalEdge->fLeft > horizontalEdge->fRight) {
   1280                 SkTSwap<SkScalar>(horizontalEdge->fLeft, horizontalEdge->fRight);
   1281             }
   1282             if (complete()) {
   1283                 startEdge();
   1284             }
   1285             continue;
   1286         }
   1287         if (fWinding + winding == 0) {
   1288             // FIXME: if prior verb or this verb is a horizontal line, reverse
   1289             // it instead of starting a new edge
   1290             SkASSERT(fCurrentEdge);
   1291             if (complete()) {
   1292                 startEdge();
   1293             }
   1294         }
   1295         fWinding = winding;
   1296         addEdge();
   1297     }
   1298     if (!complete()) {
   1299         if (fCurrentEdge) {
   1300             fEdges.pop_back();
   1301         }
   1302     }
   1303 }
   1304 
   1305 private:
   1306     const SkPath& fPath;
   1307     InEdge* fCurrentEdge;
   1308     SkTArray<InEdge>& fEdges;
   1309     SkTDArray<HorizontalEdge>& fHorizontalEdges;
   1310     SkPoint fPts[4];
   1311     SkPath::Verb fVerb;
   1312     int fPtCount;
   1313     int fPtOffset;
   1314     int8_t fWinding;
   1315     bool fIgnoreHorizontal;
   1316     bool fContainsCurves;
   1317 };
   1318 
   1319 struct WorkEdge {
   1320     SkScalar bottom() const {
   1321         return fPts[verb()].fY;
   1322     }
   1323 
   1324     void init(const InEdge* edge) {
   1325         fEdge = edge;
   1326         fPts = edge->fPts.begin();
   1327         fVerb = edge->fVerbs.begin();
   1328     }
   1329 
   1330     bool advance() {
   1331         SkASSERT(fVerb < fEdge->fVerbs.end());
   1332         fPts += *fVerb++;
   1333         return fVerb != fEdge->fVerbs.end();
   1334     }
   1335 
   1336     const SkPoint* lastPoints() const {
   1337         SkASSERT(fPts >= fEdge->fPts.begin() + lastVerb());
   1338         return &fPts[-lastVerb()];
   1339     }
   1340 
   1341     SkPath::Verb lastVerb() const {
   1342         SkASSERT(fVerb > fEdge->fVerbs.begin());
   1343         return (SkPath::Verb) fVerb[-1];
   1344     }
   1345 
   1346     const SkPoint* points() const {
   1347         return fPts;
   1348     }
   1349 
   1350     SkPath::Verb verb() const {
   1351         return (SkPath::Verb) *fVerb;
   1352     }
   1353 
   1354     ptrdiff_t verbIndex() const {
   1355         return fVerb - fEdge->fVerbs.begin();
   1356     }
   1357 
   1358     int winding() const {
   1359         return fEdge->fWinding;
   1360     }
   1361 
   1362     const InEdge* fEdge;
   1363     const SkPoint* fPts;
   1364     const uint8_t* fVerb;
   1365 };
   1366 
   1367 // always constructed with SkTDArray because new edges are inserted
   1368 // this may be a inappropriate optimization, suggesting that a separate array of
   1369 // ActiveEdge* may be faster to insert and search
   1370 
   1371 // OPTIMIZATION: Brian suggests that global sorting should be unnecessary, since
   1372 // as active edges are introduced, only local sorting should be required
   1373 class ActiveEdge {
   1374 public:
   1375     // this logic must be kept in sync with tooCloseToCall
   1376     // callers expect this to only read fAbove, fTangent
   1377     bool operator<(const ActiveEdge& rh) const {
   1378         if (fVerb == rh.fVerb) {
   1379             // FIXME: don't know what to do if verb is quad, cubic
   1380             return abCompare(fAbove, fBelow, rh.fAbove, rh.fBelow);
   1381         }
   1382         // figure out which is quad, line
   1383         // if cached data says line did not intersect quad, use top/bottom
   1384         if (fVerb != SkPath::kLine_Verb ? noIntersect(rh) : rh.noIntersect(*this)) {
   1385             return abCompare(fAbove, fBelow, rh.fAbove, rh.fBelow);
   1386         }
   1387         // use whichever of top/tangent tangent/bottom overlaps more
   1388         // with line top/bot
   1389         // assumes quad/cubic can already be upconverted to cubic/cubic
   1390         const SkPoint* line[2];
   1391         const SkPoint* curve[4];
   1392         if (fVerb != SkPath::kLine_Verb) {
   1393             line[0] = &rh.fAbove;
   1394             line[1] = &rh.fBelow;
   1395             curve[0] = &fAbove;
   1396             curve[1] = &fTangent;
   1397             curve[2] = &fBelow;
   1398         } else {
   1399             line[0] = &fAbove;
   1400             line[1] = &fBelow;
   1401             curve[0] = &rh.fAbove;
   1402             curve[1] = &rh.fTangent;
   1403             curve[2] = &rh.fBelow;
   1404         }
   1405         // FIXME: code has been abandoned, incomplete....
   1406         return false;
   1407     }
   1408 
   1409     bool abCompare(const SkPoint& a1, const SkPoint& a2, const SkPoint& b1,
   1410             const SkPoint& b2) const {
   1411         double topD = a1.fX - b1.fX;
   1412         if (b1.fY < a1.fY) {
   1413             topD = (b2.fY - b1.fY) * topD - (a1.fY - b1.fY) * (b2.fX - b1.fX);
   1414         } else if (b1.fY > a1.fY) {
   1415             topD = (a2.fY - a1.fY) * topD + (b1.fY - a1.fY) * (a2.fX - a1.fX);
   1416         }
   1417         double botD = a2.fX - b2.fX;
   1418         if (b2.fY > a2.fY) {
   1419             botD = (b2.fY - b1.fY) * botD - (a2.fY - b2.fY) * (b2.fX - b1.fX);
   1420         } else if (b2.fY < a2.fY) {
   1421             botD = (a2.fY - a1.fY) * botD + (b2.fY - a2.fY) * (a2.fX - a1.fX);
   1422         }
   1423         // return sign of greater absolute value
   1424         return (fabs(topD) > fabs(botD) ? topD : botD) < 0;
   1425     }
   1426 
   1427     // If a pair of edges are nearly coincident for some span, add a T in the
   1428     // edge so it can be shortened to match the other edge. Note that another
   1429     // approach is to trim the edge after it is added to the OutBuilder list --
   1430     // FIXME: since this has no effect if the edge is already done (i.e.,
   1431     // fYBottom >= y) maybe this can only be done by calling trimLine later.
   1432     void addTatYBelow(SkScalar y) {
   1433         if (fBelow.fY <= y || fYBottom >= y) {
   1434             return;
   1435         }
   1436         addTatYInner(y);
   1437         fFixBelow = true;
   1438     }
   1439 
   1440     void addTatYAbove(SkScalar y) {
   1441         if (fBelow.fY <= y) {
   1442             return;
   1443         }
   1444         addTatYInner(y);
   1445     }
   1446 
   1447     void addTatYInner(SkScalar y) {
   1448         if (fWorkEdge.fPts[0].fY > y) {
   1449             backup(y);
   1450         }
   1451         SkScalar left = fWorkEdge.fPts[0].fX;
   1452         SkScalar right = fWorkEdge.fPts[1].fX;
   1453         if (left > right) {
   1454             SkTSwap(left, right);
   1455         }
   1456         double ts[2];
   1457         SkASSERT(fWorkEdge.fVerb[0] == SkPath::kLine_Verb);
   1458         int pts = LineIntersect(fWorkEdge.fPts, left, right, y, ts);
   1459         SkASSERT(pts == 1);
   1460         // An ActiveEdge or WorkEdge has no need to modify the T values computed
   1461         // in the InEdge, except in the following case. If a pair of edges are
   1462         // nearly coincident, this may not be detected when the edges are
   1463         // intersected. Later, when sorted, and this near-coincidence is found,
   1464         // an additional t value must be added, requiring the cast below.
   1465         InEdge* writable = const_cast<InEdge*>(fWorkEdge.fEdge);
   1466         int insertedAt = writable->add(ts, pts, fWorkEdge.verbIndex());
   1467     #if DEBUG_ADJUST_COINCIDENT
   1468         SkDebugf("%s edge=%d y=%1.9g t=%1.9g\n", __FUNCTION__, ID(), y, ts[0]);
   1469     #endif
   1470         if (insertedAt >= 0) {
   1471             if (insertedAt + 1 < fTIndex) {
   1472                 SkASSERT(insertedAt + 2 == fTIndex);
   1473                 --fTIndex;
   1474             }
   1475         }
   1476     }
   1477 
   1478     bool advanceT() {
   1479         SkASSERT(fTIndex <= fTs->count() - fExplicitTs);
   1480         return ++fTIndex <= fTs->count() - fExplicitTs;
   1481     }
   1482 
   1483     bool advance() {
   1484     // FIXME: flip sense of next
   1485         bool result = fWorkEdge.advance();
   1486         fDone = !result;
   1487         initT();
   1488         return result;
   1489     }
   1490 
   1491     void backup(SkScalar y) {
   1492         do {
   1493             SkASSERT(fWorkEdge.fEdge->fVerbs.begin() < fWorkEdge.fVerb);
   1494             fWorkEdge.fPts -= *--fWorkEdge.fVerb;
   1495             SkASSERT(fWorkEdge.fEdge->fPts.begin() <= fWorkEdge.fPts);
   1496         } while (fWorkEdge.fPts[0].fY >= y);
   1497         initT();
   1498         SkASSERT(!fExplicitTs);
   1499         fTIndex = fTs->count() + 1;
   1500     }
   1501 
   1502     void calcAboveBelow(double tAbove, double tBelow) {
   1503         fVerb = fWorkEdge.verb();
   1504         switch (fVerb) {
   1505             case SkPath::kLine_Verb:
   1506                 LineXYAtT(fWorkEdge.fPts, tAbove, &fAbove);
   1507                 LineXYAtT(fWorkEdge.fPts, tBelow, &fTangent);
   1508                 fBelow = fTangent;
   1509                 break;
   1510             case SkPath::kQuad_Verb:
   1511                 // FIXME: put array in struct to avoid copy?
   1512                 SkPoint quad[3];
   1513                 QuadSubDivide(fWorkEdge.fPts, tAbove, tBelow, quad);
   1514                 fAbove = quad[0];
   1515                 fTangent = quad[0] != quad[1] ? quad[1] : quad[2];
   1516                 fBelow = quad[2];
   1517                 break;
   1518             case SkPath::kCubic_Verb:
   1519                 SkPoint cubic[3];
   1520                 CubicSubDivide(fWorkEdge.fPts, tAbove, tBelow, cubic);
   1521                 fAbove = cubic[0];
   1522                 // FIXME: can't see how quad logic for how tangent is used
   1523                 // extends to cubic
   1524                 fTangent = cubic[0] != cubic[1] ? cubic[1]
   1525                         : cubic[0] != cubic[2] ? cubic[2] : cubic[3];
   1526                 fBelow = cubic[3];
   1527                 break;
   1528             default:
   1529                 SkASSERT(0);
   1530         }
   1531     }
   1532 
   1533     void calcLeft(SkScalar y) {
   1534         // OPTIMIZE: put a kDone_Verb at the end of the verb list?
   1535         if (fDone || fBelow.fY > y) {
   1536             return; // nothing to do; use last
   1537         }
   1538         calcLeft();
   1539         if (fAbove.fY == fBelow.fY) {
   1540             SkDebugf("%s edge=%d fAbove.fY != fBelow.fY %1.9g\n", __FUNCTION__,
   1541                     ID(), fAbove.fY);
   1542         }
   1543     }
   1544 
   1545     void calcLeft() {
   1546         int add = (fTIndex <= fTs->count() - fExplicitTs) - 1;
   1547         double tAbove = t(fTIndex + add);
   1548         double tBelow = t(fTIndex - ~add);
   1549         // OPTIMIZATION: if fAbove, fBelow have already been computed
   1550         //  for the fTIndex, don't do it again
   1551         calcAboveBelow(tAbove, tBelow);
   1552         // For identical x, this lets us know which edge is first.
   1553         // If both edges have T values < 1, check x at next T (fBelow).
   1554         SkASSERT(tAbove != tBelow);
   1555         // FIXME: this can loop forever
   1556         // need a break if we hit the end
   1557         // FIXME: in unit test, figure out how explicit Ts work as well
   1558         while (fAbove.fY == fBelow.fY) {
   1559             if (add < 0 || fTIndex == fTs->count()) {
   1560                 add -= 1;
   1561                 SkASSERT(fTIndex + add >= 0);
   1562                 tAbove = t(fTIndex + add);
   1563             } else {
   1564                 add += 1;
   1565                 SkASSERT(fTIndex - ~add <= fTs->count() + 1);
   1566                 tBelow = t(fTIndex - ~add);
   1567             }
   1568             calcAboveBelow(tAbove, tBelow);
   1569         }
   1570         fTAbove = tAbove;
   1571         fTBelow = tBelow;
   1572     }
   1573 
   1574     bool done(SkScalar bottom) const {
   1575         return fDone || fYBottom >= bottom;
   1576     }
   1577 
   1578     void fixBelow() {
   1579         if (fFixBelow) {
   1580             fTBelow = nextT();
   1581             calcAboveBelow(fTAbove, fTBelow);
   1582             fFixBelow = false;
   1583         }
   1584     }
   1585 
   1586     void init(const InEdge* edge) {
   1587         fWorkEdge.init(edge);
   1588         fDone = false;
   1589         initT();
   1590         fBelow.fY = SK_ScalarMin;
   1591         fYBottom = SK_ScalarMin;
   1592     }
   1593 
   1594     void initT() {
   1595         const Intercepts& intercepts = fWorkEdge.fEdge->fIntercepts.front();
   1596         SkASSERT(fWorkEdge.verbIndex() <= fWorkEdge.fEdge->fIntercepts.count());
   1597         const Intercepts* interceptPtr = &intercepts + fWorkEdge.verbIndex();
   1598         fTs = &interceptPtr->fTs;
   1599         fExplicitTs = interceptPtr->fExplicit;
   1600   //  the above is conceptually the same as
   1601   //    fTs = &fWorkEdge.fEdge->fIntercepts[fWorkEdge.verbIndex()].fTs;
   1602   //  but templated arrays don't allow returning a pointer to the end() element
   1603         fTIndex = 0;
   1604         if (!fDone) {
   1605             fVerb = fWorkEdge.verb();
   1606         }
   1607         SkASSERT(fVerb > SkPath::kMove_Verb);
   1608     }
   1609 
   1610     // OPTIMIZATION: record if two edges are coincident when the are intersected
   1611     // It's unclear how to do this -- seems more complicated than recording the
   1612     // t values, since the same t values could exist intersecting non-coincident
   1613     // edges.
   1614     bool isCoincidentWith(const ActiveEdge* edge) const {
   1615         if (fAbove != edge->fAbove || fBelow != edge->fBelow) {
   1616             return false;
   1617         }
   1618         if (fVerb != edge->fVerb) {
   1619             return false;
   1620         }
   1621         switch (fVerb) {
   1622             case SkPath::kLine_Verb:
   1623                 return true;
   1624             default:
   1625                 // FIXME: add support for quads, cubics
   1626                 SkASSERT(0);
   1627                 return false;
   1628         }
   1629         return false;
   1630     }
   1631 
   1632     bool isUnordered(const ActiveEdge* edge) const {
   1633         return fAbove == edge->fAbove && fBelow == edge->fBelow;
   1634     }
   1635 
   1636 //    SkPath::Verb lastVerb() const {
   1637 //        return fDone ? fWorkEdge.lastVerb() : fWorkEdge.verb();
   1638 //    }
   1639 
   1640     const SkPoint* lastPoints() const {
   1641         return fDone ? fWorkEdge.lastPoints() : fWorkEdge.points();
   1642     }
   1643 
   1644     bool noIntersect(const ActiveEdge& ) const {
   1645         // incomplete
   1646         return false;
   1647     }
   1648 
   1649     // The shortest close call edge should be moved into a position where
   1650     // it contributes if the winding is transitioning to or from zero.
   1651     bool swapClose(const ActiveEdge* next, int prev, int wind, int mask) const {
   1652 #if DEBUG_ADJUST_COINCIDENT
   1653         SkDebugf("%s edge=%d (%g) next=%d (%g) prev=%d wind=%d nextWind=%d\n",
   1654                 __FUNCTION__, ID(), fBelow.fY, next->ID(), next->fBelow.fY,
   1655                 prev, wind, wind + next->fWorkEdge.winding());
   1656 #endif
   1657         if ((prev & mask) == 0 || (wind & mask) == 0) {
   1658             return next->fBelow.fY < fBelow.fY;
   1659         }
   1660         int nextWinding = wind + next->fWorkEdge.winding();
   1661         if ((nextWinding & mask) == 0) {
   1662             return fBelow.fY < next->fBelow.fY;
   1663         }
   1664         return false;
   1665     }
   1666 
   1667     bool swapCoincident(const ActiveEdge* edge, SkScalar bottom) const {
   1668         if (fBelow.fY >= bottom || fDone || edge->fDone) {
   1669             return false;
   1670         }
   1671         ActiveEdge thisWork = *this;
   1672         ActiveEdge edgeWork = *edge;
   1673         while ((thisWork.advanceT() || thisWork.advance())
   1674                 && (edgeWork.advanceT() || edgeWork.advance())) {
   1675             thisWork.calcLeft();
   1676             edgeWork.calcLeft();
   1677             if (thisWork < edgeWork) {
   1678                 return false;
   1679             }
   1680             if (edgeWork < thisWork) {
   1681                 return true;
   1682             }
   1683         }
   1684         return false;
   1685     }
   1686 
   1687     bool swapUnordered(const ActiveEdge* edge, SkScalar /* bottom */) const {
   1688         SkASSERT(fVerb != SkPath::kLine_Verb
   1689                 || edge->fVerb != SkPath::kLine_Verb);
   1690         if (fDone || edge->fDone) {
   1691             return false;
   1692         }
   1693         ActiveEdge thisWork, edgeWork;
   1694         extractAboveBelow(thisWork);
   1695         edge->extractAboveBelow(edgeWork);
   1696         return edgeWork < thisWork;
   1697     }
   1698 
   1699     bool tooCloseToCall(const ActiveEdge* edge) const {
   1700         int ulps;
   1701         double t1, t2, b1, b2;
   1702         // This logic must be kept in sync with operator <
   1703         if (edge->fAbove.fY < fAbove.fY) {
   1704             t1 = (edge->fTangent.fY - edge->fAbove.fY) * (fAbove.fX - edge->fAbove.fX);
   1705             t2 = (fAbove.fY - edge->fAbove.fY) * (edge->fTangent.fX - edge->fAbove.fX);
   1706         } else if (edge->fAbove.fY > fAbove.fY) {
   1707             t1 = (fTangent.fY - fAbove.fY) * (fAbove.fX - edge->fAbove.fX);
   1708             t2 = (fAbove.fY - edge->fAbove.fY) * (fTangent.fX - fAbove.fX);
   1709         } else {
   1710             t1 = fAbove.fX;
   1711             t2 = edge->fAbove.fX;
   1712         }
   1713         if (edge->fTangent.fY > fTangent.fY) {
   1714             b1 = (edge->fTangent.fY - edge->fAbove.fY) * (fTangent.fX - edge->fTangent.fX);
   1715             b2 = (fTangent.fY - edge->fTangent.fY) * (edge->fTangent.fX - edge->fAbove.fX);
   1716         } else if (edge->fTangent.fY < fTangent.fY) {
   1717             b1 = (fTangent.fY - fAbove.fY) * (fTangent.fX - edge->fTangent.fX);
   1718             b2 = (fTangent.fY - edge->fTangent.fY) * (fTangent.fX - fAbove.fX);
   1719         } else {
   1720             b1 = fTangent.fX;
   1721             b2 = edge->fTangent.fX;
   1722         }
   1723         if (fabs(t1 - t2) > fabs(b1 - b2)) {
   1724             ulps = UlpsDiff((float) t1, (float) t2);
   1725         } else {
   1726             ulps = UlpsDiff((float) b1, (float) b2);
   1727         }
   1728 #if DEBUG_ADJUST_COINCIDENT
   1729         SkDebugf("%s this=%d edge=%d ulps=%d\n", __FUNCTION__, ID(), edge->ID(),
   1730                 ulps);
   1731 #endif
   1732         if (ulps < 0 || ulps > 32) {
   1733             return false;
   1734         }
   1735         if (fVerb == SkPath::kLine_Verb && edge->fVerb == SkPath::kLine_Verb) {
   1736             return true;
   1737         }
   1738         if (fVerb != SkPath::kLine_Verb && edge->fVerb != SkPath::kLine_Verb) {
   1739             return false;
   1740         }
   1741 
   1742         double ts[2];
   1743         bool isLine = true;
   1744         bool curveQuad = true;
   1745         if (fVerb == SkPath::kCubic_Verb) {
   1746             ts[0] = (fTAbove * 2 + fTBelow) / 3;
   1747             ts[1] = (fTAbove + fTBelow * 2) / 3;
   1748             curveQuad = isLine = false;
   1749         } else if (edge->fVerb == SkPath::kCubic_Verb) {
   1750             ts[0] = (edge->fTAbove * 2 + edge->fTBelow) / 3;
   1751             ts[1] = (edge->fTAbove + edge->fTBelow * 2) / 3;
   1752             curveQuad = false;
   1753         } else if (fVerb == SkPath::kQuad_Verb) {
   1754                 ts[0] = fTAbove;
   1755                 ts[1] = (fTAbove + fTBelow) / 2;
   1756                 isLine = false;
   1757         } else {
   1758             SkASSERT(edge->fVerb == SkPath::kQuad_Verb);
   1759             ts[0] = edge->fTAbove;
   1760             ts[1] = (edge->fTAbove + edge->fTBelow) / 2;
   1761         }
   1762         const SkPoint* curvePts = isLine ? edge->lastPoints() : lastPoints();
   1763         const ActiveEdge* lineEdge = isLine ? this : edge;
   1764         SkPoint curveSample[2];
   1765         for (int index = 0; index < 2; ++index) {
   1766             if (curveQuad) {
   1767                 QuadXYAtT(curvePts, ts[index], &curveSample[index]);
   1768             } else {
   1769                 CubicXYAtT(curvePts, ts[index], &curveSample[index]);
   1770             }
   1771         }
   1772         return IsCoincident(curveSample, lineEdge->fAbove, lineEdge->fBelow);
   1773     }
   1774 
   1775     double nextT() const {
   1776         SkASSERT(fTIndex <= fTs->count() - fExplicitTs);
   1777         return t(fTIndex + 1);
   1778     }
   1779 
   1780     double t() const {
   1781         return t(fTIndex);
   1782     }
   1783 
   1784     double t(int tIndex) const {
   1785         if (fExplicitTs) {
   1786             SkASSERT(tIndex < fTs->count());
   1787             return (*fTs)[tIndex];
   1788         }
   1789         if (tIndex == 0) {
   1790             return 0;
   1791         }
   1792         if (tIndex > fTs->count()) {
   1793             return 1;
   1794         }
   1795         return (*fTs)[tIndex - 1];
   1796     }
   1797 
   1798     // FIXME: debugging only
   1799     int ID() const {
   1800         return fWorkEdge.fEdge->fID;
   1801     }
   1802 
   1803 private:
   1804     // utility used only by swapUnordered
   1805     void extractAboveBelow(ActiveEdge& extracted) const {
   1806         SkPoint curve[4];
   1807         switch (fVerb) {
   1808             case SkPath::kLine_Verb:
   1809                 extracted.fAbove = fAbove;
   1810                 extracted.fTangent = fTangent;
   1811                 return;
   1812             case SkPath::kQuad_Verb:
   1813                 QuadSubDivide(lastPoints(), fTAbove, fTBelow, curve);
   1814                 break;
   1815             case SkPath::kCubic_Verb:
   1816                 CubicSubDivide(lastPoints(), fTAbove, fTBelow, curve);
   1817                 break;
   1818             default:
   1819                 SkASSERT(0);
   1820         }
   1821         extracted.fAbove = curve[0];
   1822         extracted.fTangent = curve[1];
   1823     }
   1824 
   1825 public:
   1826     WorkEdge fWorkEdge;
   1827     const SkTDArray<double>* fTs;
   1828     SkPoint fAbove;
   1829     SkPoint fTangent;
   1830     SkPoint fBelow;
   1831     double fTAbove; // OPTIMIZATION: only required if edge has quads or cubics
   1832     double fTBelow;
   1833     SkScalar fYBottom;
   1834     int fCoincident;
   1835     int fTIndex;
   1836     SkPath::Verb fVerb;
   1837     bool fSkip; // OPTIMIZATION: use bitfields?
   1838     bool fCloseCall;
   1839     bool fDone;
   1840     bool fFixBelow;
   1841     bool fExplicitTs;
   1842 };
   1843 
   1844 static void addToActive(SkTDArray<ActiveEdge>& activeEdges, const InEdge* edge) {
   1845     size_t count = activeEdges.count();
   1846     for (size_t index = 0; index < count; ++index) {
   1847         if (edge == activeEdges[index].fWorkEdge.fEdge) {
   1848             return;
   1849         }
   1850     }
   1851     ActiveEdge* active = activeEdges.append();
   1852     active->init(edge);
   1853 }
   1854 
   1855 // Find any intersections in the range of active edges. A pair of edges, on
   1856 // either side of another edge, may change the winding contribution for part of
   1857 // the edge.
   1858 // Keep horizontal edges just for
   1859 // the purpose of computing when edges change their winding contribution, since
   1860 // this is essentially computing the horizontal intersection.
   1861 static void addBottomT(InEdge** currentPtr, InEdge** lastPtr,
   1862         HorizontalEdge** horizontal) {
   1863     InEdge** testPtr = currentPtr - 1;
   1864     HorizontalEdge* horzEdge = *horizontal;
   1865     SkScalar left = horzEdge->fLeft;
   1866     SkScalar bottom = horzEdge->fY;
   1867     while (++testPtr != lastPtr) {
   1868         InEdge* test = *testPtr;
   1869         if (test->fBounds.fBottom <= bottom || test->fBounds.fRight <= left) {
   1870             continue;
   1871         }
   1872         WorkEdge wt;
   1873         wt.init(test);
   1874         do {
   1875             HorizontalEdge** sorted = horizontal;
   1876             horzEdge = *sorted;
   1877             do {
   1878                 double wtTs[4];
   1879                 int pts;
   1880                 uint8_t verb = wt.verb();
   1881                 switch (verb) {
   1882                     case SkPath::kLine_Verb:
   1883                         pts = LineIntersect(wt.fPts, horzEdge->fLeft,
   1884                                 horzEdge->fRight, horzEdge->fY, wtTs);
   1885                         break;
   1886                     case SkPath::kQuad_Verb:
   1887                         pts = QuadIntersect(wt.fPts, horzEdge->fLeft,
   1888                                 horzEdge->fRight, horzEdge->fY, wtTs);
   1889                         break;
   1890                     case SkPath::kCubic_Verb:
   1891                         pts = CubicIntersect(wt.fPts, horzEdge->fLeft,
   1892                                 horzEdge->fRight, horzEdge->fY, wtTs);
   1893                         break;
   1894                 }
   1895                 if (pts) {
   1896 #if DEBUG_ADD_BOTTOM_TS
   1897                     for (int x = 0; x < pts; ++x) {
   1898                         SkDebugf("%s y=%g wtTs[0]=%g (%g,%g", __FUNCTION__,
   1899                                 horzEdge->fY, wtTs[x], wt.fPts[0].fX, wt.fPts[0].fY);
   1900                         for (int y = 0; y < verb; ++y) {
   1901                             SkDebugf(" %g,%g", wt.fPts[y + 1].fX, wt.fPts[y + 1].fY));
   1902                         }
   1903                         SkDebugf(")\n");
   1904                     }
   1905                     if (pts > verb) {
   1906                         SkASSERT(0); // FIXME ? should this work?
   1907                         SkDebugf("%s wtTs[1]=%g\n", __FUNCTION__, wtTs[1]);
   1908                     }
   1909 #endif
   1910                     test->add(wtTs, pts, wt.verbIndex());
   1911                 }
   1912                 horzEdge = *++sorted;
   1913             } while (horzEdge->fY == bottom
   1914                     && horzEdge->fLeft <= test->fBounds.fRight);
   1915         } while (wt.advance());
   1916     }
   1917 }
   1918 
   1919 #if DEBUG_ADD_INTERSECTING_TS
   1920 static void debugShowLineIntersection(int pts, const WorkEdge& wt,
   1921         const WorkEdge& wn, const double wtTs[2], const double wnTs[2]) {
   1922     if (!pts) {
   1923         return;
   1924     }
   1925     SkPoint wtOutPt, wnOutPt;
   1926     LineXYAtT(wt.fPts, wtTs[0], &wtOutPt);
   1927     LineXYAtT(wn.fPts, wnTs[0], &wnOutPt);
   1928     SkDebugf("%s wtTs[0]=%g (%g,%g, %g,%g) (%g,%g)\n",
   1929             __FUNCTION__,
   1930             wtTs[0], wt.fPts[0].fX, wt.fPts[0].fY,
   1931             wt.fPts[1].fX, wt.fPts[1].fY, wtOutPt.fX, wtOutPt.fY);
   1932     if (pts == 2) {
   1933         SkDebugf("%s wtTs[1]=%g\n", __FUNCTION__, wtTs[1]);
   1934     }
   1935     SkDebugf("%s wnTs[0]=%g (%g,%g, %g,%g) (%g,%g)\n",
   1936             __FUNCTION__,
   1937             wnTs[0], wn.fPts[0].fX, wn.fPts[0].fY,
   1938             wn.fPts[1].fX, wn.fPts[1].fY, wnOutPt.fX, wnOutPt.fY);
   1939     if (pts == 2) {
   1940         SkDebugf("%s wnTs[1]=%g\n", __FUNCTION__, wnTs[1]);
   1941     }
   1942 }
   1943 #else
   1944 static void debugShowLineIntersection(int , const WorkEdge& ,
   1945         const WorkEdge& , const double [2], const double [2]) {
   1946 }
   1947 #endif
   1948 
   1949 static void addIntersectingTs(InEdge** currentPtr, InEdge** lastPtr) {
   1950     InEdge** testPtr = currentPtr - 1;
   1951     // FIXME: lastPtr should be past the point of interest, so
   1952     // test below should be  lastPtr - 2
   1953     // that breaks testSimplifyTriangle22, so further investigation is needed
   1954     while (++testPtr != lastPtr - 1) {
   1955         InEdge* test = *testPtr;
   1956         InEdge** nextPtr = testPtr;
   1957         do {
   1958             InEdge* next = *++nextPtr;
   1959             // FIXME: this compares against the sentinel sometimes
   1960             // OPTIMIZATION: this may never be needed since this gets called
   1961             // in two passes now. Verify that double hits are appropriate.
   1962             if (test->cached(next)) {
   1963                 continue;
   1964             }
   1965             if (!Bounds::Intersects(test->fBounds, next->fBounds)) {
   1966                 continue;
   1967             }
   1968             WorkEdge wt, wn;
   1969             wt.init(test);
   1970             wn.init(next);
   1971             do {
   1972                 int pts;
   1973                 Intersections ts;
   1974                 bool swap = false;
   1975                 switch (wt.verb()) {
   1976                     case SkPath::kLine_Verb:
   1977                         switch (wn.verb()) {
   1978                             case SkPath::kLine_Verb: {
   1979                                 pts = LineIntersect(wt.fPts, wn.fPts, ts);
   1980                                 debugShowLineIntersection(pts, wt, wn,
   1981                                         ts.fT[0], ts.fT[1]);
   1982                                 break;
   1983                             }
   1984                             case SkPath::kQuad_Verb: {
   1985                                 swap = true;
   1986                                 pts = QuadLineIntersect(wn.fPts, wt.fPts, ts);
   1987                                 break;
   1988                             }
   1989                             case SkPath::kCubic_Verb: {
   1990                                 swap = true;
   1991                                 pts = CubicLineIntersect(wn.fPts, wt.fPts, ts);
   1992                                 break;
   1993                             }
   1994                             default:
   1995                                 SkASSERT(0);
   1996                         }
   1997                         break;
   1998                     case SkPath::kQuad_Verb:
   1999                         switch (wn.verb()) {
   2000                             case SkPath::kLine_Verb: {
   2001                                 pts = QuadLineIntersect(wt.fPts, wn.fPts, ts);
   2002                                 break;
   2003                             }
   2004                             case SkPath::kQuad_Verb: {
   2005                                 pts = QuadIntersect(wt.fPts, wn.fPts, ts);
   2006                                 break;
   2007                             }
   2008                             case SkPath::kCubic_Verb: {
   2009                                 // FIXME: promote quad to cubic
   2010                                 pts = CubicIntersect(wt.fPts, wn.fPts, ts);
   2011                                 break;
   2012                             }
   2013                             default:
   2014                                 SkASSERT(0);
   2015                         }
   2016                         break;
   2017                     case SkPath::kCubic_Verb:
   2018                         switch (wn.verb()) {
   2019                             case SkPath::kLine_Verb: {
   2020                                 pts = CubicLineIntersect(wt.fPts, wn.fPts, ts);
   2021                                 break;
   2022                             }
   2023                             case SkPath::kQuad_Verb: {
   2024                                  // FIXME: promote quad to cubic
   2025                                 pts = CubicIntersect(wt.fPts, wn.fPts, ts);
   2026                                 break;
   2027                             }
   2028                             case SkPath::kCubic_Verb: {
   2029                                 pts = CubicIntersect(wt.fPts, wn.fPts, ts);
   2030                                 break;
   2031                             }
   2032                             default:
   2033                                 SkASSERT(0);
   2034                         }
   2035                         break;
   2036                     default:
   2037                         SkASSERT(0);
   2038                 }
   2039                 test->add(ts.fT[swap], pts, wt.verbIndex());
   2040                 next->add(ts.fT[!swap], pts, wn.verbIndex());
   2041             } while (wt.bottom() <= wn.bottom() ? wt.advance() : wn.advance());
   2042         } while (nextPtr != lastPtr);
   2043     }
   2044 }
   2045 
   2046 static InEdge** advanceEdges(SkTDArray<ActiveEdge>* activeEdges,
   2047         InEdge** currentPtr, InEdge** lastPtr,  SkScalar y) {
   2048     InEdge** testPtr = currentPtr - 1;
   2049     while (++testPtr != lastPtr) {
   2050         if ((*testPtr)->fBounds.fBottom > y) {
   2051             continue;
   2052         }
   2053         if (activeEdges) {
   2054             InEdge* test = *testPtr;
   2055             ActiveEdge* activePtr = activeEdges->begin() - 1;
   2056             ActiveEdge* lastActive = activeEdges->end();
   2057             while (++activePtr != lastActive) {
   2058                 if (activePtr->fWorkEdge.fEdge == test) {
   2059                     activeEdges->remove(activePtr - activeEdges->begin());
   2060                     break;
   2061                 }
   2062             }
   2063         }
   2064         if (testPtr == currentPtr) {
   2065             ++currentPtr;
   2066         }
   2067     }
   2068     return currentPtr;
   2069 }
   2070 
   2071 // OPTIMIZE: inline?
   2072 static HorizontalEdge** advanceHorizontal(HorizontalEdge** edge, SkScalar y) {
   2073     while ((*edge)->fY < y) {
   2074         ++edge;
   2075     }
   2076     return edge;
   2077 }
   2078 
   2079 // compute bottom taking into account any intersected edges
   2080 static SkScalar computeInterceptBottom(SkTDArray<ActiveEdge>& activeEdges,
   2081         SkScalar y, SkScalar bottom) {
   2082     ActiveEdge* activePtr = activeEdges.begin() - 1;
   2083     ActiveEdge* lastActive = activeEdges.end();
   2084     while (++activePtr != lastActive) {
   2085         const InEdge* test = activePtr->fWorkEdge.fEdge;
   2086         if (!test->fContainsIntercepts) {
   2087             continue;
   2088         }
   2089         WorkEdge wt;
   2090         wt.init(test);
   2091         do {
   2092             const Intercepts& intercepts = test->fIntercepts[wt.verbIndex()];
   2093             if (intercepts.fTopIntercepts > 1) {
   2094                 SkScalar yTop = wt.fPts[0].fY;
   2095                 if (yTop > y && bottom > yTop) {
   2096                     bottom = yTop;
   2097                 }
   2098             }
   2099             if (intercepts.fBottomIntercepts > 1) {
   2100                 SkScalar yBottom = wt.fPts[wt.verb()].fY;
   2101                 if (yBottom > y && bottom > yBottom) {
   2102                     bottom = yBottom;
   2103                 }
   2104             }
   2105             const SkTDArray<double>& fTs = intercepts.fTs;
   2106             size_t count = fTs.count();
   2107             for (size_t index = 0; index < count; ++index) {
   2108                 SkScalar yIntercept;
   2109                 switch (wt.verb()) {
   2110                     case SkPath::kLine_Verb: {
   2111                         yIntercept = LineYAtT(wt.fPts, fTs[index]);
   2112                         break;
   2113                     }
   2114                     case SkPath::kQuad_Verb: {
   2115                         yIntercept = QuadYAtT(wt.fPts, fTs[index]);
   2116                         break;
   2117                     }
   2118                     case SkPath::kCubic_Verb: {
   2119                         yIntercept = CubicYAtT(wt.fPts, fTs[index]);
   2120                         break;
   2121                     }
   2122                     default:
   2123                         SkASSERT(0); // should never get here
   2124                 }
   2125                 if (yIntercept > y && bottom > yIntercept) {
   2126                     bottom = yIntercept;
   2127                 }
   2128             }
   2129         } while (wt.advance());
   2130     }
   2131 #if DEBUG_BOTTOM
   2132     SkDebugf("%s bottom=%1.9g\n", __FUNCTION__, bottom);
   2133 #endif
   2134     return bottom;
   2135 }
   2136 
   2137 static SkScalar findBottom(InEdge** currentPtr,
   2138         InEdge** edgeListEnd, SkTDArray<ActiveEdge>* activeEdges, SkScalar y,
   2139         bool /*asFill*/, InEdge**& testPtr) {
   2140     InEdge* current = *currentPtr;
   2141     SkScalar bottom = current->fBounds.fBottom;
   2142 
   2143     // find the list of edges that cross y
   2144     InEdge* test = *testPtr;
   2145     while (testPtr != edgeListEnd) {
   2146         SkScalar testTop = test->fBounds.fTop;
   2147         if (bottom <= testTop) {
   2148             break;
   2149         }
   2150         SkScalar testBottom = test->fBounds.fBottom;
   2151         // OPTIMIZATION: Shortening the bottom is only interesting when filling
   2152         // and when the edge is to the left of a longer edge. If it's a framing
   2153         // edge, or part of the right, it won't effect the longer edges.
   2154         if (testTop > y) {
   2155             bottom = testTop;
   2156             break;
   2157         }
   2158         if (y < testBottom) {
   2159             if (bottom > testBottom) {
   2160                 bottom = testBottom;
   2161             }
   2162             if (activeEdges) {
   2163                 addToActive(*activeEdges, test);
   2164             }
   2165         }
   2166         test = *++testPtr;
   2167     }
   2168 #if DEBUG_BOTTOM
   2169     SkDebugf("%s %d bottom=%1.9g\n", __FUNCTION__, activeEdges ? 2 : 1, bottom);
   2170 #endif
   2171     return bottom;
   2172 }
   2173 
   2174 static void makeEdgeList(SkTArray<InEdge>& edges, InEdge& edgeSentinel,
   2175         SkTDArray<InEdge*>& edgeList) {
   2176     size_t edgeCount = edges.count();
   2177     if (edgeCount == 0) {
   2178         return;
   2179     }
   2180     int id = 0;
   2181     for (size_t index = 0; index < edgeCount; ++index) {
   2182         InEdge& edge = edges[index];
   2183         if (!edge.fWinding) {
   2184             continue;
   2185         }
   2186         edge.fID = ++id;
   2187         *edgeList.append() = &edge;
   2188     }
   2189     *edgeList.append() = &edgeSentinel;
   2190     QSort<InEdge>(edgeList.begin(), edgeList.end() - 1);
   2191 }
   2192 
   2193 static void makeHorizontalList(SkTDArray<HorizontalEdge>& edges,
   2194         HorizontalEdge& edgeSentinel, SkTDArray<HorizontalEdge*>& edgeList) {
   2195     size_t edgeCount = edges.count();
   2196     if (edgeCount == 0) {
   2197         return;
   2198     }
   2199     for (size_t index = 0; index < edgeCount; ++index) {
   2200         *edgeList.append() = &edges[index];
   2201     }
   2202     edgeSentinel.fLeft = edgeSentinel.fRight = edgeSentinel.fY = SK_ScalarMax;
   2203     *edgeList.append() = &edgeSentinel;
   2204     QSort<HorizontalEdge>(edgeList.begin(), edgeList.end() - 1);
   2205 }
   2206 
   2207 static void skipCoincidence(int lastWinding, int winding, int windingMask,
   2208             ActiveEdge* activePtr, ActiveEdge* firstCoincident) {
   2209     if (((lastWinding & windingMask) == 0) ^ ((winding & windingMask) != 0)) {
   2210         return;
   2211     }
   2212     // FIXME: ? shouldn't this be if (lastWinding & windingMask) ?
   2213     if (lastWinding) {
   2214 #if DEBUG_ADJUST_COINCIDENT
   2215         SkDebugf("%s edge=%d 1 set skip=false\n", __FUNCTION__, activePtr->ID());
   2216 #endif
   2217         activePtr->fSkip = false;
   2218     } else {
   2219 #if DEBUG_ADJUST_COINCIDENT
   2220         SkDebugf("%s edge=%d 2 set skip=false\n", __FUNCTION__, firstCoincident->ID());
   2221 #endif
   2222         firstCoincident->fSkip = false;
   2223     }
   2224 }
   2225 
   2226 static void sortHorizontal(SkTDArray<ActiveEdge>& activeEdges,
   2227         SkTDArray<ActiveEdge*>& edgeList, SkScalar y) {
   2228     size_t edgeCount = activeEdges.count();
   2229     if (edgeCount == 0) {
   2230         return;
   2231     }
   2232 #if DEBUG_SORT_HORIZONTAL
   2233     const int tab = 3; // FIXME: debugging only
   2234     SkDebugf("%s y=%1.9g\n", __FUNCTION__, y);
   2235 #endif
   2236     size_t index;
   2237     for (index = 0; index < edgeCount; ++index) {
   2238         ActiveEdge& activeEdge = activeEdges[index];
   2239         do {
   2240             activeEdge.calcLeft(y);
   2241             // skip segments that don't span y
   2242             if (activeEdge.fAbove != activeEdge.fBelow) {
   2243                 break;
   2244             }
   2245             if (activeEdge.fDone) {
   2246 #if DEBUG_SORT_HORIZONTAL
   2247                 SkDebugf("%*s edge=%d done\n", tab, "", activeEdge.ID());
   2248 #endif
   2249                 goto nextEdge;
   2250             }
   2251 #if DEBUG_SORT_HORIZONTAL
   2252             SkDebugf("%*s edge=%d above==below\n", tab, "", activeEdge.ID());
   2253 #endif
   2254         } while (activeEdge.advanceT() || activeEdge.advance());
   2255 #if DEBUG_SORT_HORIZONTAL
   2256         SkDebugf("%*s edge=%d above=(%1.9g,%1.9g) (%1.9g) below=(%1.9g,%1.9g)"
   2257                 " (%1.9g)\n", tab, "", activeEdge.ID(),
   2258                 activeEdge.fAbove.fX, activeEdge.fAbove.fY, activeEdge.fTAbove,
   2259                 activeEdge.fBelow.fX, activeEdge.fBelow.fY, activeEdge.fTBelow);
   2260 #endif
   2261         activeEdge.fSkip = activeEdge.fCloseCall = activeEdge.fFixBelow = false;
   2262         *edgeList.append() = &activeEdge;
   2263 nextEdge:
   2264         ;
   2265     }
   2266     QSort<ActiveEdge>(edgeList.begin(), edgeList.end() - 1);
   2267 }
   2268 
   2269 // remove coincident edges
   2270 // OPTIMIZE: remove edges? This is tricky because the current logic expects
   2271 // the winding count to be maintained while skipping coincident edges. In
   2272 // addition to removing the coincident edges, the remaining edges would need
   2273 // to have a different winding value, possibly different per intercept span.
   2274 static SkScalar adjustCoincident(SkTDArray<ActiveEdge*>& edgeList,
   2275         int windingMask, SkScalar y, SkScalar bottom, OutEdgeBuilder& outBuilder)
   2276 {
   2277 #if DEBUG_ADJUST_COINCIDENT
   2278     SkDebugf("%s y=%1.9g bottom=%1.9g\n", __FUNCTION__, y, bottom);
   2279 #endif
   2280     size_t edgeCount = edgeList.count();
   2281     if (edgeCount == 0) {
   2282         return bottom;
   2283     }
   2284     ActiveEdge* activePtr, * nextPtr = edgeList[0];
   2285     size_t index;
   2286     bool foundCoincident = false;
   2287     size_t firstIndex = 0;
   2288     for (index = 1; index < edgeCount; ++index) {
   2289         activePtr = nextPtr;
   2290         nextPtr = edgeList[index];
   2291         if (firstIndex != index - 1 && activePtr->fVerb > SkPath::kLine_Verb
   2292                 && nextPtr->fVerb == SkPath::kLine_Verb
   2293                 && activePtr->isUnordered(nextPtr)) {
   2294             // swap the line with the curve
   2295             // back up to the previous edge and retest
   2296             SkTSwap<ActiveEdge*>(edgeList[index - 1], edgeList[index]);
   2297             SkASSERT(index > 1);
   2298             index -= 2;
   2299             nextPtr = edgeList[index];
   2300             continue;
   2301         }
   2302         bool closeCall = false;
   2303         activePtr->fCoincident = firstIndex;
   2304         if (activePtr->isCoincidentWith(nextPtr)
   2305                 || (closeCall = activePtr->tooCloseToCall(nextPtr))) {
   2306             activePtr->fSkip = nextPtr->fSkip = foundCoincident = true;
   2307             activePtr->fCloseCall = nextPtr->fCloseCall = closeCall;
   2308         } else if (activePtr->isUnordered(nextPtr)) {
   2309             foundCoincident = true;
   2310         } else {
   2311             firstIndex = index;
   2312         }
   2313     }
   2314     nextPtr->fCoincident = firstIndex;
   2315     if (!foundCoincident) {
   2316         return bottom;
   2317     }
   2318     int winding = 0;
   2319     nextPtr = edgeList[0];
   2320     for (index = 1; index < edgeCount; ++index) {
   2321         int priorWinding = winding;
   2322         winding += activePtr->fWorkEdge.winding();
   2323         activePtr = nextPtr;
   2324         nextPtr = edgeList[index];
   2325         SkASSERT(activePtr == edgeList[index - 1]);
   2326         SkASSERT(nextPtr == edgeList[index]);
   2327         if (activePtr->fCoincident != nextPtr->fCoincident) {
   2328             continue;
   2329         }
   2330         // the coincident edges may not have been sorted above -- advance
   2331         // the edges and resort if needed
   2332         // OPTIMIZE: if sorting is done incrementally as new edges are added
   2333         // and not all at once as is done here, fold this test into the
   2334         // current less than test.
   2335         while ((!activePtr->fSkip || !nextPtr->fSkip)
   2336                 && activePtr->fCoincident == nextPtr->fCoincident) {
   2337             if (activePtr->swapUnordered(nextPtr, bottom)) {
   2338                 winding -= activePtr->fWorkEdge.winding();
   2339                 SkASSERT(activePtr == edgeList[index - 1]);
   2340                 SkASSERT(nextPtr == edgeList[index]);
   2341                 SkTSwap<ActiveEdge*>(edgeList[index - 1], edgeList[index]);
   2342                 if (--index == 0) {
   2343                     winding += activePtr->fWorkEdge.winding();
   2344                     break;
   2345                 }
   2346                 // back up one
   2347                 activePtr = edgeList[index - 1];
   2348                 continue;
   2349             }
   2350             SkASSERT(activePtr == edgeList[index - 1]);
   2351             SkASSERT(nextPtr == edgeList[index]);
   2352             break;
   2353         }
   2354         if (activePtr->fSkip && nextPtr->fSkip) {
   2355             if (activePtr->fCloseCall ? activePtr->swapClose(nextPtr,
   2356                     priorWinding, winding, windingMask)
   2357                     : activePtr->swapCoincident(nextPtr, bottom)) {
   2358                 winding -= activePtr->fWorkEdge.winding();
   2359                 SkASSERT(activePtr == edgeList[index - 1]);
   2360                 SkASSERT(nextPtr == edgeList[index]);
   2361                 SkTSwap<ActiveEdge*>(edgeList[index - 1], edgeList[index]);
   2362                 SkTSwap<ActiveEdge*>(activePtr, nextPtr);
   2363                 winding += activePtr->fWorkEdge.winding();
   2364                 SkASSERT(activePtr == edgeList[index - 1]);
   2365                 SkASSERT(nextPtr == edgeList[index]);
   2366             }
   2367         }
   2368     }
   2369     int firstCoincidentWinding = 0;
   2370     ActiveEdge* firstCoincident = NULL;
   2371     winding = 0;
   2372     activePtr = edgeList[0];
   2373     for (index = 1; index < edgeCount; ++index) {
   2374         int priorWinding = winding;
   2375         winding += activePtr->fWorkEdge.winding();
   2376         nextPtr = edgeList[index];
   2377         if (activePtr->fSkip && nextPtr->fSkip
   2378                 && activePtr->fCoincident == nextPtr->fCoincident) {
   2379             if (!firstCoincident) {
   2380                 firstCoincident = activePtr;
   2381                 firstCoincidentWinding = priorWinding;
   2382             }
   2383             if (activePtr->fCloseCall) {
   2384                 // If one of the edges has already been added to out as a non
   2385                 // coincident edge, trim it back to the top of this span
   2386                 if (outBuilder.trimLine(y, activePtr->ID())) {
   2387                     activePtr->addTatYAbove(y);
   2388             #if DEBUG_ADJUST_COINCIDENT
   2389                     SkDebugf("%s 1 edge=%d y=%1.9g (was fYBottom=%1.9g)\n",
   2390                             __FUNCTION__, activePtr->ID(), y, activePtr->fYBottom);
   2391             #endif
   2392                     activePtr->fYBottom = y;
   2393                 }
   2394                 if (outBuilder.trimLine(y, nextPtr->ID())) {
   2395                     nextPtr->addTatYAbove(y);
   2396             #if DEBUG_ADJUST_COINCIDENT
   2397                     SkDebugf("%s 2 edge=%d y=%1.9g (was fYBottom=%1.9g)\n",
   2398                             __FUNCTION__, nextPtr->ID(), y, nextPtr->fYBottom);
   2399             #endif
   2400                     nextPtr->fYBottom = y;
   2401                 }
   2402                 // add missing t values so edges can be the same length
   2403                 SkScalar testY = activePtr->fBelow.fY;
   2404                 nextPtr->addTatYBelow(testY);
   2405                 if (bottom > testY && testY > y) {
   2406             #if DEBUG_ADJUST_COINCIDENT
   2407                     SkDebugf("%s 3 edge=%d bottom=%1.9g (was bottom=%1.9g)\n",
   2408                             __FUNCTION__, activePtr->ID(), testY, bottom);
   2409             #endif
   2410                     bottom = testY;
   2411                 }
   2412                 testY = nextPtr->fBelow.fY;
   2413                 activePtr->addTatYBelow(testY);
   2414                 if (bottom > testY && testY > y) {
   2415             #if DEBUG_ADJUST_COINCIDENT
   2416                     SkDebugf("%s 4 edge=%d bottom=%1.9g (was bottom=%1.9g)\n",
   2417                             __FUNCTION__, nextPtr->ID(), testY, bottom);
   2418             #endif
   2419                     bottom = testY;
   2420                 }
   2421             }
   2422         } else if (firstCoincident) {
   2423             skipCoincidence(firstCoincidentWinding, winding, windingMask,
   2424                     activePtr, firstCoincident);
   2425             firstCoincident = NULL;
   2426         }
   2427         activePtr = nextPtr;
   2428     }
   2429     if (firstCoincident) {
   2430         winding += activePtr->fWorkEdge.winding();
   2431         skipCoincidence(firstCoincidentWinding, winding, windingMask, activePtr,
   2432                 firstCoincident);
   2433     }
   2434     // fix up the bottom for close call edges. OPTIMIZATION: maybe this could
   2435     // be in the loop above, but moved here since loop above reads fBelow and
   2436     // it felt unsafe to write it in that loop
   2437     for (index = 0; index < edgeCount; ++index) {
   2438         (edgeList[index])->fixBelow();
   2439     }
   2440     return bottom;
   2441 }
   2442 
   2443 // stitch edge and t range that satisfies operation
   2444 static void stitchEdge(SkTDArray<ActiveEdge*>& edgeList, SkScalar
   2445 #if DEBUG_STITCH_EDGE
   2446 y
   2447 #endif
   2448 ,
   2449         SkScalar bottom, int windingMask, bool fill, OutEdgeBuilder& outBuilder) {
   2450     int winding = 0;
   2451     ActiveEdge** activeHandle = edgeList.begin() - 1;
   2452     ActiveEdge** lastActive = edgeList.end();
   2453 #if DEBUG_STITCH_EDGE
   2454     const int tab = 7; // FIXME: debugging only
   2455     SkDebugf("%s y=%1.9g bottom=%1.9g\n", __FUNCTION__, y, bottom);
   2456 #endif
   2457     while (++activeHandle != lastActive) {
   2458         ActiveEdge* activePtr = *activeHandle;
   2459         const WorkEdge& wt = activePtr->fWorkEdge;
   2460         int lastWinding = winding;
   2461         winding += wt.winding();
   2462 #if DEBUG_STITCH_EDGE
   2463         SkDebugf("%*s edge=%d lastWinding=%d winding=%d skip=%d close=%d"
   2464                 " above=%1.9g below=%1.9g\n",
   2465                 tab-4, "", activePtr->ID(), lastWinding,
   2466                 winding, activePtr->fSkip, activePtr->fCloseCall,
   2467                 activePtr->fTAbove, activePtr->fTBelow);
   2468 #endif
   2469         if (activePtr->done(bottom)) {
   2470 #if DEBUG_STITCH_EDGE
   2471             SkDebugf("%*s fDone=%d || fYBottom=%1.9g >= bottom\n", tab, "",
   2472                     activePtr->fDone, activePtr->fYBottom);
   2473 #endif
   2474             continue;
   2475         }
   2476         int opener = (lastWinding & windingMask) == 0;
   2477         bool closer = (winding & windingMask) == 0;
   2478         SkASSERT(!opener | !closer);
   2479         bool inWinding = opener | closer;
   2480         SkPoint clippedPts[4];
   2481         const SkPoint* clipped = NULL;
   2482         bool moreToDo, aboveBottom;
   2483         do {
   2484             double currentT = activePtr->t();
   2485             const SkPoint* points = wt.fPts;
   2486             double nextT;
   2487             SkPath::Verb verb = activePtr->fVerb;
   2488             do {
   2489                 nextT = activePtr->nextT();
   2490                 // FIXME: obtuse: want efficient way to say
   2491                 // !currentT && currentT != 1 || !nextT && nextT != 1
   2492                 if (currentT * nextT != 0 || currentT + nextT != 1) {
   2493                     // OPTIMIZATION: if !inWinding, we only need
   2494                     // clipped[1].fY
   2495                     switch (verb) {
   2496                         case SkPath::kLine_Verb:
   2497                             LineSubDivide(points, currentT, nextT, clippedPts);
   2498                             break;
   2499                         case SkPath::kQuad_Verb:
   2500                             QuadSubDivide(points, currentT, nextT, clippedPts);
   2501                             break;
   2502                         case SkPath::kCubic_Verb:
   2503                             CubicSubDivide(points, currentT, nextT, clippedPts);
   2504                             break;
   2505                         default:
   2506                             SkASSERT(0);
   2507                             break;
   2508                     }
   2509                     clipped = clippedPts;
   2510                 } else {
   2511                     clipped = points;
   2512                 }
   2513                 if (inWinding && !activePtr->fSkip && (fill ? clipped[0].fY
   2514                         != clipped[verb].fY : clipped[0] != clipped[verb])) {
   2515 #if DEBUG_STITCH_EDGE
   2516                     SkDebugf("%*s add%s %1.9g,%1.9g %1.9g,%1.9g edge=%d"
   2517                             " v=%d t=(%1.9g,%1.9g)\n", tab, "",
   2518                             kUVerbStr[verb], clipped[0].fX, clipped[0].fY,
   2519                             clipped[verb].fX, clipped[verb].fY,
   2520                             activePtr->ID(),
   2521                             activePtr->fWorkEdge.fVerb
   2522                             - activePtr->fWorkEdge.fEdge->fVerbs.begin(),
   2523                             currentT, nextT);
   2524 #endif
   2525                     outBuilder.addCurve(clipped, (SkPath::Verb) verb,
   2526                             activePtr->fWorkEdge.fEdge->fID,
   2527                             activePtr->fCloseCall);
   2528                 } else {
   2529 #if DEBUG_STITCH_EDGE
   2530                     SkDebugf("%*s skip%s %1.9g,%1.9g %1.9g,%1.9g"
   2531                             " edge=%d v=%d t=(%1.9g,%1.9g)\n", tab, "",
   2532                             kUVerbStr[verb], clipped[0].fX, clipped[0].fY,
   2533                             clipped[verb].fX, clipped[verb].fY,
   2534                             activePtr->ID(),
   2535                             activePtr->fWorkEdge.fVerb
   2536                             - activePtr->fWorkEdge.fEdge->fVerbs.begin(),
   2537                             currentT, nextT);
   2538 #endif
   2539                 }
   2540             // by advancing fAbove/fBelow, the next call to sortHorizontal
   2541             // will use these values if they're still valid instead of
   2542             // recomputing
   2543                 if (clipped[verb].fY > activePtr->fBelow.fY
   2544                         && bottom >= activePtr->fBelow.fY
   2545                         && verb == SkPath::kLine_Verb) {
   2546                     activePtr->fAbove = activePtr->fBelow;
   2547                     activePtr->fBelow = activePtr->fTangent = clipped[verb];
   2548                     activePtr->fTAbove = activePtr->fTBelow < 1
   2549                             ? activePtr->fTBelow : 0;
   2550                     activePtr->fTBelow = nextT;
   2551                 }
   2552                 currentT = nextT;
   2553                 moreToDo = activePtr->advanceT();
   2554                 activePtr->fYBottom = clipped[verb].fY; // was activePtr->fCloseCall ? bottom :
   2555 
   2556                 // clearing the fSkip/fCloseCall bit here means that trailing edges
   2557                 // fall out of sync, if one edge is long and another is a series of short pieces
   2558                 // if fSkip/fCloseCall is set, need to recompute coincidence/too-close-to-call
   2559                 // after advancing
   2560                 // another approach would be to restrict bottom to smaller part of close call
   2561                 // maybe this is already happening with coincidence when intersection is computed,
   2562                 // and needs to be added to the close call computation as well
   2563                 // this is hard to do because that the bottom is important is not known when
   2564                 // the lines are intersected; only when the computation for edge sorting is done
   2565                 // does the need for new bottoms become apparent.
   2566                 // maybe this is good incentive to scrap the current sort and do an insertion
   2567                 // sort that can take this into consideration when the x value is computed
   2568 
   2569                 // FIXME: initialized in sortHorizontal, cleared here as well so
   2570                 // that next edge is not skipped -- but should skipped edges ever
   2571                 // continue? (probably not)
   2572                 aboveBottom = clipped[verb].fY < bottom;
   2573                 if (clipped[0].fY != clipped[verb].fY) {
   2574                     activePtr->fSkip = false;
   2575                     activePtr->fCloseCall = false;
   2576                     aboveBottom &= !activePtr->fCloseCall;
   2577                 }
   2578 #if DEBUG_STITCH_EDGE
   2579                  else {
   2580                     if (activePtr->fSkip || activePtr->fCloseCall) {
   2581                         SkDebugf("%s skip or close == %1.9g\n", __FUNCTION__,
   2582                                 clippedPts[0].fY);
   2583                     }
   2584                 }
   2585 #endif
   2586             } while (moreToDo & aboveBottom);
   2587         } while ((moreToDo || activePtr->advance()) & aboveBottom);
   2588     }
   2589 }
   2590 
   2591 #if DEBUG_DUMP
   2592 static void dumpEdgeList(const SkTDArray<InEdge*>& edgeList,
   2593         const InEdge& edgeSentinel) {
   2594     InEdge** debugPtr = edgeList.begin();
   2595     do {
   2596         (*debugPtr++)->dump();
   2597     } while (*debugPtr != &edgeSentinel);
   2598 }
   2599 #else
   2600 static void dumpEdgeList(const SkTDArray<InEdge*>& ,
   2601         const InEdge& ) {
   2602 }
   2603 #endif
   2604 
   2605 void simplify(const SkPath& path, bool asFill, SkPath& simple) {
   2606     // returns 1 for evenodd, -1 for winding, regardless of inverse-ness
   2607     int windingMask = (path.getFillType() & 1) ? 1 : -1;
   2608     simple.reset();
   2609     simple.setFillType(SkPath::kEvenOdd_FillType);
   2610     // turn path into list of edges increasing in y
   2611     // if an edge is a quad or a cubic with a y extrema, note it, but leave it
   2612     // unbroken. Once we have a list, sort it, then walk the list (walk edges
   2613     // twice that have y extrema's on top)  and detect crossings -- look for raw
   2614     // bounds that cross over, then tight bounds that cross
   2615     SkTArray<InEdge> edges;
   2616     SkTDArray<HorizontalEdge> horizontalEdges;
   2617     InEdgeBuilder builder(path, asFill, edges, horizontalEdges);
   2618     SkTDArray<InEdge*> edgeList;
   2619     InEdge edgeSentinel;
   2620     edgeSentinel.reset();
   2621     makeEdgeList(edges, edgeSentinel, edgeList);
   2622     SkTDArray<HorizontalEdge*> horizontalList;
   2623     HorizontalEdge horizontalSentinel;
   2624     makeHorizontalList(horizontalEdges, horizontalSentinel, horizontalList);
   2625     InEdge** currentPtr = edgeList.begin();
   2626     if (!currentPtr) {
   2627         return;
   2628     }
   2629     // find all intersections between edges
   2630 // beyond looking for horizontal intercepts, we need to know if any active edges
   2631 // intersect edges below 'bottom', but above the active edge segment.
   2632 // maybe it makes more sense to compute all intercepts before doing anything
   2633 // else, since the intercept list is long-lived, at least in the current design.
   2634     SkScalar y = (*currentPtr)->fBounds.fTop;
   2635     HorizontalEdge** currentHorizontal = horizontalList.begin();
   2636     do {
   2637         InEdge** lastPtr = currentPtr; // find the edge below the bottom of the first set
   2638         SkScalar bottom = findBottom(currentPtr, edgeList.end(),
   2639                 NULL, y, asFill, lastPtr);
   2640         if (lastPtr > currentPtr) {
   2641             if (currentHorizontal) {
   2642                 if ((*currentHorizontal)->fY < SK_ScalarMax) {
   2643                     addBottomT(currentPtr, lastPtr, currentHorizontal);
   2644                 }
   2645                 currentHorizontal = advanceHorizontal(currentHorizontal, bottom);
   2646             }
   2647             addIntersectingTs(currentPtr, lastPtr);
   2648         }
   2649         y = bottom;
   2650         currentPtr = advanceEdges(NULL, currentPtr, lastPtr, y);
   2651     } while (*currentPtr != &edgeSentinel);
   2652     // if a quadratic or cubic now has an intermediate T value, see if the Ts
   2653     // on either side cause the Y values to monotonically increase. If not, split
   2654     // the curve at the new T.
   2655 
   2656     // try an alternate approach which does not split curves or stitch edges
   2657     // (may still need adjustCoincident, though)
   2658     // the idea is to output non-intersecting contours, then figure out their
   2659     // respective winding contribution
   2660     // each contour will need to know whether it is CW or CCW, and then whether
   2661     // a ray from that contour hits any a contour that contains it. The ray can
   2662     // move to the left and then arbitrarily move up or down (as long as it never
   2663     // moves to the right) to find a reference sibling contour or containing
   2664     // contour. If the contour is part of an intersection, the companion contour
   2665     // that is part of the intersection can determine the containership.
   2666     if (builder.containsCurves()) {
   2667         currentPtr = edgeList.begin();
   2668         SkTArray<InEdge> splits;
   2669         do {
   2670             (*currentPtr)->splitInflectionPts(splits);
   2671         } while (*++currentPtr != &edgeSentinel);
   2672         if (splits.count()) {
   2673             for (int index = 0; index < splits.count(); ++index) {
   2674                 edges.push_back(splits[index]);
   2675             }
   2676             edgeList.reset();
   2677             makeEdgeList(edges, edgeSentinel, edgeList);
   2678         }
   2679     }
   2680     dumpEdgeList(edgeList, edgeSentinel);
   2681     // walk the sorted edges from top to bottom, computing accumulated winding
   2682     SkTDArray<ActiveEdge> activeEdges;
   2683     OutEdgeBuilder outBuilder(asFill);
   2684     currentPtr = edgeList.begin();
   2685     y = (*currentPtr)->fBounds.fTop;
   2686     do {
   2687         InEdge** lastPtr = currentPtr; // find the edge below the bottom of the first set
   2688         SkScalar bottom = findBottom(currentPtr, edgeList.end(),
   2689                 &activeEdges, y, asFill, lastPtr);
   2690         if (lastPtr > currentPtr) {
   2691             bottom = computeInterceptBottom(activeEdges, y, bottom);
   2692             SkTDArray<ActiveEdge*> activeEdgeList;
   2693             sortHorizontal(activeEdges, activeEdgeList, y);
   2694             bottom = adjustCoincident(activeEdgeList, windingMask, y, bottom,
   2695                 outBuilder);
   2696             stitchEdge(activeEdgeList, y, bottom, windingMask, asFill, outBuilder);
   2697         }
   2698         y = bottom;
   2699         // OPTIMIZATION: as edges expire, InEdge allocations could be released
   2700         currentPtr = advanceEdges(&activeEdges, currentPtr, lastPtr, y);
   2701     } while (*currentPtr != &edgeSentinel);
   2702     // assemble output path from string of pts, verbs
   2703     outBuilder.bridge();
   2704     outBuilder.assemble(simple);
   2705 }
   2706