Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(610)

Unified Diff: src/pathops/SkPathOpsCommon.cpp

Issue 633393002: harden pathops for pathological test (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: exclude new test that asserts in debug Created 6 years, 1 month ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/pathops/SkOpSegment.cpp ('k') | src/pathops/SkPathOpsDebug.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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, &current, 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, &current, 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) {
« no previous file with comments | « src/pathops/SkOpSegment.cpp ('k') | src/pathops/SkPathOpsDebug.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698