| Index: src/pathops/SkPathOpsCommon.cpp
|
| diff --git a/src/pathops/SkPathOpsCommon.cpp b/src/pathops/SkPathOpsCommon.cpp
|
| index f7b7273a8d0cf3676a44c414b575e3877c22e66d..1a5bfc18896d11375766b5971aff9065483f26d5 100644
|
| --- a/src/pathops/SkPathOpsCommon.cpp
|
| +++ b/src/pathops/SkPathOpsCommon.cpp
|
| @@ -161,7 +161,7 @@ SkOpSegment* FindChase(SkTDArray<SkOpSpan*>* chase, int* tIndex, int* endIndex)
|
| if (!sortable) {
|
| continue;
|
| }
|
| - // find first angle, initialize winding to computed fWindSum
|
| + // find first angle, initialize winding to computed wind sum
|
| const SkOpAngle* angle = segment->spanToAngle(*tIndex, *endIndex);
|
| const SkOpAngle* firstAngle;
|
| SkDEBUGCODE(firstAngle = angle);
|
| @@ -208,7 +208,8 @@ SkOpSegment* FindChase(SkTDArray<SkOpSpan*>* chase, int* tIndex, int* endIndex)
|
| if (SkOpSegment::UseInnerWinding(maxWinding, winding)) {
|
| maxWinding = winding;
|
| }
|
| - (void) segment->markAndChaseWinding(angle, maxWinding, 0);
|
| + // allowed to do nothing
|
| + (void) segment->markAndChaseWinding(angle, maxWinding, 0, NULL);
|
| break;
|
| }
|
| }
|
| @@ -315,6 +316,12 @@ static void skipVertical(const SkTArray<SkOpContour*, true>& contourList,
|
| return;
|
| }
|
|
|
| +struct SortableTop { // error if local in pre-C++11
|
| + SkOpSegment* fSegment;
|
| + int fIndex;
|
| + int fEndIndex;
|
| +};
|
| +
|
| SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList,
|
| SkOpAngle::IncludeType angleIncludeType, bool* firstContour, int* indexPtr,
|
| int* endIndexPtr, SkPoint* topLeft, bool* unsortable, bool* done, bool* onlyVertical,
|
| @@ -356,6 +363,8 @@ SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList,
|
| double tHit;
|
| SkScalar hitDx = 0;
|
| SkScalar hitOppDx = 0;
|
| + // keep track of subsequent returns to detect infinite loops
|
| + SkTDArray<SortableTop> sortableTops;
|
| do {
|
| // if current is vertical, find another candidate which is not
|
| // if only remaining candidates are vertical, then they can be marked done
|
| @@ -366,6 +375,35 @@ SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList,
|
| tryAgain = false;
|
| contourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endIndexPtr, &tHit,
|
| &hitDx, &tryAgain, onlyVertical, false);
|
| + if (tryAgain) {
|
| + bool giveUp = false;
|
| + int count = sortableTops.count();
|
| + for (int index = 0; index < count; ++index) {
|
| + const SortableTop& prev = sortableTops[index];
|
| + if (giveUp) {
|
| + prev.fSegment->markDoneFinal(prev.fIndex);
|
| + } else if (prev.fSegment == current
|
| + && (prev.fIndex == *indexPtr || prev.fEndIndex == *endIndexPtr)) {
|
| + // remaining edges are non-vertical and cannot have their winding computed
|
| + // mark them as done and return, and hope that assembly can fill the holes
|
| + giveUp = true;
|
| + index = -1;
|
| + }
|
| + }
|
| + if (giveUp) {
|
| + *done = true;
|
| + return NULL;
|
| + }
|
| + }
|
| + SortableTop* sortableTop = sortableTops.append();
|
| + sortableTop->fSegment = current;
|
| + sortableTop->fIndex = *indexPtr;
|
| + sortableTop->fEndIndex = *endIndexPtr;
|
| +#if DEBUG_SORT
|
| + SkDebugf("%s current=%d index=%d endIndex=%d tHit=%1.9g hitDx=%1.9g try=%d vert=%d\n",
|
| + __FUNCTION__, current->debugID(), *indexPtr, *endIndexPtr, tHit, hitDx, tryAgain,
|
| + *onlyVertical);
|
| +#endif
|
| if (*onlyVertical) {
|
| return current;
|
| }
|
| @@ -378,10 +416,16 @@ SkOpSegment* FindSortableTop(const SkTArray<SkOpContour*, true>& contourList,
|
| oppContourWinding = rightAngleWinding(contourList, ¤t, indexPtr, endIndexPtr, &tHit,
|
| &hitOppDx, &tryAgain, NULL, true);
|
| } while (tryAgain);
|
| - current->initWinding(*indexPtr, *endIndexPtr, tHit, contourWinding, hitDx, oppContourWinding,
|
| - hitOppDx);
|
| + bool success = current->initWinding(*indexPtr, *endIndexPtr, tHit, contourWinding, hitDx,
|
| + oppContourWinding, hitOppDx);
|
| if (current->done()) {
|
| return NULL;
|
| + } else if (!success) { // check if the span has a valid winding
|
| + int min = SkTMin(*indexPtr, *endIndexPtr);
|
| + const SkOpSpan& span = current->span(min);
|
| + if (span.fWindSum == SK_MinS32) {
|
| + return NULL;
|
| + }
|
| }
|
| return current;
|
| }
|
| @@ -405,14 +449,17 @@ static void checkDuplicates(SkTArray<SkOpContour*, true>* contourList) {
|
| }
|
| }
|
|
|
| -static void checkEnds(SkTArray<SkOpContour*, true>* contourList) {
|
| +static bool checkEnds(SkTArray<SkOpContour*, true>* contourList) {
|
| // it's hard to determine if the end of a cubic or conic nearly intersects another curve.
|
| // instead, look to see if the connecting curve intersected at that same end.
|
| int contourCount = (*contourList).count();
|
| for (int cTest = 0; cTest < contourCount; ++cTest) {
|
| SkOpContour* contour = (*contourList)[cTest];
|
| - contour->checkEnds();
|
| + if (!contour->checkEnds()) {
|
| + return false;
|
| + }
|
| }
|
| + return true;
|
| }
|
|
|
| static bool checkMultiples(SkTArray<SkOpContour*, true>* contourList) {
|
| @@ -706,7 +753,9 @@ bool HandleCoincidence(SkTArray<SkOpContour*, true>* contourList, int total) {
|
| SkOpContour::debugShowWindingValues(contourList);
|
| #endif
|
| fixOtherTIndex(contourList);
|
| - checkEnds(contourList); // check if connecting curve intersected at the same end
|
| + if (!checkEnds(contourList)) { // check if connecting curve intersected at the same end
|
| + return false;
|
| + }
|
| bool hasM = checkMultiples(contourList); // check if intersections agree on t and point values
|
| SkTDArray<SkOpSegment::AlignedSpan> aligned;
|
| if (hasM) {
|
|
|