Index: src/pathops/SkOpSegment.h |
diff --git a/src/pathops/SkOpSegment.h b/src/pathops/SkOpSegment.h |
index 79d83b1155fbd8728d3d0e986f78c270e97b74a8..54c1892d1bd881064d1c2332d55777eeba73e2bb 100644 |
--- a/src/pathops/SkOpSegment.h |
+++ b/src/pathops/SkOpSegment.h |
@@ -19,7 +19,7 @@ class SkPathWriter; |
class SkOpSegment { |
public: |
SkOpSegment() { |
-#ifdef SK_DEBUG |
+#if defined(SK_DEBUG) || !FORCE_RELEASE |
fID = ++SkPathOpsDebug::gSegmentID; |
#endif |
} |
@@ -28,6 +28,12 @@ public: |
return fBounds.fTop < rh.fBounds.fTop; |
} |
+ // FIXME: add some template or macro to avoid casting |
+ SkOpAngle& angle(int index) { |
+ const SkOpAngle& cAngle = (const_cast<const SkOpSegment*>(this))->angle(index); |
+ return const_cast<SkOpAngle&>(cAngle); |
+ } |
+ |
const SkPathOpsBounds& bounds() const { |
return fBounds; |
} |
@@ -42,6 +48,8 @@ public: |
return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1; |
} |
+ void constructLine(SkPoint shortLine[2]); |
+ |
int count() const { |
return fTs.count(); |
} |
@@ -59,7 +67,6 @@ public: |
return done(SkMin32(angle->start(), angle->end())); |
} |
- // used only by partial coincidence detection |
SkDPoint dPtAtT(double mid) const { |
return (*CurveDPointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid); |
} |
@@ -72,6 +79,14 @@ public: |
return dxdy(index).fY; |
} |
+ bool hasSmall() const { |
+ return fSmall; |
+ } |
+ |
+ bool hasTiny() const { |
+ return fTiny; |
+ } |
+ |
bool intersected() const { |
return fTs.count() > 0; |
} |
@@ -131,11 +146,12 @@ public: |
return fTs[lesser].fOppValue; |
} |
- const SkOpSegment* other(int index) const { |
- return fTs[index].fOther; |
+#if DEBUG_VALIDATE |
+ bool oppXor() const { |
+ return fOppXor; |
} |
+#endif |
- // was used only by right angle winding finding |
SkPoint ptAtT(double mid) const { |
return (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, mid); |
} |
@@ -160,11 +176,23 @@ public: |
*sumWinding -= deltaSum; |
} |
- // OPTIMIZATION: mark as debugging only if used solely by tests |
const SkOpSpan& span(int tIndex) const { |
return fTs[tIndex]; |
} |
+ const SkOpAngle* spanToAngle(int tStart, int tEnd) const { |
+ SkASSERT(tStart != tEnd); |
+ const SkOpSpan& span = fTs[tStart]; |
+ int index = tStart < tEnd ? span.fToAngleIndex : span.fFromAngleIndex; |
+ return index >= 0 ? &angle(index) : NULL; |
+ } |
+ |
+ // FIXME: create some sort of macro or template that avoids casting |
+ SkOpAngle* spanToAngle(int tStart, int tEnd) { |
+ const SkOpAngle* cAngle = (const_cast<const SkOpSegment*>(this))->spanToAngle(tStart, tEnd); |
+ return const_cast<SkOpAngle*>(cAngle); |
+ } |
+ |
// OPTIMIZATION: mark as debugging only if used solely by tests |
const SkTDArray<SkOpSpan>& spans() const { |
return fTs; |
@@ -217,6 +245,12 @@ public: |
} |
#endif |
+#if DEBUG_VALIDATE |
+ bool _xor() const { // FIXME: used only by SkOpAngle::debugValidateLoop() |
+ return fXor; |
+ } |
+#endif |
+ |
const SkPoint& xyAtT(const SkOpSpan* span) const { |
return span->fPt; |
} |
@@ -231,44 +265,56 @@ public: |
} |
#endif |
- bool activeAngle(int index, int* done, SkTArray<SkOpAngle, true>* angles); |
+ const SkOpAngle* activeAngle(int index, int* start, int* end, bool* done, |
+ bool* sortable) const; |
SkPoint activeLeftTop(bool onlySortable, int* firstT) const; |
bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op); |
bool activeWinding(int index, int endIndex); |
void addCubic(const SkPoint pts[4], bool operand, bool evenOdd); |
void addCurveTo(int start, int end, SkPathWriter* path, bool active) const; |
+ void addEndSpan(int endIndex); |
void addLine(const SkPoint pts[2], bool operand, bool evenOdd); |
void addOtherT(int index, double otherT, int otherIndex); |
void addQuad(const SkPoint pts[3], bool operand, bool evenOdd); |
- int addSelfT(SkOpSegment* other, const SkPoint& pt, double newT); |
+ void addSimpleAngle(int endIndex); |
+ int addSelfT(const SkPoint& pt, double newT); |
+ void addStartSpan(int endIndex); |
int addT(SkOpSegment* other, const SkPoint& pt, double newT); |
void addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other); |
void addTCoincident(const SkPoint& startPt, const SkPoint& endPt, double endT, |
- SkOpSegment* other); |
- void addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind, const SkPoint& pt); |
+ SkOpSegment* other); |
+ const SkOpSpan* addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind, |
+ const SkPoint& pt); |
+ bool alignSpan(int index, double thisT, const SkPoint& thisPt); |
+ void alignSpanState(int start, int end); |
+ const SkOpAngle& angle(int index) const; |
bool betweenTs(int lesser, double testT, int greater) const; |
+ bool calcAngles(); |
+ void checkDuplicates(); |
void checkEnds(); |
+ void checkMultiples(); |
+ void checkSmall(); |
bool checkSmall(int index) const; |
void checkTiny(); |
- int computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType, |
- SkTArray<SkOpAngle, true>* angles, SkTArray<SkOpAngle*, true>* sorted); |
+ int computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType); |
int crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT, bool* hitSomething, |
double mid, bool opp, bool current) const; |
bool findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* other, int oStart, int oEnd, |
int step, SkPoint* startPt, SkPoint* endPt, double* endT) const; |
SkOpSegment* findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd, |
- bool* unsortable, SkPathOp op, const int xorMiMask, |
- const int xorSuMask); |
+ bool* unsortable, SkPathOp op, int xorMiMask, int xorSuMask); |
SkOpSegment* findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd, |
bool* unsortable); |
SkOpSegment* findNextXor(int* nextStart, int* nextEnd, bool* unsortable); |
+ int findExactT(double t, const SkOpSegment* ) const; |
int findT(double t, const SkOpSegment* ) const; |
- SkOpSegment* findTop(int* tIndex, int* endIndex, bool* unsortable, bool onlySortable); |
+ SkOpSegment* findTop(int* tIndex, int* endIndex, bool* unsortable); |
void fixOtherTIndex(); |
- void initWinding(int start, int end); |
+ void initWinding(int start, int end, SkOpAngle::IncludeType angleIncludeType); |
void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind, |
SkScalar hitOppDx); |
bool isMissing(double startT, const SkPoint& pt) const; |
+ bool isSmall(const SkOpAngle* angle) const; |
bool isTiny(const SkOpAngle* angle) const; |
bool joinCoincidence(SkOpSegment* other, double otherT, int step, bool cancel); |
SkOpSpan* markAndChaseDoneBinary(int index, int endIndex); |
@@ -283,44 +329,44 @@ public: |
int nextSpan(int from, int step) const; |
void setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding, |
int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding); |
- enum SortAngleKind { |
- kMustBeOrdered_SortAngleKind, // required for winding calc |
- kMayBeUnordered_SortAngleKind // ok for find top |
- }; |
- static bool SortAngles(const SkTArray<SkOpAngle, true>& angles, // FIXME: replace with |
- SkTArray<SkOpAngle*, true>* angleList, // Sort Angles 2 |
- SortAngleKind ); |
- static bool SortAngles2(const SkTArray<SkOpAngle, true>& angles, |
- SkTArray<SkOpAngle*, true>* angleList); |
+ void sortAngles(); |
bool subDivide(int start, int end, SkPoint edge[4]) const; |
bool subDivide(int start, int end, SkDCubic* result) const; |
void undoneSpan(int* start, int* end); |
int updateOppWindingReverse(const SkOpAngle* angle) const; |
int updateWindingReverse(const SkOpAngle* angle) const; |
static bool UseInnerWinding(int outerWinding, int innerWinding); |
+ static bool UseInnerWindingReverse(int outerWinding, int innerWinding); |
int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const; |
int windSum(const SkOpAngle* angle) const; |
- |
-#ifdef SK_DEBUG |
+// available for testing only |
+#if DEBUG_VALIDATE |
+ bool debugContains(const SkOpAngle* ) const; |
+#endif |
+#if defined(SK_DEBUG) || !FORCE_RELEASE |
int debugID() const { |
return fID; |
} |
+#else |
+ int debugID() const { |
+ return -1; |
+ } |
#endif |
#if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY |
void debugShowActiveSpans() const; |
#endif |
-#if DEBUG_SORT || DEBUG_SWAP_TOP |
- void debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles, int first, |
- const int contourWinding, const int oppContourWinding, bool sortable) const; |
- void debugShowSort(const char* fun, const SkTArray<SkOpAngle*, true>& angles, int first, |
- bool sortable); |
-#endif |
#if DEBUG_CONCIDENT |
void debugShowTs(const char* prefix) const; |
#endif |
#if DEBUG_SHOW_WINDING |
int debugShowWindingValues(int slotCount, int ofInterest) const; |
#endif |
+ void debugValidate() const; |
+ // available to testing only |
+ void dumpAngles() const; |
+ void dumpContour(int firstID, int lastID) const; |
+ void dumpPts() const; |
+ void dumpSpans() const; |
private: |
struct MissingSpan { |
@@ -332,40 +378,55 @@ private: |
SkPoint fPt; |
}; |
- bool activeAngleOther(int index, int* done, SkTArray<SkOpAngle, true>* angles); |
- bool activeAngleInner(int index, int* done, SkTArray<SkOpAngle, true>* angles); |
+ const SkOpAngle* activeAngleInner(int index, int* start, int* end, bool* done, |
+ bool* sortable) const; |
+ const SkOpAngle* activeAngleOther(int index, int* start, int* end, bool* done, |
+ bool* sortable) const; |
bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op, |
- int* sumMiWinding, int* sumSuWinding, int* maxWinding, int* sumWinding, |
- int* oppMaxWinding, int* oppSumWinding); |
- bool activeWinding(int index, int endIndex, int* maxWinding, int* sumWinding); |
- void addAngle(SkTArray<SkOpAngle, true>* angles, int start, int end) const; |
+ int* sumMiWinding, int* sumSuWinding); |
+ bool activeWinding(int index, int endIndex, int* sumWinding); |
void addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other); |
void addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other); |
+ int addSingletonAngleDown(int start, SkOpSegment** otherPtr); |
+ int addSingletonAngleUp(int start, SkOpSegment** otherPtr); |
+ SkOpAngle* addSingletonAngles(int start, int step); |
void addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind, const SkPoint& pt, |
const SkPoint& oPt); |
- void addTwoAngles(int start, int end, SkTArray<SkOpAngle, true>* angles) const; |
bool betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const; |
- bool buildAngles(int index, SkTArray<SkOpAngle, true>* angles, bool includeOpp) const; |
- void buildAnglesInner(int index, SkTArray<SkOpAngle, true>* angles) const; |
void bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* index, |
SkTArray<SkPoint, true>* outsideTs); |
void bumpCoincidentOther(const SkOpSpan& oTest, int* index, |
SkTArray<SkPoint, true>* outsideTs); |
bool bumpSpan(SkOpSpan* span, int windDelta, int oppDelta); |
+ bool calcLoopSpanCount(const SkOpSpan& thisSpan, int* smallCounts); |
+ void checkLinks(const SkOpSpan* , |
+ SkTArray<MissingSpan, true>* missingSpans) const; |
+ static void CheckOneLink(const SkOpSpan* test, const SkOpSpan* oSpan, |
+ const SkOpSpan* oFirst, const SkOpSpan* oLast, |
+ const SkOpSpan** missingPtr, |
+ SkTArray<MissingSpan, true>* missingSpans); |
+ int checkSetAngle(int tIndex) const; |
+ void checkSmallCoincidence(const SkOpSpan& span, SkTArray<MissingSpan, true>* ); |
bool clockwise(int tStart, int tEnd) const; |
static void ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, |
SkOpAngle::IncludeType ); |
static void ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, |
SkOpAngle::IncludeType ); |
bool decrementSpan(SkOpSpan* span); |
- int findStartingEdge(const SkTArray<SkOpAngle*, true>& sorted, int start, int end); |
+ int findEndSpan(int endIndex) const; |
+ int findStartSpan(int startIndex) const; |
+ int firstActive(int tIndex) const; |
+ const SkOpSpan& firstSpan(const SkOpSpan& thisSpan) const; |
void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd); |
+ bool inLoop(const SkOpAngle* baseAngle, int spanCount, int* indexPtr) const; |
bool isSimple(int end) const; |
bool isTiny(int index) const; |
+ const SkOpSpan& lastSpan(const SkOpSpan& thisSpan) const; |
void matchWindingValue(int tIndex, double t, bool borrowWind); |
SkOpSpan* markAndChaseDone(int index, int endIndex, int winding); |
SkOpSpan* markAndChaseDoneBinary(const SkOpAngle* angle, int winding, int oppWinding); |
- SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, const int winding); |
+ SkOpSpan* markAndChaseWinding(const SkOpAngle* angle, int winding); |
+ SkOpSpan* markAndChaseWinding(int index, int endIndex, int winding); |
SkOpSpan* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding); |
SkOpSpan* markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle); |
void markDoneBinary(int index, int winding, int oppWinding); |
@@ -380,10 +441,21 @@ private: |
void markWinding(int index, int winding, int oppWinding); |
void markUnsortable(int start, int end); |
bool monotonicInY(int tStart, int tEnd) const; |
+ |
+ bool multipleEnds() const { |
+ return fTs[count() - 2].fT == 1; |
+ } |
+ |
+ bool multipleStarts() const { |
+ return fTs[1].fT == 0; |
+ } |
+ |
bool multipleSpans(int end) const; |
SkOpSegment* nextChase(int* index, const int step, int* min, SkOpSpan** last); |
int nextExactSpan(int from, int step) const; |
bool serpentine(int tStart, int tEnd) const; |
+ void setFromAngleIndex(int endIndex, int angleIndex); |
+ void setToAngleIndex(int endIndex, int angleIndex); |
void setUpWindings(int index, int endIndex, int* sumMiWinding, |
int* maxWinding, int* sumWinding); |
void subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const; |
@@ -395,7 +467,6 @@ private: |
int updateWinding(int index, int endIndex) const; |
int updateWinding(const SkOpAngle* angle) const; |
int updateWindingReverse(int index, int endIndex) const; |
- static bool UseInnerWindingReverse(int outerWinding, int innerWinding); |
SkOpSpan* verifyOneWinding(const char* funName, int tIndex); |
SkOpSpan* verifyOneWindingU(const char* funName, int tIndex); |
@@ -412,8 +483,12 @@ private: |
#if DEBUG_SWAP_TOP |
bool controlsContainedByEnds(int tStart, int tEnd) const; |
#endif |
+ void debugAddAngle(int start, int end); |
#if DEBUG_CONCIDENT |
- void debugAddTPair(double t, const SkOpSegment& other, double otherT) const; |
+ void debugAddTPair(double t, const SkOpSegment& other, double otherT) const; |
+#endif |
+#if DEBUG_ANGLE |
+ void debugCheckPointsEqualish(int tStart, int tEnd) const; |
#endif |
#if DEBUG_MARK_DONE || DEBUG_UNSORTABLE |
void debugShowNewWinding(const char* fun, const SkOpSpan& span, int winding); |
@@ -424,27 +499,37 @@ private: |
return value < 0 ? '?' : value <= 9 ? '0' + value : '+'; |
} |
#endif |
- void debugValidate() const; |
-#ifdef SK_DEBUG |
- void dumpPts() const; |
+ // available to testing only |
+ void debugConstruct(); |
+ void debugConstructCubic(SkPoint shortQuad[4]); |
+ void debugConstructLine(SkPoint shortQuad[2]); |
+ void debugConstructQuad(SkPoint shortQuad[3]); |
+ void debugReset(); |
void dumpDPts() const; |
- void dumpSpans() const; |
-#endif |
+ void dumpSpan(int index) const; |
const SkPoint* fPts; |
SkPathOpsBounds fBounds; |
// FIXME: can't convert to SkTArray because it uses insert |
- SkTDArray<SkOpSpan> fTs; // two or more (always includes t=0 t=1) |
+ SkTDArray<SkOpSpan> fTs; // 2+ (always includes t=0 t=1) -- at least (number of spans) + 1 |
+// FIXME: replace both with bucket storage that allows direct immovable pointers to angles |
+ SkTArray<SkOpAngle, true> fSingletonAngles; // 0 or 2 -- allocated for singletons |
+ SkTArray<SkOpAngle, true> fAngles; // 0 or 2+ -- (number of non-zero spans) * 2 |
// OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value |
int fDoneSpans; // quick check that segment is finished |
// OPTIMIZATION: force the following to be byte-sized |
SkPath::Verb fVerb; |
+ bool fLoop; // set if cubic intersects itself |
bool fOperand; |
bool fXor; // set if original contour had even-odd fill |
bool fOppXor; // set if opposite operand had even-odd fill |
-#ifdef SK_DEBUG |
+ bool fSmall; // set if some span is small |
+ bool fTiny; // set if some span is tiny |
+#if defined(SK_DEBUG) || !FORCE_RELEASE |
int fID; |
#endif |
+ |
+ friend class PathOpsSegmentTester; |
}; |
#endif |