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 SkOpSpan_DEFINED
      8 #define SkOpSpan_DEFINED
      9 
     10 #include "SkPathOpsDebug.h"
     11 #include "SkPathOpsTypes.h"
     12 #include "SkPoint.h"
     13 
     14 class SkChunkAlloc;
     15 struct SkOpAngle;
     16 class SkOpContour;
     17 class SkOpGlobalState;
     18 class SkOpSegment;
     19 class SkOpSpanBase;
     20 class SkOpSpan;
     21 
     22 // subset of op span used by terminal span (when t is equal to one)
     23 class SkOpPtT {
     24 public:
     25     enum {
     26         kIsAlias = 1,
     27         kIsDuplicate = 1
     28     };
     29 
     30     void addOpp(SkOpPtT* opp) {
     31         // find the fOpp ptr to opp
     32         SkOpPtT* oppPrev = opp->fNext;
     33         if (oppPrev == this) {
     34             return;
     35         }
     36         while (oppPrev->fNext != opp) {
     37             oppPrev = oppPrev->fNext;
     38              if (oppPrev == this) {
     39                  return;
     40              }
     41         }
     42 
     43         SkOpPtT* oldNext = this->fNext;
     44         SkASSERT(this != opp);
     45         this->fNext = opp;
     46         SkASSERT(oppPrev != oldNext);
     47         oppPrev->fNext = oldNext;
     48     }
     49 
     50     bool alias() const;
     51     bool collapsed(const SkOpPtT* ) const;
     52     bool contains(const SkOpPtT* ) const;
     53     SkOpPtT* contains(const SkOpSegment* );
     54     SkOpContour* contour() const;
     55 
     56     int debugID() const {
     57         return SkDEBUGRELEASE(fID, -1);
     58     }
     59 
     60     const SkOpAngle* debugAngle(int id) const;
     61     bool debugContains(const SkOpPtT* ) const;
     62     const SkOpPtT* debugContains(const SkOpSegment* check) const;
     63     SkOpContour* debugContour(int id);
     64     int debugLoopLimit(bool report) const;
     65     bool debugMatchID(int id) const;
     66     const SkOpPtT* debugPtT(int id) const;
     67     const SkOpSegment* debugSegment(int id) const;
     68     const SkOpSpanBase* debugSpan(int id) const;
     69     void debugValidate() const;
     70 
     71     bool deleted() const {
     72         return fDeleted;
     73     }
     74 
     75     SkOpPtT* doppelganger();
     76 
     77     bool duplicate() const {
     78         return fDuplicatePt;
     79     }
     80 
     81     void dump() const;  // available to testing only
     82     void dumpAll() const;
     83     void dumpBase() const;
     84 
     85     SkOpPtT* find(SkOpSegment* );
     86     SkOpGlobalState* globalState() const;
     87     void init(SkOpSpanBase* , double t, const SkPoint& , bool dup);
     88 
     89     void insert(SkOpPtT* span) {
     90         SkASSERT(span != this);
     91         span->fNext = fNext;
     92         fNext = span;
     93     }
     94 
     95     const SkOpPtT* next() const {
     96         return fNext;
     97     }
     98 
     99     SkOpPtT* next() {
    100         return fNext;
    101     }
    102 
    103     bool onEnd() const;
    104 
    105     static bool Overlaps(SkOpPtT* s1, SkOpPtT* e1, SkOpPtT* s2, SkOpPtT* e2,
    106             SkOpPtT** sOut, SkOpPtT** eOut) {
    107         SkOpPtT* start1 = s1->fT < e1->fT ? s1 : e1;
    108         SkOpPtT* start2 = s2->fT < e2->fT ? s2 : e2;
    109         *sOut = between(s1->fT, start2->fT, e1->fT) ? start2
    110                 : between(s2->fT, start1->fT, e2->fT) ? start1 : nullptr;
    111         SkOpPtT* end1 = s1->fT < e1->fT ? e1 : s1;
    112         SkOpPtT* end2 = s2->fT < e2->fT ? e2 : s2;
    113         *eOut = between(s1->fT, end2->fT, e1->fT) ? end2
    114                 : between(s2->fT, end1->fT, e2->fT) ? end1 : nullptr;
    115         if (*sOut == *eOut) {
    116             SkASSERT(start1->fT >= end2->fT || start2->fT >= end1->fT);
    117             return false;
    118         }
    119         SkASSERT(!*sOut || *sOut != *eOut);
    120         return *sOut && *eOut;
    121     }
    122 
    123     SkOpPtT* prev();
    124     SkOpPtT* remove();
    125     void removeNext(SkOpPtT* kept);
    126 
    127     const SkOpSegment* segment() const;
    128     SkOpSegment* segment();
    129 
    130     void setDeleted() {
    131         SkASSERT(!fDeleted);
    132         fDeleted = true;
    133     }
    134 
    135     const SkOpSpanBase* span() const {
    136         return fSpan;
    137     }
    138 
    139     SkOpSpanBase* span() {
    140         return fSpan;
    141     }
    142 
    143     const SkOpPtT* starter(const SkOpPtT* end) const {
    144         return fT < end->fT ? this : end;
    145     }
    146 
    147     double fT;
    148     SkPoint fPt;   // cache of point value at this t
    149 protected:
    150     SkOpSpanBase* fSpan;  // contains winding data
    151     SkOpPtT* fNext;  // intersection on opposite curve or alias on this curve
    152     bool fDeleted;  // set if removed from span list
    153     bool fDuplicatePt;  // set if identical pt is somewhere in the next loop
    154     SkDEBUGCODE(int fID);
    155 };
    156 
    157 class SkOpSpanBase {
    158 public:
    159     void align();
    160 
    161     bool aligned() const {
    162         return fAligned;
    163     }
    164 
    165     void alignEnd(double t, const SkPoint& pt);
    166 
    167     void bumpSpanAdds() {
    168         ++fSpanAdds;
    169     }
    170 
    171     bool chased() const {
    172         return fChased;
    173     }
    174 
    175     void clearCoinEnd() {
    176         SkASSERT(fCoinEnd != this);
    177         fCoinEnd = this;
    178     }
    179 
    180     const SkOpSpanBase* coinEnd() const {
    181         return fCoinEnd;
    182     }
    183 
    184     bool contains(const SkOpSpanBase* ) const;
    185     SkOpPtT* contains(const SkOpSegment* );
    186 
    187     bool containsCoinEnd(const SkOpSpanBase* coin) const {
    188         SkASSERT(this != coin);
    189         const SkOpSpanBase* next = this;
    190         while ((next = next->fCoinEnd) != this) {
    191             if (next == coin) {
    192                 return true;
    193             }
    194         }
    195         return false;
    196     }
    197 
    198     bool containsCoinEnd(const SkOpSegment* ) const;
    199     SkOpContour* contour() const;
    200 
    201     int debugBumpCount() {
    202         return SkDEBUGRELEASE(++fCount, -1);
    203     }
    204 
    205     int debugID() const {
    206         return SkDEBUGRELEASE(fID, -1);
    207     }
    208 
    209     bool debugAlignedEnd(double t, const SkPoint& pt) const;
    210     bool debugAlignedInner() const;
    211     const SkOpAngle* debugAngle(int id) const;
    212     bool debugCoinEndLoopCheck() const;
    213     bool debugContains(const SkOpSegment* ) const;
    214     SkOpContour* debugContour(int id);
    215     const SkOpPtT* debugPtT(int id) const;
    216     const SkOpSegment* debugSegment(int id) const;
    217     const SkOpSpanBase* debugSpan(int id) const;
    218     const SkOpSpan* debugStarter(SkOpSpanBase const** endPtr) const;
    219     SkOpGlobalState* globalState() const;
    220     void debugValidate() const;
    221 
    222     bool deleted() const {
    223         return fPtT.deleted();
    224     }
    225 
    226     void dump() const;  // available to testing only
    227     void dumpCoin() const;
    228     void dumpAll() const;
    229     void dumpBase() const;
    230 
    231     bool final() const {
    232         return fPtT.fT == 1;
    233     }
    234 
    235     SkOpAngle* fromAngle() const {
    236         return fFromAngle;
    237     }
    238 
    239     void initBase(SkOpSegment* parent, SkOpSpan* prev, double t, const SkPoint& pt);
    240 
    241     void insertCoinEnd(SkOpSpanBase* coin) {
    242         if (containsCoinEnd(coin)) {
    243             SkASSERT(coin->containsCoinEnd(this));
    244             return;
    245         }
    246         debugValidate();
    247         SkASSERT(this != coin);
    248         SkOpSpanBase* coinNext = coin->fCoinEnd;
    249         coin->fCoinEnd = this->fCoinEnd;
    250         this->fCoinEnd = coinNext;
    251         debugValidate();
    252     }
    253 
    254     void merge(SkOpSpan* span);
    255 
    256     SkOpSpan* prev() const {
    257         return fPrev;
    258     }
    259 
    260     const SkPoint& pt() const {
    261         return fPtT.fPt;
    262     }
    263 
    264     const SkOpPtT* ptT() const {
    265         return &fPtT;
    266     }
    267 
    268     SkOpPtT* ptT() {
    269         return &fPtT;
    270     }
    271 
    272     SkOpSegment* segment() const {
    273         return fSegment;
    274     }
    275 
    276     void setAligned() {
    277         fAligned = true;
    278     }
    279 
    280     void setChased(bool chased) {
    281         fChased = chased;
    282     }
    283 
    284     SkOpPtT* setCoinEnd(SkOpSpanBase* oldCoinEnd, SkOpSegment* oppSegment);
    285 
    286     void setFromAngle(SkOpAngle* angle) {
    287         fFromAngle = angle;
    288     }
    289 
    290     void setPrev(SkOpSpan* prev) {
    291         fPrev = prev;
    292     }
    293 
    294     bool simple() const {
    295         fPtT.debugValidate();
    296         return fPtT.next()->next() == &fPtT;
    297     }
    298 
    299     int spanAddsCount() const {
    300         return fSpanAdds;
    301     }
    302 
    303     const SkOpSpan* starter(const SkOpSpanBase* end) const {
    304         const SkOpSpanBase* result = t() < end->t() ? this : end;
    305         return result->upCast();
    306     }
    307 
    308     SkOpSpan* starter(SkOpSpanBase* end) {
    309         SkASSERT(this->segment() == end->segment());
    310         SkOpSpanBase* result = t() < end->t() ? this : end;
    311         return result->upCast();
    312     }
    313 
    314     SkOpSpan* starter(SkOpSpanBase** endPtr) {
    315         SkOpSpanBase* end = *endPtr;
    316         SkASSERT(this->segment() == end->segment());
    317         SkOpSpanBase* result;
    318         if (t() < end->t()) {
    319             result = this;
    320         } else {
    321             result = end;
    322             *endPtr = this;
    323         }
    324         return result->upCast();
    325     }
    326 
    327     int step(const SkOpSpanBase* end) const {
    328         return t() < end->t() ? 1 : -1;
    329     }
    330 
    331     double t() const {
    332         return fPtT.fT;
    333     }
    334 
    335     void unaligned() {
    336         fAligned = false;
    337     }
    338 
    339     SkOpSpan* upCast() {
    340         SkASSERT(!final());
    341         return (SkOpSpan*) this;
    342     }
    343 
    344     const SkOpSpan* upCast() const {
    345         SkASSERT(!final());
    346         return (const SkOpSpan*) this;
    347     }
    348 
    349     SkOpSpan* upCastable() {
    350         return final() ? nullptr : upCast();
    351     }
    352 
    353     const SkOpSpan* upCastable() const {
    354         return final() ? nullptr : upCast();
    355     }
    356 
    357 private:
    358     void alignInner();
    359 
    360 protected:  // no direct access to internals to avoid treating a span base as a span
    361     SkOpPtT fPtT;  // list of points and t values associated with the start of this span
    362     SkOpSegment* fSegment;  // segment that contains this span
    363     SkOpSpanBase* fCoinEnd;  // linked list of coincident spans that end here (may point to itself)
    364     SkOpAngle* fFromAngle;  // points to next angle from span start to end
    365     SkOpSpan* fPrev;  // previous intersection point
    366     int fSpanAdds;  // number of times intersections have been added to span
    367     bool fAligned;
    368     bool fChased;  // set after span has been added to chase array
    369     SkDEBUGCODE(int fCount);  // number of pt/t pairs added
    370     SkDEBUGCODE(int fID);
    371 };
    372 
    373 class SkOpSpan : public SkOpSpanBase {
    374 public:
    375     bool alreadyAdded() const {
    376         if (fAlreadyAdded) {
    377             return true;
    378         }
    379         fAlreadyAdded = true;
    380         return false;
    381     }
    382 
    383     bool clearCoincident() {
    384         SkASSERT(!final());
    385         if (fCoincident == this) {
    386             return false;
    387         }
    388         fCoincident = this;
    389         return true;
    390     }
    391 
    392     int computeWindSum();
    393     bool containsCoincidence(const SkOpSegment* ) const;
    394 
    395     bool containsCoincidence(const SkOpSpan* coin) const {
    396         SkASSERT(this != coin);
    397         const SkOpSpan* next = this;
    398         while ((next = next->fCoincident) != this) {
    399             if (next == coin) {
    400                 return true;
    401             }
    402         }
    403         return false;
    404     }
    405 
    406     bool debugCoinLoopCheck() const;
    407     void detach(SkOpPtT* );
    408 
    409     bool done() const {
    410         SkASSERT(!final());
    411         return fDone;
    412     }
    413 
    414     void dumpCoin() const;
    415     bool dumpSpan() const;
    416     void init(SkOpSegment* parent, SkOpSpan* prev, double t, const SkPoint& pt);
    417 
    418     void insertCoincidence(SkOpSpan* coin) {
    419         if (containsCoincidence(coin)) {
    420             SkASSERT(coin->containsCoincidence(this));
    421             return;
    422         }
    423         debugValidate();
    424         SkASSERT(this != coin);
    425         SkOpSpan* coinNext = coin->fCoincident;
    426         coin->fCoincident = this->fCoincident;
    427         this->fCoincident = coinNext;
    428         debugValidate();
    429     }
    430 
    431     bool isCanceled() const {
    432         SkASSERT(!final());
    433         return fWindValue == 0 && fOppValue == 0;
    434     }
    435 
    436     bool isCoincident() const {
    437         SkASSERT(!final());
    438         return fCoincident != this;
    439     }
    440 
    441     SkOpSpanBase* next() const {
    442         SkASSERT(!final());
    443         return fNext;
    444     }
    445 
    446     int oppSum() const {
    447         SkASSERT(!final());
    448         return fOppSum;
    449     }
    450 
    451     int oppValue() const {
    452         SkASSERT(!final());
    453         return fOppValue;
    454     }
    455 
    456     SkOpPtT* setCoinStart(SkOpSpan* oldCoinStart, SkOpSegment* oppSegment);
    457 
    458     void setDone(bool done) {
    459         SkASSERT(!final());
    460         fDone = done;
    461     }
    462 
    463     void setNext(SkOpSpanBase* nextT) {
    464         SkASSERT(!final());
    465         fNext = nextT;
    466     }
    467 
    468     void setOppSum(int oppSum);
    469 
    470     void setOppValue(int oppValue) {
    471         SkASSERT(!final());
    472         SkASSERT(fOppSum == SK_MinS32);
    473         fOppValue = oppValue;
    474     }
    475 
    476     void setToAngle(SkOpAngle* angle) {
    477         SkASSERT(!final());
    478         fToAngle = angle;
    479     }
    480 
    481     void setWindSum(int windSum);
    482 
    483     void setWindValue(int windValue) {
    484         SkASSERT(!final());
    485         SkASSERT(windValue >= 0);
    486         SkASSERT(fWindSum == SK_MinS32);
    487         fWindValue = windValue;
    488     }
    489 
    490     bool sortableTop(SkOpContour* );
    491 
    492     SkOpAngle* toAngle() const {
    493         SkASSERT(!final());
    494         return fToAngle;
    495     }
    496 
    497     int windSum() const {
    498         SkASSERT(!final());
    499         return fWindSum;
    500     }
    501 
    502     int windValue() const {
    503         SkASSERT(!final());
    504         return fWindValue;
    505     }
    506 
    507 private:  // no direct access to internals to avoid treating a span base as a span
    508     SkOpSpan* fCoincident;  // linked list of spans coincident with this one (may point to itself)
    509     SkOpAngle* fToAngle;  // points to next angle from span start to end
    510     SkOpSpanBase* fNext;  // next intersection point
    511     int fWindSum;  // accumulated from contours surrounding this one.
    512     int fOppSum;  // for binary operators: the opposite winding sum
    513     int fWindValue;  // 0 == canceled; 1 == normal; >1 == coincident
    514     int fOppValue;  // normally 0 -- when binary coincident edges combine, opp value goes here
    515     int fTopTTry; // specifies direction and t value to try next
    516     bool fDone;  // if set, this span to next higher T has been processed
    517     mutable bool fAlreadyAdded;
    518 };
    519 
    520 #endif
    521