handle failing pathop tests

Some tests isolated from GrShapes_arcs do not
fail gracefully, so make sure errors are properly
handled.

TBR=reed@google.com

Bug: skia:
Change-Id: Ia8c9903e64ef755ec11c398df3e5d258ca1f5f8b
Reviewed-on: https://skia-review.googlesource.com/143112
Reviewed-by: Cary Clark <caryclark@skia.org>
Commit-Queue: Cary Clark <caryclark@skia.org>
Auto-Submit: Cary Clark <caryclark@skia.org>
This commit is contained in:
Cary Clark 2018-07-24 12:40:10 -04:00 committed by Skia Commit-Bot
parent 6a4e60bb8f
commit 2587f41f26
8 changed files with 4796 additions and 39 deletions

View File

@ -338,7 +338,7 @@ SkOpSpanBase::Collapsed SkOpSegment::collapsed(double s, double e) const {
return SkOpSpanBase::Collapsed::kNo; return SkOpSpanBase::Collapsed::kNo;
} }
void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, bool SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
SkOpAngle::IncludeType includeType) { SkOpAngle::IncludeType includeType) {
SkOpSegment* baseSegment = baseAngle->segment(); SkOpSegment* baseSegment = baseAngle->segment();
int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); int sumMiWinding = baseSegment->updateWindingReverse(baseAngle);
@ -358,17 +358,22 @@ void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle
int oppMaxWinding, oppSumWinding; int oppMaxWinding, oppSumWinding;
nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding, nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
&sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding, if (!nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
nextAngle); nextAngle, &last)) {
return false;
}
} else { } else {
nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding, nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding,
&maxWinding, &sumWinding); &maxWinding, &sumWinding);
last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle); if (!nextSegment->markAngle(maxWinding, sumWinding, nextAngle, &last)) {
return false;
}
} }
nextAngle->setLastMarked(last); nextAngle->setLastMarked(last);
return true;
} }
void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle, bool SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
SkOpAngle::IncludeType includeType) { SkOpAngle::IncludeType includeType) {
SkOpSegment* baseSegment = baseAngle->segment(); SkOpSegment* baseSegment = baseAngle->segment();
int sumMiWinding = baseSegment->updateWinding(baseAngle); int sumMiWinding = baseSegment->updateWinding(baseAngle);
@ -388,14 +393,19 @@ void SkOpSegment::ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngl
int oppMaxWinding, oppSumWinding; int oppMaxWinding, oppSumWinding;
nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding, nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
&sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding);
last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding, if (!nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding,
nextAngle); nextAngle, &last)) {
return false;
}
} else { } else {
nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding, nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding,
&maxWinding, &sumWinding); &maxWinding, &sumWinding);
last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle); if (!nextSegment->markAngle(maxWinding, sumWinding, nextAngle, &last)) {
return false;
}
} }
nextAngle->setLastMarked(last); nextAngle->setLastMarked(last);
return true;
} }
// at this point, the span is already ordered, or unorderable // at this point, the span is already ordered, or unorderable
@ -910,10 +920,10 @@ bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
if (this->operand() == other->operand()) { if (this->operand() == other->operand()) {
if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) { if (spanStart->windSum() != winding || spanStart->oppSum() != oppWinding) {
this->globalState()->setWindingFailed(); this->globalState()->setWindingFailed();
return false; return true; // ... but let it succeed anyway
} }
} else { } else {
SkASSERT(spanStart->windSum() == oppWinding); FAIL_IF(spanStart->windSum() != oppWinding);
SkASSERT(spanStart->oppSum() == winding); SkASSERT(spanStart->oppSum() == winding);
} }
SkASSERT(!last); SkASSERT(!last);
@ -931,13 +941,15 @@ bool SkOpSegment::markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end,
return success; return success;
} }
SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) { bool SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle,
SkOpSpanBase** result) {
SkASSERT(angle->segment() == this); SkASSERT(angle->segment() == this);
if (UseInnerWinding(maxWinding, sumWinding)) { if (UseInnerWinding(maxWinding, sumWinding)) {
maxWinding = sumWinding; maxWinding = sumWinding;
} }
SkOpSpanBase* last; if (!markAndChaseWinding(angle->start(), angle->end(), maxWinding, result)) {
(void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, &last); return false;
}
#if DEBUG_WINDING #if DEBUG_WINDING
if (last) { if (last) {
SkDebugf("%s last seg=%d span=%d", __FUNCTION__, SkDebugf("%s last seg=%d span=%d", __FUNCTION__,
@ -949,11 +961,11 @@ SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpA
SkDebugf("\n"); SkDebugf("\n");
} }
#endif #endif
return last; return true;
} }
SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding, bool SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding,
int oppSumWinding, const SkOpAngle* angle) { int oppSumWinding, const SkOpAngle* angle, SkOpSpanBase** result) {
SkASSERT(angle->segment() == this); SkASSERT(angle->segment() == this);
if (UseInnerWinding(maxWinding, sumWinding)) { if (UseInnerWinding(maxWinding, sumWinding)) {
maxWinding = sumWinding; maxWinding = sumWinding;
@ -961,9 +973,10 @@ SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxW
if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) { if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) {
oppMaxWinding = oppSumWinding; oppMaxWinding = oppSumWinding;
} }
SkOpSpanBase* last = nullptr;
// caller doesn't require that this marks anything // caller doesn't require that this marks anything
(void) markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, &last); if (!markAndChaseWinding(angle->start(), angle->end(), maxWinding, oppMaxWinding, result)) {
return false;
}
#if DEBUG_WINDING #if DEBUG_WINDING
if (last) { if (last) {
SkDebugf("%s last segment=%d span=%d", __FUNCTION__, SkDebugf("%s last segment=%d span=%d", __FUNCTION__,
@ -975,7 +988,7 @@ SkOpSpanBase* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxW
SkDebugf(" \n"); SkDebugf(" \n");
} }
#endif #endif
return last; return true;
} }
void SkOpSegment::markDone(SkOpSpan* span) { void SkOpSegment::markDone(SkOpSpan* span) {

View File

@ -105,9 +105,9 @@ public:
void calcAngles(); void calcAngles();
SkOpSpanBase::Collapsed collapsed(double startT, double endT) const; SkOpSpanBase::Collapsed collapsed(double startT, double endT) const;
static void ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, static bool ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle,
SkOpAngle::IncludeType ); SkOpAngle::IncludeType );
static void ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle, static bool ComputeOneSumReverse(SkOpAngle* baseAngle, SkOpAngle* nextAngle,
SkOpAngle::IncludeType ); SkOpAngle::IncludeType );
int computeSum(SkOpSpanBase* start, SkOpSpanBase* end, SkOpAngle::IncludeType includeType); int computeSum(SkOpSpanBase* start, SkOpSpanBase* end, SkOpAngle::IncludeType includeType);
@ -279,9 +279,9 @@ public:
SkOpSpanBase** lastPtr); SkOpSpanBase** lastPtr);
bool markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding, bool markAndChaseWinding(SkOpSpanBase* start, SkOpSpanBase* end, int winding,
int oppWinding, SkOpSpanBase** lastPtr); int oppWinding, SkOpSpanBase** lastPtr);
SkOpSpanBase* markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle); bool markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle, SkOpSpanBase** result);
SkOpSpanBase* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding, bool markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding,
const SkOpAngle* angle); const SkOpAngle* angle, SkOpSpanBase** result);
void markDone(SkOpSpan* ); void markDone(SkOpSpan* );
bool markWinding(SkOpSpan* , int winding); bool markWinding(SkOpSpan* , int winding);
bool markWinding(SkOpSpan* , int winding, int oppWinding); bool markWinding(SkOpSpan* , int winding, int oppWinding);

View File

@ -156,7 +156,8 @@ SkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr,
} }
// OPTIMIZATION: should this also add to the chase? // OPTIMIZATION: should this also add to the chase?
if (sortable) { if (sortable) {
(void) segment->markAngle(maxWinding, sumWinding, angle); // TODO: add error handling
SkAssertResult(segment->markAngle(maxWinding, sumWinding, angle, nullptr));
} }
} }
} }

View File

@ -12,8 +12,8 @@
#include <utility> #include <utility>
static SkOpSegment* findChaseOp(SkTDArray<SkOpSpanBase*>& chase, SkOpSpanBase** startPtr, static bool findChaseOp(SkTDArray<SkOpSpanBase*>& chase, SkOpSpanBase** startPtr,
SkOpSpanBase** endPtr) { SkOpSpanBase** endPtr, SkOpSegment** result) {
while (chase.count()) { while (chase.count()) {
SkOpSpanBase* span; SkOpSpanBase* span;
chase.pop(&span); chase.pop(&span);
@ -30,7 +30,8 @@ static SkOpSegment* findChaseOp(SkTDArray<SkOpSpanBase*>& chase, SkOpSpanBase**
#else #else
*chase.append() = span; *chase.append() = span;
#endif #endif
return last->segment(); *result = last->segment();
return true;
} }
if (done) { if (done) {
continue; continue;
@ -39,7 +40,8 @@ static SkOpSegment* findChaseOp(SkTDArray<SkOpSpanBase*>& chase, SkOpSpanBase**
bool sortable; bool sortable;
const SkOpAngle* angle = AngleWinding(*startPtr, *endPtr, &winding, &sortable); const SkOpAngle* angle = AngleWinding(*startPtr, *endPtr, &winding, &sortable);
if (!angle) { if (!angle) {
return nullptr; *result = nullptr;
return true;
} }
if (winding == SK_MinS32) { if (winding == SK_MinS32) {
continue; continue;
@ -50,12 +52,14 @@ static SkOpSegment* findChaseOp(SkTDArray<SkOpSpanBase*>& chase, SkOpSpanBase**
sumMiWinding = segment->updateWindingReverse(angle); sumMiWinding = segment->updateWindingReverse(angle);
if (sumMiWinding == SK_MinS32) { if (sumMiWinding == SK_MinS32) {
SkASSERT(segment->globalState()->debugSkipAssert()); SkASSERT(segment->globalState()->debugSkipAssert());
return nullptr; *result = nullptr;
return true;
} }
sumSuWinding = segment->updateOppWindingReverse(angle); sumSuWinding = segment->updateOppWindingReverse(angle);
if (sumSuWinding == SK_MinS32) { if (sumSuWinding == SK_MinS32) {
SkASSERT(segment->globalState()->debugSkipAssert()); SkASSERT(segment->globalState()->debugSkipAssert());
return nullptr; *result = nullptr;
return true;
} }
if (segment->operand()) { if (segment->operand()) {
using std::swap; using std::swap;
@ -81,8 +85,10 @@ static SkOpSegment* findChaseOp(SkTDArray<SkOpSpanBase*>& chase, SkOpSpanBase**
} }
// OPTIMIZATION: should this also add to the chase? // OPTIMIZATION: should this also add to the chase?
if (sortable) { if (sortable) {
(void) segment->markAngle(maxWinding, sumWinding, oppMaxWinding, if (!segment->markAngle(maxWinding, sumWinding, oppMaxWinding,
oppSumWinding, angle); oppSumWinding, angle, nullptr)) {
return false;
}
} }
} }
} }
@ -92,10 +98,12 @@ static SkOpSegment* findChaseOp(SkTDArray<SkOpSpanBase*>& chase, SkOpSpanBase**
#else #else
*chase.append() = span; *chase.append() = span;
#endif #endif
return first; *result = first;
return true;
} }
} }
return nullptr; *result = nullptr;
return true;
} }
static bool bridgeOp(SkOpContourHead* contourList, const SkPathOp op, static bool bridgeOp(SkOpContourHead* contourList, const SkPathOp op,
@ -181,7 +189,9 @@ static bool bridgeOp(SkOpContourHead* contourList, const SkPathOp op,
#endif #endif
} }
} }
current = findChaseOp(chase, &start, &end); if (!findChaseOp(chase, &start, &end, &current)) {
return false;
}
SkPathOpsDebug::ShowActiveSpans(contourList); SkPathOpsDebug::ShowActiveSpans(contourList);
if (!current) { if (!current) {
break; break;
@ -347,10 +357,12 @@ bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result
contourList->dumpSegments("aligned"); contourList->dumpSegments("aligned");
#endif #endif
// construct closed contours // construct closed contours
SkPath original = *result;
result->reset(); result->reset();
result->setFillType(fillType); result->setFillType(fillType);
SkPathWriter wrapper(*result); SkPathWriter wrapper(*result);
if (!bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper)) { if (!bridgeOp(contourList, op, xorMask, xorOpMask, &wrapper)) {
*result = original;
return false; return false;
} }
wrapper.assemble(); // if some edges could not be resolved, assemble remaining wrapper.assemble(); // if some edges could not be resolved, assemble remaining

View File

@ -520,6 +520,11 @@ bool testSimplifyCheck(skiatest::Reporter* reporter, const SkPath& path, const c
ExpectSuccess::kYes : ExpectSuccess::kNo, SkipAssert::kNo, ExpectMatch::kNo); ExpectSuccess::kYes : ExpectSuccess::kNo, SkipAssert::kNo, ExpectMatch::kNo);
} }
bool testSimplifyFail(skiatest::Reporter* reporter, const SkPath& path, const char* filename) {
return inner_simplify(reporter, path, filename,
ExpectSuccess::kNo, SkipAssert::kYes, ExpectMatch::kNo);
}
#if DEBUG_SHOW_TEST_NAME #if DEBUG_SHOW_TEST_NAME
static void showName(const SkPath& a, const SkPath& b, const SkPathOp shapeOp) { static void showName(const SkPath& a, const SkPath& b, const SkPathOp shapeOp) {
SkDebugf("\n"); SkDebugf("\n");

View File

@ -38,15 +38,17 @@ extern bool testPathOpCheck(skiatest::Reporter* reporter, const SkPath& a, const
const SkPathOp , const char* testName, bool checkFail); const SkPathOp , const char* testName, bool checkFail);
extern bool testPathOpFail(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b, extern bool testPathOpFail(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
const SkPathOp, const char* testName); const SkPathOp, const char* testName);
extern bool testPathOpFuzz(skiatest::Reporter* reporter, const SkPath& a, extern bool testPathOpFuzz(skiatest::Reporter* reporter, const SkPath& a, const SkPath& b,
const SkPath& b, const SkPathOp , const char* testName); const SkPathOp , const char* testName);
extern bool testSimplify(SkPath& path, bool useXor, SkPath& out, PathOpsThreadState& state, extern bool testSimplify(SkPath& path, bool useXor, SkPath& out, PathOpsThreadState& state,
const char* pathStr); const char* pathStr);
extern bool testSimplify(skiatest::Reporter* reporter, const SkPath& path, const char* filename); extern bool testSimplify(skiatest::Reporter* reporter, const SkPath& path, const char* filename);
extern bool testSimplifyCheck(skiatest::Reporter* reporter, const SkPath& path, extern bool testSimplifyCheck(skiatest::Reporter* reporter, const SkPath& path,
const char* filename, bool checkFail); const char* filename, bool checkFail);
extern bool testSimplifyFail(skiatest::Reporter* reporter, const SkPath& path,
const char* filename);
extern bool testSimplifyFuzz(skiatest::Reporter* reporter, const SkPath& path, extern bool testSimplifyFuzz(skiatest::Reporter* reporter, const SkPath& path,
const char* filename); const char* filename);
void initializeTests(skiatest::Reporter* reporter, const char* testName); void initializeTests(skiatest::Reporter* reporter, const char* testName);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff