diff options
author | caryclark <caryclark@google.com> | 2014-11-13 06:58:52 -0800 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2014-11-13 06:58:52 -0800 |
commit | 65f553182ab7069378ef863d30094d0327f178d0 (patch) | |
tree | 4e7a435941ae82ddd6cab0abcfb2ed7946f79969 /src/pathops/SkPathOpsOp.cpp | |
parent | b1cff03325c42bb1cd87204d9b0dd3d6b9678d3e (diff) |
These tests stress pathops by describing the union of circle-like paths that have tiny line segments embedded and double back to create near-coincident conditions.
The fixes include
- detect when finding the active top loops between two possible answers
- preflight chasing winding to ensure answer is consistent
- binary search more often when quadratic intersection fails
- add more failure paths when an intersect is missed
While this fixes the chrome bug, reenabling path ops in svg should be deferred until additional fixes are landed.
TBR=
BUG=421132
Committed: https://skia.googlesource.com/skia/+/6f726addf3178b01949bb389ef83cf14a1d7b6b2
Review URL: https://codereview.chromium.org/633393002
Diffstat (limited to 'src/pathops/SkPathOpsOp.cpp')
-rw-r--r-- | src/pathops/SkPathOpsOp.cpp | 64 |
1 files changed, 59 insertions, 5 deletions
diff --git a/src/pathops/SkPathOpsOp.cpp b/src/pathops/SkPathOpsOp.cpp index 72efb89d10..f2b25c04ec 100644 --- a/src/pathops/SkPathOpsOp.cpp +++ b/src/pathops/SkPathOpsOp.cpp @@ -45,22 +45,28 @@ static SkOpSegment* findChaseOp(SkTDArray<SkOpSpan*>& chase, int* tIndex, int* e continue; } const SkOpAngle* firstAngle = angle; - SkDEBUGCODE(bool loop = false); - int winding; + bool loop = false; + int winding = SK_MinS32; do { angle = angle->next(); - SkASSERT(angle != firstAngle || !loop); - SkDEBUGCODE(loop |= angle == firstAngle); + if (angle == firstAngle && loop) { + break; // if we get here, there's no winding, loop is unorderable + } + loop |= angle == firstAngle; segment = angle->segment(); winding = segment->windSum(angle); } while (winding == SK_MinS32); + if (winding == SK_MinS32) { + continue; + } int sumMiWinding = segment->updateWindingReverse(angle); int sumSuWinding = segment->updateOppWindingReverse(angle); if (segment->operand()) { SkTSwap<int>(sumMiWinding, sumSuWinding); } SkOpSegment* first = NULL; - while ((angle = angle->next()) != firstAngle) { + bool badData = false; + while ((angle = angle->next()) != firstAngle && !badData) { segment = angle->segment(); int start = angle->start(); int end = angle->end(); @@ -73,11 +79,19 @@ static SkOpSegment* findChaseOp(SkTDArray<SkOpSpan*>& chase, int* tIndex, int* e *tIndex = start; *endIndex = end; } + if (segment->inconsistentAngle(maxWinding, sumWinding, oppMaxWinding, + oppSumWinding, angle)) { + badData = true; + break; + } // OPTIMIZATION: should this also add to the chase? (void) segment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding, angle); } } + if (badData) { + continue; + } if (first) { #if TRY_ROTATE *chase.insert(0) = span; @@ -245,7 +259,47 @@ static const bool gOutInverse[kReverseDifference_PathOp + 1][2][2] = { {{ false, true }, { false, false }}, // rev diff }; +#define DEBUGGING_PATHOPS_FROM_HOST 0 // enable to debug svg in chrome -- note path hardcoded below +#if DEBUGGING_PATHOPS_FROM_HOST +#include "SkData.h" +#include "SkStream.h" + +static void dump_path(FILE* file, const SkPath& path, bool force, bool dumpAsHex) { + SkDynamicMemoryWStream wStream; + path.dump(&wStream, force, dumpAsHex); + SkAutoDataUnref data(wStream.copyToData()); + fprintf(file, "%.*s\n", (int) data->size(), data->data()); +} + +static int dumpID = 0; + +static void dump_op(const SkPath& one, const SkPath& two, SkPathOp op) { +#if SK_BUILD_FOR_MAC + FILE* file = fopen("/Users/caryclark/Documents/svgop.txt", "w"); +#else + FILE* file = fopen("/usr/local/google/home/caryclark/Documents/svgop.txt", "w"); +#endif + fprintf(file, + "\nstatic void fuzz763_%d(skiatest::Reporter* reporter, const char* filename) {\n", + ++dumpID); + fprintf(file, " SkPath path;\n"); + fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", one.getFillType()); + dump_path(file, one, false, true); + fprintf(file, " SkPath path1(path);\n"); + fprintf(file, " path.reset();\n"); + fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", two.getFillType()); + dump_path(file, two, false, true); + fprintf(file, " SkPath path2(path);\n"); + fprintf(file, " testPathOp(reporter, path1, path2, (SkPathOp) %d, filename);\n", op); + fprintf(file, "}\n"); + fclose(file); +} +#endif + bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) { +#if DEBUGGING_PATHOPS_FROM_HOST + dump_op(one, two, op); +#endif #if DEBUG_SHOW_TEST_NAME char* debugName = DEBUG_FILENAME_STRING; if (debugName && debugName[0]) { |