Index: src/pathops/SkOpSpan.h |
diff --git a/src/pathops/SkOpSpan.h b/src/pathops/SkOpSpan.h |
index d9ce44eb7720fb4fb4cd78521b1ec750f15b9358..9e5939a5e1e90f15a696b01af243144d1470085a 100644 |
--- a/src/pathops/SkOpSpan.h |
+++ b/src/pathops/SkOpSpan.h |
@@ -7,36 +7,460 @@ |
#ifndef SkOpSpan_DEFINED |
#define SkOpSpan_DEFINED |
+#include "SkPathOpsDebug.h" |
#include "SkPoint.h" |
-class SkOpAngle; |
+class SkChunkAlloc; |
+struct SkOpAngle; |
+class SkOpContour; |
+class SkOpGlobalState; |
class SkOpSegment; |
+class SkOpSpanBase; |
+class SkOpSpan; |
-struct SkOpSpan { |
- SkPoint fPt; // computed when the curves are intersected |
- double fT; |
- double fOtherT; // value at fOther[fOtherIndex].fT |
- SkOpSegment* fOther; |
- SkOpAngle* fFromAngle; // (if t > 0) index into segment's angle array going negative in t |
- SkOpAngle* fToAngle; // (if t < 1) index into segment's angle array going positive in t |
- int fOtherIndex; // can't be used during intersection |
+// subset of op span used by terminal span (when t is equal to one) |
+class SkOpPtT { |
+public: |
+ enum { |
+ kIsAlias = 1, |
+ kIsDuplicate = 1 |
+ }; |
+ |
+ void addOpp(SkOpPtT* opp) { |
+ // find the fOpp ptr to opp |
+ SkOpPtT* oppPrev = opp->fNext; |
+ if (oppPrev == this) { |
+ return; |
+ } |
+ while (oppPrev->fNext != opp) { |
+ oppPrev = oppPrev->fNext; |
+ if (oppPrev == this) { |
+ return; |
+ } |
+ } |
+ |
+ SkOpPtT* oldNext = this->fNext; |
+ SkASSERT(this != opp); |
+ this->fNext = opp; |
+ SkASSERT(oppPrev != oldNext); |
+ oppPrev->fNext = oldNext; |
+ } |
+ |
+ bool alias() const; |
+ SkOpContour* contour() const; |
+ |
+ int debugID() const { |
+ return PATH_OPS_DEBUG_RELEASE(fID, -1); |
+ } |
+ |
+ const SkOpAngle* debugAngle(int id) const; |
+ SkOpContour* debugContour(int id); |
+ int debugLoopLimit(bool report) const; |
+ bool debugMatchID(int id) const; |
+ const SkOpPtT* debugPtT(int id) const; |
+ const SkOpSegment* debugSegment(int id) const; |
+ const SkOpSpanBase* debugSpan(int id) const; |
+ SkOpGlobalState* globalState() const; |
+ void debugValidate() const; |
+ |
+ bool deleted() const { |
+ return fDeleted; |
+ } |
+ |
+ bool duplicate() const { |
+ return fDuplicatePt; |
+ } |
+ |
+ void dump() const; // available to testing only |
+ void dumpAll() const; |
+ void dumpBase() const; |
+ |
+ void init(SkOpSpanBase* , double t, const SkPoint& , bool dup); |
+ |
+ void insert(SkOpPtT* span) { |
+ SkASSERT(span != this); |
+ span->fNext = fNext; |
+ fNext = span; |
+ } |
+ |
+ const SkOpPtT* next() const { |
+ return fNext; |
+ } |
+ |
+ SkOpPtT* next() { |
+ return fNext; |
+ } |
+ |
+ bool onEnd() const; |
+ SkOpPtT* prev(); |
+ SkOpPtT* remove(); |
+ void removeNext(SkOpPtT* kept); |
+ |
+ const SkOpSegment* segment() const; |
+ SkOpSegment* segment(); |
+ |
+ void setDeleted() { |
+ SkASSERT(!fDeleted); |
+ fDeleted = true; |
+ } |
+ |
+ const SkOpSpanBase* span() const { |
+ return fSpan; |
+ } |
+ |
+ SkOpSpanBase* span() { |
+ return fSpan; |
+ } |
+ |
+ double fT; |
+ SkPoint fPt; // cache of point value at this t |
+protected: |
+ SkOpSpanBase* fSpan; // contains winding data |
+ SkOpPtT* fNext; // intersection on opposite curve or alias on this curve |
+ bool fDeleted; // set if removed from span list |
+ bool fDuplicatePt; // set if identical pt is somewhere in the next loop |
+ PATH_OPS_DEBUG_CODE(int fID); |
+}; |
+ |
+class SkOpSpanBase { |
+public: |
+ void addSimpleAngle(bool checkFrom , SkChunkAlloc* ); |
+ void align(); |
+ |
+ bool aligned() const { |
+ return fAligned; |
+ } |
+ |
+ void alignEnd(double t, const SkPoint& pt); |
+ |
+ bool chased() const { |
+ return fChased; |
+ } |
+ |
+ void clearCoinEnd() { |
+ SkASSERT(fCoinEnd != this); |
+ fCoinEnd = this; |
+ } |
+ |
+ const SkOpSpanBase* coinEnd() const { |
+ return fCoinEnd; |
+ } |
+ |
+ bool contains(const SkOpSpanBase* ) const; |
+ SkOpPtT* contains(const SkOpSegment* ); |
+ |
+ bool containsCoinEnd(const SkOpSpanBase* coin) const { |
+ SkASSERT(this != coin); |
+ const SkOpSpanBase* next = this; |
+ while ((next = next->fCoinEnd) != this) { |
+ if (next == coin) { |
+ return true; |
+ } |
+ } |
+ return false; |
+ } |
+ |
+ bool containsCoinEnd(const SkOpSegment* ) const; |
+ SkOpContour* contour() const; |
+ |
+ int debugBumpCount() { |
+ return PATH_OPS_DEBUG_RELEASE(++fCount, -1); |
+ } |
+ |
+ int debugID() const { |
+ return PATH_OPS_DEBUG_RELEASE(fID, -1); |
+ } |
+ |
+ const SkOpAngle* debugAngle(int id) const; |
+ bool debugCoinEndLoopCheck() const; |
+ SkOpContour* debugContour(int id); |
+ const SkOpPtT* debugPtT(int id) const; |
+ const SkOpSegment* debugSegment(int id) const; |
+ const SkOpSpanBase* debugSpan(int id) const; |
+ SkOpGlobalState* globalState() const; |
+ void debugValidate() const; |
+ |
+ bool deleted() const { |
+ return fPtT.deleted(); |
+ } |
+ |
+ void dump() const; // available to testing only |
+ void dumpCoin() const; |
+ void dumpAll() const; |
+ void dumpBase() const; |
+ |
+ bool final() const { |
+ return fPtT.fT == 1; |
+ } |
+ |
+ SkOpAngle* fromAngle() const { |
+ return fFromAngle; |
+ } |
+ |
+ void initBase(SkOpSegment* parent, SkOpSpan* prev, double t, const SkPoint& pt); |
+ |
+ void insertCoinEnd(SkOpSpanBase* coin) { |
+ if (containsCoinEnd(coin)) { |
+ SkASSERT(coin->containsCoinEnd(this)); |
+ return; |
+ } |
+ debugValidate(); |
+ SkASSERT(this != coin); |
+ SkOpSpanBase* coinNext = coin->fCoinEnd; |
+ coin->fCoinEnd = this->fCoinEnd; |
+ this->fCoinEnd = coinNext; |
+ debugValidate(); |
+ } |
+ |
+ void merge(SkOpSpan* span); |
+ |
+ SkOpSpan* prev() const { |
+ return fPrev; |
+ } |
+ |
+ const SkPoint& pt() const { |
+ return fPtT.fPt; |
+ } |
+ |
+ const SkOpPtT* ptT() const { |
+ return &fPtT; |
+ } |
+ |
+ SkOpPtT* ptT() { |
+ return &fPtT; |
+ } |
+ |
+ SkOpSegment* segment() const { |
+ return fSegment; |
+ } |
+ |
+ void setChased(bool chased) { |
+ fChased = chased; |
+ } |
+ |
+ SkOpPtT* setCoinEnd(SkOpSpanBase* oldCoinEnd, SkOpSegment* oppSegment); |
+ |
+ void setFromAngle(SkOpAngle* angle) { |
+ fFromAngle = angle; |
+ } |
+ |
+ void setPrev(SkOpSpan* prev) { |
+ fPrev = prev; |
+ } |
+ |
+ bool simple() const { |
+ fPtT.debugValidate(); |
+ return fPtT.next()->next() == &fPtT; |
+ } |
+ |
+ const SkOpSpan* starter(const SkOpSpanBase* end) const { |
+ const SkOpSpanBase* result = t() < end->t() ? this : end; |
+ return result->upCast(); |
+ } |
+ |
+ SkOpSpan* starter(SkOpSpanBase* end) { |
+ SkASSERT(this->segment() == end->segment()); |
+ SkOpSpanBase* result = t() < end->t() ? this : end; |
+ return result->upCast(); |
+ } |
+ |
+ SkOpSpan* starter(SkOpSpanBase** endPtr) { |
+ SkOpSpanBase* end = *endPtr; |
+ SkASSERT(this->segment() == end->segment()); |
+ SkOpSpanBase* result; |
+ if (t() < end->t()) { |
+ result = this; |
+ } else { |
+ result = end; |
+ *endPtr = this; |
+ } |
+ return result->upCast(); |
+ } |
+ |
+ int step(const SkOpSpanBase* end) const { |
+ return t() < end->t() ? 1 : -1; |
+ } |
+ |
+ double t() const { |
+ return fPtT.fT; |
+ } |
+ |
+ void unaligned() { |
+ fAligned = false; |
+ } |
+ |
+ SkOpSpan* upCast() { |
+ SkASSERT(!final()); |
+ return (SkOpSpan*) this; |
+ } |
+ |
+ const SkOpSpan* upCast() const { |
+ SkASSERT(!final()); |
+ return (const SkOpSpan*) this; |
+ } |
+ |
+ SkOpSpan* upCastable() { |
+ return final() ? NULL : upCast(); |
+ } |
+ |
+ const SkOpSpan* upCastable() const { |
+ return final() ? NULL : upCast(); |
+ } |
+ |
+private: |
+ void alignInner(); |
+ |
+protected: // no direct access to internals to avoid treating a span base as a span |
+ SkOpPtT fPtT; // list of points and t values associated with the start of this span |
+ SkOpSegment* fSegment; // segment that contains this span |
+ SkOpSpanBase* fCoinEnd; // linked list of coincident spans that end here (may point to itself) |
+ SkOpAngle* fFromAngle; // points to next angle from span start to end |
+ SkOpSpan* fPrev; // previous intersection point |
+ bool fAligned; |
+ bool fChased; // set after span has been added to chase array |
+ PATH_OPS_DEBUG_CODE(int fCount); // number of pt/t pairs added |
+ PATH_OPS_DEBUG_CODE(int fID); |
+}; |
+ |
+class SkOpSpan : public SkOpSpanBase { |
+public: |
+ void applyCoincidence(SkOpSpan* opp); |
+ |
+ bool clearCoincident() { |
+ SkASSERT(!final()); |
+ if (fCoincident == this) { |
+ return false; |
+ } |
+ fCoincident = this; |
+ return true; |
+ } |
+ |
+ bool containsCoincidence(const SkOpSegment* ) const; |
+ |
+ bool containsCoincidence(const SkOpSpan* coin) const { |
+ SkASSERT(this != coin); |
+ const SkOpSpan* next = this; |
+ while ((next = next->fCoincident) != this) { |
+ if (next == coin) { |
+ return true; |
+ } |
+ } |
+ return false; |
+ } |
+ |
+ bool debugCoinLoopCheck() const; |
+ void detach(SkOpPtT* ); |
+ |
+ bool done() const { |
+ SkASSERT(!final()); |
+ return fDone; |
+ } |
+ |
+ void dumpCoin() const; |
+ bool dumpSpan() const; |
+ void init(SkOpSegment* parent, SkOpSpan* prev, double t, const SkPoint& pt); |
+ |
+ void insertCoincidence(SkOpSpan* coin) { |
+ if (containsCoincidence(coin)) { |
+ SkASSERT(coin->containsCoincidence(this)); |
+ return; |
+ } |
+ debugValidate(); |
+ SkASSERT(this != coin); |
+ SkOpSpan* coinNext = coin->fCoincident; |
+ coin->fCoincident = this->fCoincident; |
+ this->fCoincident = coinNext; |
+ debugValidate(); |
+ } |
+ |
+ bool isCanceled() const { |
+ SkASSERT(!final()); |
+ return fWindValue == 0 && fOppValue == 0; |
+ } |
+ |
+ bool isCoincident() const { |
+ SkASSERT(!final()); |
+ return fCoincident != this; |
+ } |
+ |
+ SkOpSpanBase* next() const { |
+ SkASSERT(!final()); |
+ return fNext; |
+ } |
+ |
+ int oppSum() const { |
+ SkASSERT(!final()); |
+ return fOppSum; |
+ } |
+ |
+ int oppValue() const { |
+ SkASSERT(!final()); |
+ return fOppValue; |
+ } |
+ |
+ SkOpPtT* setCoinStart(SkOpSpan* oldCoinStart, SkOpSegment* oppSegment); |
+ |
+ void setDone(bool done) { |
+ SkASSERT(!final()); |
+ fDone = done; |
+ } |
+ |
+ void setNext(SkOpSpanBase* nextT) { |
+ SkASSERT(!final()); |
+ fNext = nextT; |
+ } |
+ |
+ void setOppSum(int oppSum); |
+ |
+ void setOppValue(int oppValue) { |
+ SkASSERT(!final()); |
+ SkASSERT(fOppSum == SK_MinS32); |
+ fOppValue = oppValue; |
+ } |
+ |
+ void setToAngle(SkOpAngle* angle) { |
+ SkASSERT(!final()); |
+ fToAngle = angle; |
+ } |
+ |
+ void setWindSum(int windSum) { |
+ SkASSERT(!final()); |
+ SkASSERT(fWindSum == SK_MinS32 || fWindSum == windSum); |
+ SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(windSum) <= DEBUG_LIMIT_WIND_SUM); |
+ fWindSum = windSum; |
+ } |
+ |
+ void setWindValue(int windValue) { |
+ SkASSERT(!final()); |
+ SkASSERT(windValue >= 0); |
+ SkASSERT(fWindSum == SK_MinS32); |
+ fWindValue = windValue; |
+ } |
+ |
+ SkOpAngle* toAngle() const { |
+ SkASSERT(!final()); |
+ return fToAngle; |
+ } |
+ |
+ int windSum() const { |
+ SkASSERT(!final()); |
+ return fWindSum; |
+ } |
+ |
+ int windValue() const { |
+ SkASSERT(!final()); |
+ return fWindValue; |
+ } |
+ |
+private: // no direct access to internals to avoid treating a span base as a span |
+ SkOpSpan* fCoincident; // linked list of spans coincident with this one (may point to itself) |
+ SkOpAngle* fToAngle; // points to next angle from span start to end |
+ SkOpSpanBase* fNext; // next intersection point |
int fWindSum; // accumulated from contours surrounding this one. |
int fOppSum; // for binary operators: the opposite winding sum |
int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident |
int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here |
- bool fChased; // set after span has been added to chase array |
- bool fCoincident; // set if span is bumped -- if set additional points aren't inserted |
bool fDone; // if set, this span to next higher T has been processed |
- bool fLoop; // set when a cubic loops back to this point |
- bool fMultiple; // set if this is one of mutiple spans with identical t and pt values |
- bool fNear; // set if opposite end point is near but not equal to this one |
- bool fSmall; // if set, consecutive points are almost equal |
- bool fTiny; // if set, consecutive points are equal but consecutive ts are not precisely equal |
- |
- // available to testing only |
- const SkOpSegment* debugToSegment(ptrdiff_t* ) const; |
- void dump() const; |
- void dumpOne() const; |
}; |
#endif |