Home | History | Annotate | Download | only in pathops
      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 #ifndef SkOpSegment_DEFINE
      8 #define SkOpSegment_DEFINE
      9 
     10 #include "SkOpAngle.h"
     11 #include "SkOpSpan.h"
     12 #include "SkPathOpsBounds.h"
     13 #include "SkPathOpsCurve.h"
     14 #include "SkTArray.h"
     15 #include "SkTDArray.h"
     16 
     17 #if defined(SK_DEBUG) || !FORCE_RELEASE
     18 #include "SkThread.h"
     19 #endif
     20 
     21 struct SkCoincidence;
     22 class SkPathWriter;
     23 
     24 class SkOpSegment {
     25 public:
     26     SkOpSegment() {
     27 #if defined(SK_DEBUG) || !FORCE_RELEASE
     28         fID = sk_atomic_inc(&SkPathOpsDebug::gSegmentID);
     29 #endif
     30     }
     31 
     32     bool operator<(const SkOpSegment& rh) const {
     33         return fBounds.fTop < rh.fBounds.fTop;
     34     }
     35 
     36     struct AlignedSpan  {
     37         double fOldT;
     38         double fT;
     39         SkPoint fOldPt;
     40         SkPoint fPt;
     41         const SkOpSegment* fSegment;
     42         const SkOpSegment* fOther1;
     43         const SkOpSegment* fOther2;
     44     };
     45 
     46     const SkPathOpsBounds& bounds() const {
     47         return fBounds;
     48     }
     49 
     50     // OPTIMIZE
     51     // when the edges are initially walked, they don't automatically get the prior and next
     52     // edges assigned to positions t=0 and t=1. Doing that would remove the need for this check,
     53     // and would additionally remove the need for similar checks in condition edges. It would
     54     // also allow intersection code to assume end of segment intersections (maybe?)
     55     bool complete() const {
     56         int count = fTs.count();
     57         return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1;
     58     }
     59 
     60     int count() const {
     61         return fTs.count();
     62     }
     63 
     64     bool done() const {
     65         SkASSERT(fDoneSpans <= fTs.count());
     66         return fDoneSpans == fTs.count();
     67     }
     68 
     69     bool done(int min) const {
     70         return fTs[min].fDone;
     71     }
     72 
     73     bool done(const SkOpAngle* angle) const {
     74         return done(SkMin32(angle->start(), angle->end()));
     75     }
     76 
     77     SkDPoint dPtAtT(double mid) const {
     78         return (*CurveDPointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid);
     79     }
     80 
     81     SkVector dxdy(int index) const {
     82         return (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, fTs[index].fT);
     83     }
     84 
     85     SkScalar dy(int index) const {
     86         return dxdy(index).fY;
     87     }
     88 
     89     bool hasMultiples() const {
     90         return fMultiples;
     91     }
     92 
     93     bool hasSmall() const {
     94         return fSmall;
     95     }
     96 
     97     bool hasTiny() const {
     98         return fTiny;
     99     }
    100 
    101     bool intersected() const {
    102         return fTs.count() > 0;
    103     }
    104 
    105     bool isCanceled(int tIndex) const {
    106         return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0;
    107     }
    108 
    109     bool isConnected(int startIndex, int endIndex) const {
    110         return fTs[startIndex].fWindSum != SK_MinS32 || fTs[endIndex].fWindSum != SK_MinS32;
    111     }
    112 
    113     bool isHorizontal() const {
    114         return fBounds.fTop == fBounds.fBottom;
    115     }
    116 
    117     bool isVertical() const {
    118         return fBounds.fLeft == fBounds.fRight;
    119     }
    120 
    121     bool isVertical(int start, int end) const {
    122         return (*CurveIsVertical[SkPathOpsVerbToPoints(fVerb)])(fPts, start, end);
    123     }
    124 
    125     bool operand() const {
    126         return fOperand;
    127     }
    128 
    129     int oppSign(const SkOpAngle* angle) const {
    130         SkASSERT(angle->segment() == this);
    131         return oppSign(angle->start(), angle->end());
    132     }
    133 
    134     int oppSign(int startIndex, int endIndex) const {
    135         int result = startIndex < endIndex ? -fTs[startIndex].fOppValue : fTs[endIndex].fOppValue;
    136 #if DEBUG_WIND_BUMP
    137         SkDebugf("%s oppSign=%d\n", __FUNCTION__, result);
    138 #endif
    139         return result;
    140     }
    141 
    142     int oppSum(int tIndex) const {
    143         return fTs[tIndex].fOppSum;
    144     }
    145 
    146     int oppSum(const SkOpAngle* angle) const {
    147         int lesser = SkMin32(angle->start(), angle->end());
    148         return fTs[lesser].fOppSum;
    149     }
    150 
    151     int oppValue(int tIndex) const {
    152         return fTs[tIndex].fOppValue;
    153     }
    154 
    155     int oppValue(const SkOpAngle* angle) const {
    156         int lesser = SkMin32(angle->start(), angle->end());
    157         return fTs[lesser].fOppValue;
    158     }
    159 
    160 #if DEBUG_VALIDATE
    161     bool oppXor() const {
    162         return fOppXor;
    163     }
    164 #endif
    165 
    166     SkPoint ptAtT(double mid) const {
    167         return (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid);
    168     }
    169 
    170     const SkPoint* pts() const {
    171         return fPts;
    172     }
    173 
    174     void reset() {
    175         init(NULL, (SkPath::Verb) -1, false, false);
    176         fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
    177         fTs.reset();
    178     }
    179 
    180     bool reversePoints(const SkPoint& p1, const SkPoint& p2) const;
    181 
    182     void setOppXor(bool isOppXor) {
    183         fOppXor = isOppXor;
    184     }
    185 
    186     void setUpWinding(int index, int endIndex, int* maxWinding, int* sumWinding) {
    187         int deltaSum = spanSign(index, endIndex);
    188         *maxWinding = *sumWinding;
    189         *sumWinding -= deltaSum;
    190     }
    191 
    192     const SkOpSpan& span(int tIndex) const {
    193         return fTs[tIndex];
    194     }
    195 
    196     const SkOpAngle* spanToAngle(int tStart, int tEnd) const {
    197         SkASSERT(tStart != tEnd);
    198         const SkOpSpan& span = fTs[tStart];
    199         return tStart < tEnd ? span.fToAngle : span.fFromAngle;
    200     }
    201 
    202     // FIXME: create some sort of macro or template that avoids casting
    203     SkOpAngle* spanToAngle(int tStart, int tEnd) {
    204         const SkOpAngle* cAngle = (const_cast<const SkOpSegment*>(this))->spanToAngle(tStart, tEnd);
    205         return const_cast<SkOpAngle*>(cAngle);
    206     }
    207 
    208     int spanSign(const SkOpAngle* angle) const {
    209         SkASSERT(angle->segment() == this);
    210         return spanSign(angle->start(), angle->end());
    211     }
    212 
    213     int spanSign(int startIndex, int endIndex) const {
    214         int result = startIndex < endIndex ? -fTs[startIndex].fWindValue : fTs[endIndex].fWindValue;
    215 #if DEBUG_WIND_BUMP
    216         SkDebugf("%s spanSign=%d\n", __FUNCTION__, result);
    217 #endif
    218         return result;
    219     }
    220 
    221     double t(int tIndex) const {
    222         return fTs[tIndex].fT;
    223     }
    224 
    225     double tAtMid(int start, int end, double mid) const {
    226         return fTs[start].fT * (1 - mid) + fTs[end].fT * mid;
    227     }
    228 
    229     void updatePts(const SkPoint pts[]) {
    230         fPts = pts;
    231     }
    232 
    233     SkPath::Verb verb() const {
    234         return fVerb;
    235     }
    236 
    237     int windSum(int tIndex) const {
    238         return fTs[tIndex].fWindSum;
    239     }
    240 
    241     int windValue(int tIndex) const {
    242         return fTs[tIndex].fWindValue;
    243     }
    244 
    245 #if defined(SK_DEBUG) || DEBUG_WINDING
    246     SkScalar xAtT(int index) const {
    247         return xAtT(&fTs[index]);
    248     }
    249 #endif
    250 
    251 #if DEBUG_VALIDATE
    252     bool _xor() const {  // FIXME: used only by SkOpAngle::debugValidateLoop()
    253         return fXor;
    254     }
    255 #endif
    256 
    257     const SkPoint& xyAtT(const SkOpSpan* span) const {
    258         return span->fPt;
    259     }
    260 
    261     const SkPoint& xyAtT(int index) const {
    262         return xyAtT(&fTs[index]);
    263     }
    264 
    265 #if defined(SK_DEBUG) || DEBUG_WINDING
    266     SkScalar yAtT(int index) const {
    267         return yAtT(&fTs[index]);
    268     }
    269 #endif
    270 
    271     const SkOpAngle* activeAngle(int index, int* start, int* end, bool* done,
    272                                  bool* sortable) const;
    273     SkPoint activeLeftTop(int* firstT) const;
    274     bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op);
    275     bool activeWinding(int index, int endIndex);
    276     void addCubic(const SkPoint pts[4], bool operand, bool evenOdd);
    277     void addCurveTo(int start, int end, SkPathWriter* path, bool active) const;
    278     void addEndSpan(int endIndex);
    279     void addLine(const SkPoint pts[2], bool operand, bool evenOdd);
    280     void addOtherT(int index, double otherT, int otherIndex);
    281     void addQuad(const SkPoint pts[3], bool operand, bool evenOdd);
    282     void addSimpleAngle(int endIndex);
    283     int addSelfT(const SkPoint& pt, double newT);
    284     void addStartSpan(int endIndex);
    285     int addT(SkOpSegment* other, const SkPoint& pt, double newT);
    286     void addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other);
    287     bool addTCoincident(const SkPoint& startPt, const SkPoint& endPt, double endT,
    288                         SkOpSegment* other);
    289     const SkOpSpan* addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
    290                              const SkPoint& pt);
    291     const SkOpSpan* addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind,
    292                              const SkPoint& pt, const SkPoint& oPt);
    293     void alignMultiples(SkTDArray<AlignedSpan>* aligned);
    294     bool alignSpan(int index, double thisT, const SkPoint& thisPt);
    295     void alignSpanState(int start, int end);
    296     bool betweenTs(int lesser, double testT, int greater) const;
    297     void blindCancel(const SkCoincidence& coincidence, SkOpSegment* other);
    298     void blindCoincident(const SkCoincidence& coincidence, SkOpSegment* other);
    299     bool calcAngles();
    300     double calcMissingTEnd(const SkOpSegment* ref, double loEnd, double min, double max,
    301                            double hiEnd, const SkOpSegment* other, int thisEnd);
    302     double calcMissingTStart(const SkOpSegment* ref, double loEnd, double min, double max,
    303                              double hiEnd, const SkOpSegment* other, int thisEnd);
    304     void checkDuplicates();
    305     void checkEnds();
    306     void checkMultiples();
    307     void checkSmall();
    308     bool checkSmall(int index) const;
    309     void checkTiny();
    310     int computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType);
    311     bool containsPt(const SkPoint& , int index, int endIndex) const;
    312     int crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT, bool* hitSomething,
    313                      double mid, bool opp, bool current) const;
    314     bool findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* other, int oStart, int oEnd,
    315                              int step, SkPoint* startPt, SkPoint* endPt, double* endT) const;
    316     SkOpSegment* findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
    317                             bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask);
    318     SkOpSegment* findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd,
    319                                  bool* unsortable);
    320     SkOpSegment* findNextXor(int* nextStart, int* nextEnd, bool* unsortable);
    321     int findExactT(double t, const SkOpSegment* ) const;
    322     int findOtherT(double t, const SkOpSegment* ) const;
    323     int findT(double t, const SkPoint& , const SkOpSegment* ) const;
    324     SkOpSegment* findTop(int* tIndex, int* endIndex, bool* unsortable, bool firstPass);
    325     void fixOtherTIndex();
    326     void initWinding(int start, int end, SkOpAngle::IncludeType angleIncludeType);
    327     void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind,
    328                      SkScalar hitOppDx);
    329     bool isMissing(double startT, const SkPoint& pt) const;
    330     bool isTiny(const SkOpAngle* angle) const;
    331     bool joinCoincidence(SkOpSegment* other, double otherT, const SkPoint& otherPt, int step,
    332                          bool cancel);
    333     SkOpSpan* markAndChaseDoneBinary(int index, int endIndex);
    334     SkOpSpan* markAndChaseDoneUnary(int index, int endIndex);
    335     SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding);
    336     SkOpSpan* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
    337                         const SkOpAngle* angle);
    338     void markDone(int index, int winding);
    339     void markDoneBinary(int index);
    340     void markDoneUnary(int index);
    341     bool nextCandidate(int* start, int* end) const;
    342     int nextSpan(int from, int step) const;
    343     void pinT(const SkPoint& pt, double* t);
    344     void setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding,
    345             int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding);
    346     void sortAngles();
    347     bool subDivide(int start, int end, SkPoint edge[4]) const;
    348     bool subDivide(int start, int end, SkDCubic* result) const;
    349     void undoneSpan(int* start, int* end);
    350     int updateOppWindingReverse(const SkOpAngle* angle) const;
    351     int updateWindingReverse(const SkOpAngle* angle) const;
    352     static bool UseInnerWinding(int outerWinding, int innerWinding);
    353     static bool UseInnerWindingReverse(int outerWinding, int innerWinding);
    354     int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const;
    355     int windSum(const SkOpAngle* angle) const;
    356 // available for testing only
    357 #if defined(SK_DEBUG) || !FORCE_RELEASE
    358     int debugID() const {
    359         return fID;
    360     }
    361 #else
    362     int debugID() const {
    363         return -1;
    364     }
    365 #endif
    366 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
    367     void debugShowActiveSpans() const;
    368 #endif
    369 #if DEBUG_CONCIDENT
    370     void debugShowTs(const char* prefix) const;
    371 #endif
    372 #if DEBUG_SHOW_WINDING
    373     int debugShowWindingValues(int slotCount, int ofInterest) const;
    374 #endif
    375     const SkTDArray<SkOpSpan>& debugSpans() const;
    376     void debugValidate() const;
    377     // available to testing only
    378     const SkOpAngle* debugLastAngle() const;
    379     void dumpAngles() const;
    380     void dumpContour(int firstID, int lastID) const;
    381     void dumpPts() const;
    382     void dumpSpans() const;
    383 
    384 private:
    385     struct MissingSpan  {
    386         double fT;
    387         double fEndT;
    388         SkOpSegment* fSegment;
    389         SkOpSegment* fOther;
    390         double fOtherT;
    391         SkPoint fPt;
    392     };
    393 
    394     const SkOpAngle* activeAngleInner(int index, int* start, int* end, bool* done,
    395                                       bool* sortable) const;
    396     const SkOpAngle* activeAngleOther(int index, int* start, int* end, bool* done,
    397                                       bool* sortable) const;
    398     bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op,
    399                   int* sumMiWinding, int* sumSuWinding);
    400     bool activeWinding(int index, int endIndex, int* sumWinding);
    401     void addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other);
    402     void addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other);
    403     SkOpAngle* addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle** );
    404     SkOpAngle* addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle** );
    405     SkOpAngle* addSingletonAngles(int step);
    406     void alignSpan(const SkPoint& newPt, double newT, const SkOpSegment* other, double otherT,
    407                    const SkOpSegment* other2, SkOpSpan* oSpan, SkTDArray<AlignedSpan>* );
    408     bool betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const;
    409     void bumpCoincidentBlind(bool binary, int index, int last);
    410     void bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* index,
    411                            SkTArray<SkPoint, true>* outsideTs);
    412     void bumpCoincidentOBlind(int index, int last);
    413     void bumpCoincidentOther(const SkOpSpan& oTest, int* index,
    414                            SkTArray<SkPoint, true>* outsideTs);
    415     bool bumpSpan(SkOpSpan* span, int windDelta, int oppDelta);
    416     bool calcLoopSpanCount(const SkOpSpan& thisSpan, int* smallCounts);
    417     bool checkForSmall(const SkOpSpan* span, const SkPoint& pt, double newT,
    418                        int* less, int* more) const;
    419     void checkLinks(const SkOpSpan* ,
    420                     SkTArray<MissingSpan, true>* missingSpans) const;
    421     static void CheckOneLink(const SkOpSpan* test, const SkOpSpan* oSpan,
    422                              const SkOpSpan* oFirst, const SkOpSpan* oLast,
    423                              const SkOpSpan** missingPtr,
    424                              SkTArray<MissingSpan, true>* missingSpans);
    425     int checkSetAngle(int tIndex) const;
    426     void checkSmallCoincidence(const SkOpSpan& span, SkTArray<MissingSpan, true>* );
    427     bool coincidentSmall(const SkPoint& pt, double t, const SkOpSegment* other) const;
    428     bool clockwise(int tStart, int tEnd, bool* swap) const;
    429     static void ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
    430                               SkOpAngle::IncludeType );
    431     static void ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
    432                                      SkOpAngle::IncludeType );
    433     bool containsT(double t, const SkOpSegment* other, double otherT) const;
    434     bool decrementSpan(SkOpSpan* span);
    435     int findEndSpan(int endIndex) const;
    436     int findStartSpan(int startIndex) const;
    437     int firstActive(int tIndex) const;
    438     const SkOpSpan& firstSpan(const SkOpSpan& thisSpan) const;
    439     void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd);
    440     bool inCoincidentSpan(double t, const SkOpSegment* other) const;
    441     bool inLoop(const SkOpAngle* baseAngle, int spanCount, int* indexPtr) const;
    442 #if OLD_CHASE
    443     bool isSimple(int end) const;
    444 #else
    445     SkOpSegment* isSimple(int* end, int* step);
    446 #endif
    447     bool isTiny(int index) const;
    448     const SkOpSpan& lastSpan(const SkOpSpan& thisSpan) const;
    449     void matchWindingValue(int tIndex, double t, bool borrowWind);
    450     SkOpSpan* markAndChaseDone(int index, int endIndex, int winding);
    451     SkOpSpan* markAndChaseDoneBinary(const SkOpAngle* angle, int winding, int oppWinding);
    452     SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, int winding);
    453     SkOpSpan* markAndChaseWinding(int index, int endIndex, int winding);
    454     SkOpSpan* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding);
    455     SkOpSpan* markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle);
    456     void markDoneBinary(int index, int winding, int oppWinding);
    457     SkOpSpan* markAndChaseDoneUnary(const SkOpAngle* angle, int winding);
    458     void markOneDone(const char* funName, int tIndex, int winding);
    459     void markOneDoneBinary(const char* funName, int tIndex);
    460     void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding);
    461     void markOneDoneUnary(const char* funName, int tIndex);
    462     SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding);
    463     SkOpSpan* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding);
    464     void markWinding(int index, int winding);
    465     void markWinding(int index, int winding, int oppWinding);
    466     bool monotonicInY(int tStart, int tEnd) const;
    467 
    468     bool multipleEnds() const { return fTs[count() - 2].fT == 1; }
    469     bool multipleStarts() const { return fTs[1].fT == 0; }
    470 
    471     SkOpSegment* nextChase(int* index, int* step, int* min, SkOpSpan** last);
    472     int nextExactSpan(int from, int step) const;
    473     bool serpentine(int tStart, int tEnd) const;
    474     void setCoincidentRange(const SkPoint& startPt, const SkPoint& endPt,  SkOpSegment* other);
    475     void setFromAngle(int endIndex, SkOpAngle* );
    476     void setToAngle(int endIndex, SkOpAngle* );
    477     void setUpWindings(int index, int endIndex, int* sumMiWinding,
    478             int* maxWinding, int* sumWinding);
    479     void subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const;
    480     static void TrackOutsidePair(SkTArray<SkPoint, true>* outsideTs, const SkPoint& endPt,
    481             const SkPoint& startPt);
    482     static void TrackOutside(SkTArray<SkPoint, true>* outsideTs, const SkPoint& startPt);
    483     int updateOppWinding(int index, int endIndex) const;
    484     int updateOppWinding(const SkOpAngle* angle) const;
    485     int updateWinding(int index, int endIndex) const;
    486     int updateWinding(const SkOpAngle* angle) const;
    487     int updateWindingReverse(int index, int endIndex) const;
    488     SkOpSpan* verifyOneWinding(const char* funName, int tIndex);
    489     SkOpSpan* verifyOneWindingU(const char* funName, int tIndex);
    490 
    491     SkScalar xAtT(const SkOpSpan* span) const {
    492         return xyAtT(span).fX;
    493     }
    494 
    495     SkScalar yAtT(const SkOpSpan* span) const {
    496         return xyAtT(span).fY;
    497     }
    498 
    499     void zeroSpan(SkOpSpan* span);
    500 
    501 #if DEBUG_SWAP_TOP
    502     bool controlsContainedByEnds(int tStart, int tEnd) const;
    503 #endif
    504     void debugAddAngle(int start, int end);
    505 #if DEBUG_CONCIDENT
    506     void debugAddTPair(double t, const SkOpSegment& other, double otherT) const;
    507 #endif
    508 #if DEBUG_ANGLE
    509     void debugCheckPointsEqualish(int tStart, int tEnd) const;
    510 #endif
    511 #if DEBUG_SWAP_TOP
    512     int debugInflections(int index, int endIndex) const;
    513 #endif
    514 #if DEBUG_MARK_DONE || DEBUG_UNSORTABLE
    515     void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding);
    516     void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding, int oppWinding);
    517 #endif
    518 #if DEBUG_WINDING
    519     static char as_digit(int value) {
    520         return value < 0 ? '?' : value <= 9 ? '0' + value : '+';
    521     }
    522 #endif
    523     // available to testing only
    524     void debugConstruct();
    525     void debugConstructCubic(SkPoint shortQuad[4]);
    526     void debugConstructLine(SkPoint shortQuad[2]);
    527     void debugConstructQuad(SkPoint shortQuad[3]);
    528     void debugReset();
    529     void dumpDPts() const;
    530     void dumpSpan(int index) const;
    531 
    532     const SkPoint* fPts;
    533     SkPathOpsBounds fBounds;
    534     // FIXME: can't convert to SkTArray because it uses insert
    535     SkTDArray<SkOpSpan> fTs;  // 2+ (always includes t=0 t=1) -- at least (number of spans) + 1
    536     SkOpAngleSet fAngles;  // empty or 2+ -- (number of non-zero spans) * 2
    537     // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value
    538     int fDoneSpans;  // quick check that segment is finished
    539     // OPTIMIZATION: force the following to be byte-sized
    540     SkPath::Verb fVerb;
    541     bool fLoop;   // set if cubic intersects itself
    542     bool fMultiples;  // set if curve intersects multiple other curves at one interior point
    543     bool fOperand;
    544     bool fXor;  // set if original contour had even-odd fill
    545     bool fOppXor;  // set if opposite operand had even-odd fill
    546     bool fSmall;  // set if some span is small
    547     bool fTiny;  // set if some span is tiny
    548 #if defined(SK_DEBUG) || !FORCE_RELEASE
    549     int fID;
    550 #endif
    551 
    552     friend class PathOpsSegmentTester;
    553 };
    554 
    555 #endif
    556