Home | History | Annotate | Download | only in pathops
      1 /*
      2  * Copyright 2013 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 SkOpContour_DEFINED
      8 #define SkOpContour_DEFINED
      9 
     10 #include "SkOpSegment.h"
     11 #include "SkTDArray.h"
     12 #include "SkTSort.h"
     13 
     14 class SkChunkAlloc;
     15 enum class SkOpRayDir;
     16 struct SkOpRayHit;
     17 class SkPathWriter;
     18 
     19 class SkOpContour {
     20 public:
     21     SkOpContour() {
     22         reset();
     23     }
     24 
     25     ~SkOpContour() {
     26         if (fNext) {
     27             fNext->~SkOpContour();
     28         }
     29     }
     30 
     31     bool operator<(const SkOpContour& rh) const {
     32         return fBounds.fTop == rh.fBounds.fTop
     33                 ? fBounds.fLeft < rh.fBounds.fLeft
     34                 : fBounds.fTop < rh.fBounds.fTop;
     35     }
     36 
     37     void addConic(SkPoint pts[3], SkScalar weight, SkChunkAlloc* allocator) {
     38         appendSegment(allocator).addConic(pts, weight, this);
     39     }
     40 
     41     void addCubic(SkPoint pts[4], SkChunkAlloc* allocator) {
     42         appendSegment(allocator).addCubic(pts, this);
     43     }
     44 
     45     SkOpSegment* addCurve(SkPath::Verb verb, const SkPoint pts[4], SkChunkAlloc* allocator);
     46 
     47     void addLine(SkPoint pts[2], SkChunkAlloc* allocator) {
     48         appendSegment(allocator).addLine(pts, this);
     49     }
     50 
     51     void addQuad(SkPoint pts[3], SkChunkAlloc* allocator) {
     52         appendSegment(allocator).addQuad(pts, this);
     53     }
     54 
     55     void align() {
     56         SkASSERT(fCount > 0);
     57         SkOpSegment* segment = &fHead;
     58         do {
     59             segment->align();
     60         } while ((segment = segment->next()));
     61     }
     62 
     63     SkOpSegment& appendSegment(SkChunkAlloc* allocator) {
     64         SkOpSegment* result = fCount++
     65                 ? SkOpTAllocator<SkOpSegment>::Allocate(allocator) : &fHead;
     66         result->setPrev(fTail);
     67         if (fTail) {
     68             fTail->setNext(result);
     69         }
     70         fTail = result;
     71         return *result;
     72     }
     73 
     74     SkOpContour* appendContour(SkChunkAlloc* allocator) {
     75         SkOpContour* contour = SkOpTAllocator<SkOpContour>::New(allocator);
     76         contour->setNext(NULL);
     77         SkOpContour* prev = this;
     78         SkOpContour* next;
     79         while ((next = prev->next())) {
     80             prev = next;
     81         }
     82         prev->setNext(contour);
     83         return contour;
     84     }
     85 
     86     const SkPathOpsBounds& bounds() const {
     87         return fBounds;
     88     }
     89 
     90     void calcAngles(SkChunkAlloc* allocator) {
     91         SkASSERT(fCount > 0);
     92         SkOpSegment* segment = &fHead;
     93         do {
     94             segment->calcAngles(allocator);
     95         } while ((segment = segment->next()));
     96     }
     97 
     98     void complete() {
     99         setBounds();
    100     }
    101 
    102     int count() const {
    103         return fCount;
    104     }
    105 
    106     int debugID() const {
    107         return SkDEBUGRELEASE(fID, -1);
    108     }
    109 
    110     int debugIndent() const {
    111         return SkDEBUGRELEASE(fDebugIndent, 0);
    112     }
    113 
    114 #if DEBUG_ACTIVE_SPANS
    115     void debugShowActiveSpans() {
    116         SkOpSegment* segment = &fHead;
    117         do {
    118             segment->debugShowActiveSpans();
    119         } while ((segment = segment->next()));
    120     }
    121 #endif
    122 
    123     const SkOpAngle* debugAngle(int id) const {
    124         return SkDEBUGRELEASE(this->globalState()->debugAngle(id), NULL);
    125     }
    126 
    127     SkOpContour* debugContour(int id) {
    128         return SkDEBUGRELEASE(this->globalState()->debugContour(id), NULL);
    129     }
    130 
    131     const SkOpPtT* debugPtT(int id) const {
    132         return SkDEBUGRELEASE(this->globalState()->debugPtT(id), NULL);
    133     }
    134 
    135     const SkOpSegment* debugSegment(int id) const {
    136         return SkDEBUGRELEASE(this->globalState()->debugSegment(id), NULL);
    137     }
    138 
    139     const SkOpSpanBase* debugSpan(int id) const {
    140         return SkDEBUGRELEASE(this->globalState()->debugSpan(id), NULL);
    141     }
    142 
    143     SkOpGlobalState* globalState() const {
    144         return fState;
    145     }
    146 
    147     void debugValidate() const {
    148 #if DEBUG_VALIDATE
    149         const SkOpSegment* segment = &fHead;
    150         const SkOpSegment* prior = NULL;
    151         do {
    152             segment->debugValidate();
    153             SkASSERT(segment->prev() == prior);
    154             prior = segment;
    155         } while ((segment = segment->next()));
    156         SkASSERT(prior == fTail);
    157 #endif
    158     }
    159 
    160     bool done() const {
    161         return fDone;
    162     }
    163 
    164     void dump() const;
    165     void dumpAll() const;
    166     void dumpAngles() const;
    167     void dumpContours() const;
    168     void dumpContoursAll() const;
    169     void dumpContoursAngles() const;
    170     void dumpContoursPts() const;
    171     void dumpContoursPt(int segmentID) const;
    172     void dumpContoursSegment(int segmentID) const;
    173     void dumpContoursSpan(int segmentID) const;
    174     void dumpContoursSpans() const;
    175     void dumpPt(int ) const;
    176     void dumpPts() const;
    177     void dumpPtsX() const;
    178     void dumpSegment(int ) const;
    179     void dumpSegments(SkPathOp op) const;
    180     void dumpSpan(int ) const;
    181     void dumpSpans() const;
    182 
    183     const SkPoint& end() const {
    184         return fTail->pts()[SkPathOpsVerbToPoints(fTail->verb())];
    185     }
    186 
    187     SkOpSpan* findSortableTop(SkOpContour* );
    188 
    189     SkOpSegment* first() {
    190         SkASSERT(fCount > 0);
    191         return &fHead;
    192     }
    193 
    194     const SkOpSegment* first() const {
    195         SkASSERT(fCount > 0);
    196         return &fHead;
    197     }
    198 
    199     void indentDump() const {
    200         SkDEBUGCODE(fDebugIndent += 2);
    201     }
    202 
    203     void init(SkOpGlobalState* globalState, bool operand, bool isXor) {
    204         fState = globalState;
    205         fOperand = operand;
    206         fXor = isXor;
    207         SkDEBUGCODE(fID = globalState->nextContourID());
    208     }
    209 
    210     bool isXor() const {
    211         return fXor;
    212     }
    213 
    214     void missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocator) {
    215         SkASSERT(fCount > 0);
    216         SkOpSegment* segment = &fHead;
    217         do {
    218             if (fState->angleCoincidence()) {
    219                 segment->checkAngleCoin(coincidences, allocator);
    220             } else {
    221                 segment->missingCoincidence(coincidences, allocator);
    222             }
    223         } while ((segment = segment->next()));
    224     }
    225 
    226     bool moveMultiples() {
    227         SkASSERT(fCount > 0);
    228         SkOpSegment* segment = &fHead;
    229         do {
    230             segment->moveMultiples();
    231         } while ((segment = segment->next()));
    232         return true;
    233     }
    234 
    235     void moveNearby() {
    236         SkASSERT(fCount > 0);
    237         SkOpSegment* segment = &fHead;
    238         do {
    239             segment->moveNearby();
    240         } while ((segment = segment->next()));
    241     }
    242 
    243     SkOpContour* next() {
    244         return fNext;
    245     }
    246 
    247     const SkOpContour* next() const {
    248         return fNext;
    249     }
    250 
    251     bool operand() const {
    252         return fOperand;
    253     }
    254 
    255     bool oppXor() const {
    256         return fOppXor;
    257     }
    258 
    259     void outdentDump() const {
    260         SkDEBUGCODE(fDebugIndent -= 2);
    261     }
    262 
    263     void rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits, SkChunkAlloc* );
    264 
    265     void remove(SkOpContour* contour) {
    266         if (contour == this) {
    267             SkASSERT(fCount == 0);
    268             return;
    269         }
    270         SkASSERT(contour->fNext == NULL);
    271         SkOpContour* prev = this;
    272         SkOpContour* next;
    273         while ((next = prev->next()) != contour) {
    274             SkASSERT(next);
    275             prev = next;
    276         }
    277         SkASSERT(prev);
    278         prev->setNext(NULL);
    279     }
    280 
    281     void reset() {
    282         fTail = NULL;
    283         fNext = NULL;
    284         fCount = 0;
    285         fDone = false;
    286         fTopsFound = false;
    287         SkDEBUGCODE(fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin));
    288         SkDEBUGCODE(fFirstSorted = -1);
    289         SkDEBUGCODE(fDebugIndent = 0);
    290     }
    291 
    292     void setBounds() {
    293         SkASSERT(fCount > 0);
    294         const SkOpSegment* segment = &fHead;
    295         fBounds = segment->bounds();
    296         while ((segment = segment->next())) {
    297             fBounds.add(segment->bounds());
    298         }
    299     }
    300 
    301     void setGlobalState(SkOpGlobalState* state) {
    302         fState = state;
    303     }
    304 
    305     void setNext(SkOpContour* contour) {
    306 //        SkASSERT(!fNext == !!contour);
    307         fNext = contour;
    308     }
    309 
    310     void setOperand(bool isOp) {
    311         fOperand = isOp;
    312     }
    313 
    314     void setOppXor(bool isOppXor) {
    315         fOppXor = isOppXor;
    316     }
    317 
    318     void setXor(bool isXor) {
    319         fXor = isXor;
    320     }
    321 
    322     SkPath::Verb simplifyCubic(SkPoint pts[4]);
    323 
    324     void sortAngles() {
    325         SkASSERT(fCount > 0);
    326         SkOpSegment* segment = &fHead;
    327         do {
    328             segment->sortAngles();
    329         } while ((segment = segment->next()));
    330     }
    331 
    332     const SkPoint& start() const {
    333         return fHead.pts()[0];
    334     }
    335 
    336     void toPartialBackward(SkPathWriter* path) const {
    337         const SkOpSegment* segment = fTail;
    338         do {
    339             segment->addCurveTo(segment->tail(), segment->head(), path, true);
    340         } while ((segment = segment->prev()));
    341     }
    342 
    343     void toPartialForward(SkPathWriter* path) const {
    344         const SkOpSegment* segment = &fHead;
    345         do {
    346             segment->addCurveTo(segment->head(), segment->tail(), path, true);
    347         } while ((segment = segment->next()));
    348     }
    349 
    350     void toPath(SkPathWriter* path) const;
    351     SkOpSegment* undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr);
    352 
    353 private:
    354     SkOpGlobalState* fState;
    355     SkOpSegment fHead;
    356     SkOpSegment* fTail;
    357     SkOpContour* fNext;
    358     SkPathOpsBounds fBounds;
    359     int fCount;
    360     int fFirstSorted;
    361     bool fDone;  // set by find top segment
    362     bool fTopsFound;
    363     bool fOperand;  // true for the second argument to a binary operator
    364     bool fXor;  // set if original path had even-odd fill
    365     bool fOppXor;  // set if opposite path had even-odd fill
    366     SkDEBUGCODE(int fID);
    367     SkDEBUGCODE(mutable int fDebugIndent);
    368 };
    369 
    370 class SkOpContourHead : public SkOpContour {
    371 };
    372 
    373 #endif
    374