/* * Copyright 2013 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #ifndef SkOpCoincidence_DEFINED #define SkOpCoincidence_DEFINED #include "SkArenaAlloc.h" #include "SkTDArray.h" #include "SkOpSpan.h" #include "SkPathOpsTypes.h" class SkOpPtT; class SkOpSpanBase; class SkCoincidentSpans { public: const SkOpPtT* coinPtTEnd() const; const SkOpPtT* coinPtTStart() const; // These return non-const pointers so that, as copies, they can be added // to a new span pair SkOpPtT* coinPtTEndWritable() const { return const_cast<SkOpPtT*>(fCoinPtTEnd); } SkOpPtT* coinPtTStartWritable() const { return const_cast<SkOpPtT*>(fCoinPtTStart); } bool collapsed(const SkOpPtT* ) const; bool contains(const SkOpPtT* s, const SkOpPtT* e) const; void correctEnds(); void correctOneEnd(const SkOpPtT* (SkCoincidentSpans::* getEnd)() const, void (SkCoincidentSpans::* setEnd)(const SkOpPtT* ptT) ); #if DEBUG_COIN void debugCorrectEnds(SkPathOpsDebug::GlitchLog* log) const; void debugCorrectOneEnd(SkPathOpsDebug::GlitchLog* log, const SkOpPtT* (SkCoincidentSpans::* getEnd)() const, void (SkCoincidentSpans::* setEnd)(const SkOpPtT* ptT) const) const; bool debugExpand(SkPathOpsDebug::GlitchLog* log) const; #endif const char* debugID() const { #if DEBUG_COIN return fGlobalState->debugCoinDictEntry().fFunctionName; #else return nullptr; #endif } void debugShow() const; #ifdef SK_DEBUG void debugStartCheck(const SkOpSpanBase* outer, const SkOpSpanBase* over, const SkOpGlobalState* debugState) const; #endif void dump() const; bool expand(); bool extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd); bool flipped() const { return fOppPtTStart->fT > fOppPtTEnd->fT; } SkDEBUGCODE(SkOpGlobalState* globalState() { return fGlobalState; }) void init(SkDEBUGCODE(SkOpGlobalState* globalState)) { sk_bzero(this, sizeof(*this)); SkDEBUGCODE(fGlobalState = globalState); } SkCoincidentSpans* next() { return fNext; } const SkCoincidentSpans* next() const { return fNext; } SkCoincidentSpans** nextPtr() { return &fNext; } const SkOpPtT* oppPtTStart() const; const SkOpPtT* oppPtTEnd() const; // These return non-const pointers so that, as copies, they can be added // to a new span pair SkOpPtT* oppPtTStartWritable() const { return const_cast<SkOpPtT*>(fOppPtTStart); } SkOpPtT* oppPtTEndWritable() const { return const_cast<SkOpPtT*>(fOppPtTEnd); } bool ordered(bool* result) const; void set(SkCoincidentSpans* next, const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd); void setCoinPtTEnd(const SkOpPtT* ptT) { SkOPASSERT(ptT == ptT->span()->ptT()); SkOPASSERT(!fCoinPtTStart || ptT->fT != fCoinPtTStart->fT); SkASSERT(!fCoinPtTStart || fCoinPtTStart->segment() == ptT->segment()); fCoinPtTEnd = ptT; ptT->setCoincident(); } void setCoinPtTStart(const SkOpPtT* ptT) { SkOPASSERT(ptT == ptT->span()->ptT()); SkOPASSERT(!fCoinPtTEnd || ptT->fT != fCoinPtTEnd->fT); SkASSERT(!fCoinPtTEnd || fCoinPtTEnd->segment() == ptT->segment()); fCoinPtTStart = ptT; ptT->setCoincident(); } void setEnds(const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTEnd) { this->setCoinPtTEnd(coinPtTEnd); this->setOppPtTEnd(oppPtTEnd); } void setOppPtTEnd(const SkOpPtT* ptT) { SkOPASSERT(ptT == ptT->span()->ptT()); SkOPASSERT(!fOppPtTStart || ptT->fT != fOppPtTStart->fT); SkASSERT(!fOppPtTStart || fOppPtTStart->segment() == ptT->segment()); fOppPtTEnd = ptT; ptT->setCoincident(); } void setOppPtTStart(const SkOpPtT* ptT) { SkOPASSERT(ptT == ptT->span()->ptT()); SkOPASSERT(!fOppPtTEnd || ptT->fT != fOppPtTEnd->fT); SkASSERT(!fOppPtTEnd || fOppPtTEnd->segment() == ptT->segment()); fOppPtTStart = ptT; ptT->setCoincident(); } void setStarts(const SkOpPtT* coinPtTStart, const SkOpPtT* oppPtTStart) { this->setCoinPtTStart(coinPtTStart); this->setOppPtTStart(oppPtTStart); } void setNext(SkCoincidentSpans* next) { fNext = next; } private: SkCoincidentSpans* fNext; const SkOpPtT* fCoinPtTStart; const SkOpPtT* fCoinPtTEnd; const SkOpPtT* fOppPtTStart; const SkOpPtT* fOppPtTEnd; SkDEBUGCODE(SkOpGlobalState* fGlobalState); }; class SkOpCoincidence { public: SkOpCoincidence(SkOpGlobalState* globalState) : fHead(nullptr) , fTop(nullptr) , fGlobalState(globalState) , fContinue(false) , fSpanDeleted(false) , fPtAllocated(false) , fCoinExtended(false) , fSpanMerged(false) { globalState->setCoincidence(this); } void add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart, SkOpPtT* oppPtTEnd); bool addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS()); bool addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS()); bool addMissing(bool* added DEBUG_COIN_DECLARE_PARAMS()); bool apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()); bool contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const; void correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS()); #if DEBUG_COIN void debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* log) const; void debugAddExpanded(SkPathOpsDebug::GlitchLog* ) const; void debugAddMissing(SkPathOpsDebug::GlitchLog* , bool* added) const; void debugAddOrOverlap(SkPathOpsDebug::GlitchLog* log, const SkOpSegment* coinSeg, const SkOpSegment* oppSeg, double coinTs, double coinTe, double oppTs, double oppTe, bool* added) const; #endif const SkOpAngle* debugAngle(int id) const { return SkDEBUGRELEASE(fGlobalState->debugAngle(id), nullptr); } void debugCheckBetween() const; #if DEBUG_COIN void debugCheckValid(SkPathOpsDebug::GlitchLog* log) const; #endif SkOpContour* debugContour(int id) const { return SkDEBUGRELEASE(fGlobalState->debugContour(id), nullptr); } #if DEBUG_COIN void debugCorrectEnds(SkPathOpsDebug::GlitchLog* log) const; bool debugExpand(SkPathOpsDebug::GlitchLog* ) const; void debugMark(SkPathOpsDebug::GlitchLog* ) const; void debugMarkCollapsed(SkPathOpsDebug::GlitchLog* , const SkCoincidentSpans* coin, const SkOpPtT* test) const; void debugMarkCollapsed(SkPathOpsDebug::GlitchLog* , const SkOpPtT* test) const; #endif const SkOpPtT* debugPtT(int id) const { return SkDEBUGRELEASE(fGlobalState->debugPtT(id), nullptr); } const SkOpSegment* debugSegment(int id) const { return SkDEBUGRELEASE(fGlobalState->debugSegment(id), nullptr); } #if DEBUG_COIN void debugRelease(SkPathOpsDebug::GlitchLog* , const SkCoincidentSpans* , const SkCoincidentSpans* ) const; void debugRelease(SkPathOpsDebug::GlitchLog* , const SkOpSegment* ) const; #endif void debugShowCoincidence() const; const SkOpSpanBase* debugSpan(int id) const { return SkDEBUGRELEASE(fGlobalState->debugSpan(id), nullptr); } void debugValidate() const; void dump() const; bool expand(DEBUG_COIN_DECLARE_ONLY_PARAMS()); bool extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd); bool findOverlaps(SkOpCoincidence* DEBUG_COIN_DECLARE_PARAMS()) const; void fixUp(SkOpPtT* deleted, const SkOpPtT* kept); SkOpGlobalState* globalState() { return fGlobalState; } const SkOpGlobalState* globalState() const { return fGlobalState; } bool isEmpty() const { return !fHead && !fTop; } bool mark(DEBUG_COIN_DECLARE_ONLY_PARAMS()); void markCollapsed(SkOpPtT* ); static bool Ordered(const SkOpPtT* coinPtTStart, const SkOpPtT* oppPtTStart) { return Ordered(coinPtTStart->segment(), oppPtTStart->segment()); } static bool Ordered(const SkOpSegment* coin, const SkOpSegment* opp); void release(const SkOpSegment* ); void releaseDeleted(); private: void add(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) { this->add(const_cast<SkOpPtT*>(coinPtTStart), const_cast<SkOpPtT*>(coinPtTEnd), const_cast<SkOpPtT*>(oppPtTStart), const_cast<SkOpPtT*>(oppPtTEnd)); } bool addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan); bool addEndMovedSpans(const SkOpPtT* ptT); bool addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over2s, double tStart, double tEnd, SkOpSegment* coinSeg, SkOpSegment* oppSeg, bool* added SkDEBUGPARAMS(const SkOpPtT* over1e) SkDEBUGPARAMS(const SkOpPtT* over2e)); bool addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg, double coinTs, double coinTe, double oppTs, double oppTe, bool* added); bool addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg1o, const SkOpSegment* seg2, const SkOpSegment* seg2o, const SkOpPtT* overS, const SkOpPtT* overE); bool checkOverlap(SkCoincidentSpans* check, const SkOpSegment* coinSeg, const SkOpSegment* oppSeg, double coinTs, double coinTe, double oppTs, double oppTe, SkTDArray<SkCoincidentSpans*>* overlaps) const; bool contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const; bool contains(const SkCoincidentSpans* coin, const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const; #if DEBUG_COIN void debugAddIfMissing(SkPathOpsDebug::GlitchLog* , const SkCoincidentSpans* outer, const SkOpPtT* over1s, const SkOpPtT* over1e) const; void debugAddIfMissing(SkPathOpsDebug::GlitchLog* , const SkOpPtT* over1s, const SkOpPtT* over2s, double tStart, double tEnd, const SkOpSegment* coinSeg, const SkOpSegment* oppSeg, bool* added, const SkOpPtT* over1e, const SkOpPtT* over2e) const; void debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* , const SkOpSpan* base, const SkOpSpanBase* testSpan) const; void debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* , const SkOpPtT* ptT) const; #endif void fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept); void markCollapsed(SkCoincidentSpans* head, SkOpPtT* test); bool overlap(const SkOpPtT* coinStart1, const SkOpPtT* coinEnd1, const SkOpPtT* coinStart2, const SkOpPtT* coinEnd2, double* overS, double* overE) const; bool release(SkCoincidentSpans* coin, SkCoincidentSpans* ); void releaseDeleted(SkCoincidentSpans* ); void restoreHead(); // return coinPtT->segment()->t mapped from overS->fT <= t <= overE->fT static double TRange(const SkOpPtT* overS, double t, const SkOpSegment* coinPtT SkDEBUGPARAMS(const SkOpPtT* overE)); SkCoincidentSpans* fHead; SkCoincidentSpans* fTop; SkOpGlobalState* fGlobalState; bool fContinue; bool fSpanDeleted; bool fPtAllocated; bool fCoinExtended; bool fSpanMerged; }; #endif