aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/pathops
diff options
context:
space:
mode:
authorGravatar Cary Clark <caryclark@skia.org>2018-03-14 15:55:02 -0400
committerGravatar Skia Commit-Bot <skia-commit-bot@chromium.org>2018-03-15 17:07:16 +0000
commitb8421edb47e9b3831df64d03a00f15509c2bebaa (patch)
treec06608d81848316c8a8c1a57938a72911d99ac00 /src/pathops
parentc2ec4e8d83e42d7059528e3ccc7c3ab584ed1f31 (diff)
fix pathops fuzzers and debugging
En route to fixing fuzzer bugs, I discovered that most debugging in pathops was broken. Pathops has extensive runtime functions that trace links and connections between data structures that are invaluable to debugging. The only practical way to use these functions is to call them from the debugger in immediate mode. Some time, some where, the MSVS Immediate Window ceased to be able to call functions that are members of structs or classes, and functions that take templated parameters. I can find no mention of this on the web, so I assume that something about our setup is triggering this, but I've had no luck finding the culprit. In the meantime, I've added global functions wrapped in a namespace to sneak calls to these functions without MSVS being any the wiser. While this works, it is likely to bitrot by tomorrow or next Tuesday so I will continue to try to find and fix the root cause. This also fixes the fuzzer bugs; generally one-line edits that change asserts to fails. All pathops tests succeed with this. To run all tests, do: ./out/debug/pathops_unittest -V -x ./out/release/pathops_unittest -V -x TBR=caryclark@google.com Bug: skia: Change-Id: I956ae3d8df6d25e155e62bd6dede64519c7fbdb1 Reviewed-on: https://skia-review.googlesource.com/114321 Reviewed-by: Kevin Lubick <kjlubick@google.com> Reviewed-by: Cary Clark <caryclark@skia.org> Commit-Queue: Cary Clark <caryclark@skia.org>
Diffstat (limited to 'src/pathops')
-rw-r--r--src/pathops/SkOpCoincidence.cpp4
-rw-r--r--src/pathops/SkPathOpsDebug.cpp11
-rw-r--r--src/pathops/SkPathOpsDebug.h235
-rw-r--r--src/pathops/SkPathOpsTSect.h3
4 files changed, 186 insertions, 67 deletions
diff --git a/src/pathops/SkOpCoincidence.cpp b/src/pathops/SkOpCoincidence.cpp
index 8fa42a5c4e..3251ec4371 100644
--- a/src/pathops/SkOpCoincidence.cpp
+++ b/src/pathops/SkOpCoincidence.cpp
@@ -691,7 +691,7 @@ bool SkOpCoincidence::addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg,
if (overlap && os && oe && overlap->contains(os, oe)) {
return true;
}
- SkASSERT(!cs || !cs->deleted());
+ FAIL_IF(cs && cs->deleted());
FAIL_IF(os && os->deleted());
SkASSERT(!ce || !ce->deleted());
FAIL_IF(oe && oe->deleted());
@@ -1098,7 +1098,7 @@ bool SkOpCoincidence::apply(DEBUG_COIN_DECLARE_ONLY_PARAMS()) {
FAIL_IF(windValue == -1);
start->setWindValue(windValue);
start->setOppValue(oppValue);
- FAIL_IF(oWindValue == -1);
+ FAIL_IF(oWindValue <= -1);
oStart->setWindValue(oWindValue);
oStart->setOppValue(oOppValue);
if (!windValue && !oppValue) {
diff --git a/src/pathops/SkPathOpsDebug.cpp b/src/pathops/SkPathOpsDebug.cpp
index f13b958a84..346db4b340 100644
--- a/src/pathops/SkPathOpsDebug.cpp
+++ b/src/pathops/SkPathOpsDebug.cpp
@@ -47,8 +47,6 @@ const char* SkPathOpsDebug::kPathOpStr[] = {"diff", "sect", "union", "xor", "rdi
#if defined SK_DEBUG || !FORCE_RELEASE
-const char* SkPathOpsDebug::kLVerbStr[] = {"", "line", "quad", "cubic"};
-
int SkPathOpsDebug::gContourID = 0;
int SkPathOpsDebug::gSegmentID = 0;
@@ -3124,3 +3122,12 @@ void SkPathOpsDebug::VerifySimplify(const SkPath& path, const SkPath& result) {
}
#endif
+
+// global path dumps for msvs Visual Studio 17 to use from Immediate Window
+void Dump(const SkPath& path) {
+ path.dump();
+}
+
+void DumpHex(const SkPath& path) {
+ path.dumpHex();
+}
diff --git a/src/pathops/SkPathOpsDebug.h b/src/pathops/SkPathOpsDebug.h
index afdfb32be1..9aec715de1 100644
--- a/src/pathops/SkPathOpsDebug.h
+++ b/src/pathops/SkPathOpsDebug.h
@@ -14,7 +14,36 @@
#include <stdio.h>
enum class SkOpPhase : char;
+struct SkDQuad;
+class SkOpAngle;
+class SkOpCoincidence;
+class SkOpContour;
class SkOpContourHead;
+class SkOpPtT;
+class SkOpSegment;
+class SkOpSpan;
+class SkOpSpanBase;
+struct SkDPoint;
+struct SkDLine;
+struct SkDQuad;
+struct SkDConic;
+struct SkDCubic;
+template<typename TCurve, typename OppCurve> class SkTSect;
+
+// dummy classes to fool msvs Visual Studio 2018 Immediate Window
+#define DummyClasses(a, b) \
+class SkDebugTCoincident##a##b; \
+class SkDebugTSect##a##b; \
+class SkDebugTSpan##a##b
+
+DummyClasses(Quad, Quad);
+DummyClasses(Conic, Quad);
+DummyClasses(Conic, Conic);
+DummyClasses(Cubic, Quad);
+DummyClasses(Cubic, Conic);
+DummyClasses(Cubic, Cubic);
+
+#undef DummyClasses
#ifdef SK_RELEASE
#define FORCE_RELEASE 1
@@ -97,7 +126,7 @@ class SkOpContourHead;
#define DEBUG_PERP 1
#define DEBUG_SHOW_TEST_NAME 1
#define DEBUG_SORT 1
-#define DEBUG_T_SECT 0
+#define DEBUG_T_SECT 0 // enabling may trigger validate asserts even though op does not fail
#define DEBUG_T_SECT_DUMP 0 // Use 1 normally. Use 2 to number segments, 3 for script output
#define DEBUG_T_SECT_LOOP_COUNT 0
#define DEBUG_VALIDATE 1
@@ -233,8 +262,6 @@ class SkOpContourHead;
class SkPathOpsDebug {
public:
- static const char* kLVerbStr[];
-
#if DEBUG_COIN
struct GlitchLog;
@@ -311,7 +338,18 @@ public:
#if DEBUG_ACTIVE_OP
static const char* kPathOpStr[];
#endif
+ static bool gRunFail;
+ static bool gVeryVerbose;
+
+#if DEBUG_ACTIVE_SPANS
+ static SkString gActiveSpans;
+#endif
+#if DEBUG_DUMP_VERIFY
+ static bool gDumpOp;
+ static bool gVerifyOp;
+#endif
+ static const char* OpStr(SkPathOp );
static void MathematicaIze(char* str, size_t bufferSize);
static bool ValidWind(int winding);
static void WindingPrintf(int winding);
@@ -324,86 +362,157 @@ public:
SkPathOpsDebug::DeleteNameStr)))
static void BumpTestName(char* );
#endif
- static const char* OpStr(SkPathOp );
static void ShowActiveSpans(SkOpContourHead* contourList);
static void ShowOnePath(const SkPath& path, const char* name, bool includeDeclaration);
static void ShowPath(const SkPath& one, const SkPath& two, SkPathOp op, const char* name);
- static bool ChaseContains(const SkTDArray<class SkOpSpanBase*>& , const class SkOpSpanBase* );
+ static bool ChaseContains(const SkTDArray<SkOpSpanBase*>& , const SkOpSpanBase* );
static void CheckHealth(class SkOpContourHead* contourList);
- static const class SkOpAngle* DebugAngleAngle(const class SkOpAngle*, int id);
- static class SkOpContour* DebugAngleContour(class SkOpAngle*, int id);
- static const class SkOpPtT* DebugAnglePtT(const class SkOpAngle*, int id);
- static const class SkOpSegment* DebugAngleSegment(const class SkOpAngle*, int id);
- static const class SkOpSpanBase* DebugAngleSpan(const class SkOpAngle*, int id);
-
- static const class SkOpAngle* DebugContourAngle(class SkOpContour*, int id);
- static class SkOpContour* DebugContourContour(class SkOpContour*, int id);
- static const class SkOpPtT* DebugContourPtT(class SkOpContour*, int id);
- static const class SkOpSegment* DebugContourSegment(class SkOpContour*, int id);
- static const class SkOpSpanBase* DebugContourSpan(class SkOpContour*, int id);
-
- static const class SkOpAngle* DebugCoincidenceAngle(class SkOpCoincidence*, int id);
- static class SkOpContour* DebugCoincidenceContour(class SkOpCoincidence*, int id);
- static const class SkOpPtT* DebugCoincidencePtT(class SkOpCoincidence*, int id);
- static const class SkOpSegment* DebugCoincidenceSegment(class SkOpCoincidence*, int id);
- static const class SkOpSpanBase* DebugCoincidenceSpan(class SkOpCoincidence*, int id);
-
- static const class SkOpAngle* DebugPtTAngle(const class SkOpPtT*, int id);
- static class SkOpContour* DebugPtTContour(class SkOpPtT*, int id);
- static const class SkOpPtT* DebugPtTPtT(const class SkOpPtT*, int id);
- static const class SkOpSegment* DebugPtTSegment(const class SkOpPtT*, int id);
- static const class SkOpSpanBase* DebugPtTSpan(const class SkOpPtT*, int id);
-
- static const class SkOpAngle* DebugSegmentAngle(const class SkOpSegment*, int id);
- static class SkOpContour* DebugSegmentContour(class SkOpSegment*, int id);
- static const class SkOpPtT* DebugSegmentPtT(const class SkOpSegment*, int id);
- static const class SkOpSegment* DebugSegmentSegment(const class SkOpSegment*, int id);
- static const class SkOpSpanBase* DebugSegmentSpan(const class SkOpSegment*, int id);
-
- static const class SkOpAngle* DebugSpanAngle(const class SkOpSpanBase*, int id);
- static class SkOpContour* DebugSpanContour(class SkOpSpanBase*, int id);
- static const class SkOpPtT* DebugSpanPtT(const class SkOpSpanBase*, int id);
- static const class SkOpSegment* DebugSpanSegment(const class SkOpSpanBase*, int id);
- static const class SkOpSpanBase* DebugSpanSpan(const class SkOpSpanBase*, int id);
-
#if DEBUG_COIN
- static void DumpCoinDict();
- static void DumpGlitchType(GlitchType );
+ static void DumpCoinDict();
+ static void DumpGlitchType(GlitchType );
#endif
- static bool gRunFail;
- static bool gVeryVerbose;
+};
-#if DEBUG_DUMP_VERIFY
- static bool gDumpOp;
- static bool gVerifyOp;
+// Visual Studio 2017 does not permit calling member functions from the Immediate Window.
+// Global functions work fine, however. Use globals within a namespace rather than
+// static members inside a class.
+namespace SkOpDebug {
+ const SkOpAngle* AngleAngle(const SkOpAngle*, int id);
+ SkOpContour* AngleContour(SkOpAngle*, int id);
+ const SkOpPtT* AnglePtT(const SkOpAngle*, int id);
+ const SkOpSegment* AngleSegment(const SkOpAngle*, int id);
+ const SkOpSpanBase* AngleSpan(const SkOpAngle*, int id);
+
+ const SkOpAngle* ContourAngle(SkOpContour*, int id);
+ SkOpContour* ContourContour(SkOpContour*, int id);
+ const SkOpPtT* ContourPtT(SkOpContour*, int id);
+ const SkOpSegment* ContourSegment(SkOpContour*, int id);
+ const SkOpSpanBase* ContourSpan(SkOpContour*, int id);
+
+ const SkOpAngle* CoincidenceAngle(SkOpCoincidence*, int id);
+ SkOpContour* CoincidenceContour(SkOpCoincidence*, int id);
+ const SkOpPtT* CoincidencePtT(SkOpCoincidence*, int id);
+ const SkOpSegment* CoincidenceSegment(SkOpCoincidence*, int id);
+ const SkOpSpanBase* CoincidenceSpan(SkOpCoincidence*, int id);
+
+ const SkOpAngle* PtTAngle(const SkOpPtT*, int id);
+ SkOpContour* PtTContour(SkOpPtT*, int id);
+ const SkOpPtT* PtTPtT(const SkOpPtT*, int id);
+ const SkOpSegment* PtTSegment(const SkOpPtT*, int id);
+ const SkOpSpanBase* PtTSpan(const SkOpPtT*, int id);
+
+ const SkOpAngle* SegmentAngle(const SkOpSegment*, int id);
+ SkOpContour* SegmentContour(SkOpSegment*, int id);
+ const SkOpPtT* SegmentPtT(const SkOpSegment*, int id);
+ const SkOpSegment* SegmentSegment(const SkOpSegment*, int id);
+ const SkOpSpanBase* SegmentSpan(const SkOpSegment*, int id);
+
+ const SkOpAngle* SpanAngle(const SkOpSpanBase*, int id);
+ SkOpContour* SpanContour(SkOpSpanBase*, int id);
+ const SkOpPtT* SpanPtT(const SkOpSpanBase*, int id);
+ const SkOpSegment* SpanSegment(const SkOpSpanBase*, int id);
+ const SkOpSpanBase* SpanSpan(const SkOpSpanBase*, int id);
- static void DumpOp(const SkPath& one, const SkPath& two, SkPathOp op,
+#if DEBUG_DUMP_VERIFY
+ void DumpOp(const SkPath& one, const SkPath& two, SkPathOp op,
const char* testName);
- static void DumpOp(FILE* file, const SkPath& one, const SkPath& two, SkPathOp op,
+ void DumpOp(FILE* file, const SkPath& one, const SkPath& two, SkPathOp op,
const char* testName);
- static void DumpSimplify(const SkPath& path, const char* testName);
- static void DumpSimplify(FILE* file, const SkPath& path, const char* testName);
- static void ReportOpFail(const SkPath& one, const SkPath& two, SkPathOp op);
- static void ReportSimplifyFail(const SkPath& path);
- static void VerifyOp(const SkPath& one, const SkPath& two, SkPathOp op,
+ void DumpSimplify(const SkPath& path, const char* testName);
+ void DumpSimplify(FILE* file, const SkPath& path, const char* testName);
+ void ReportOpFail(const SkPath& one, const SkPath& two, SkPathOp op);
+ void ReportSimplifyFail(const SkPath& path);
+ void VerifyOp(const SkPath& one, const SkPath& two, SkPathOp op,
const SkPath& result);
- static void VerifySimplify(const SkPath& path, const SkPath& result);
+ void VerifySimplify(const SkPath& path, const SkPath& result);
#endif
-#if DEBUG_ACTIVE_SPANS
- static SkString gActiveSpans;
-#endif
-
-};
-
-struct SkDQuad;
+ // global path dumps for msvs Visual Studio 17 to use from Immediate Window
+ void Dump(const SkOpContour& );
+ void DumpAll(const SkOpContour& );
+ void DumpAngles(const SkOpContour& );
+ void DumpContours(const SkOpContour& );
+ void DumpContoursAll(const SkOpContour& );
+ void DumpContoursAngles(const SkOpContour& );
+ void DumpContoursPts(const SkOpContour& );
+ void DumpContoursPt(const SkOpContour& , int segmentID);
+ void DumpContoursSegment(const SkOpContour& , int segmentID);
+ void DumpContoursSpan(const SkOpContour& , int segmentID);
+ void DumpContoursSpans(const SkOpContour& );
+ void DumpPt(const SkOpContour& , int );
+ void DumpPts(const SkOpContour& , const char* prefix = "seg");
+ void DumpSegment(const SkOpContour& , int );
+ void DumpSegments(const SkOpContour& , const char* prefix = "seg", SkPathOp op = (SkPathOp) -1);
+ void DumpSpan(const SkOpContour& , int );
+ void DumpSpans(const SkOpContour& );
+
+ void Dump(const SkOpSegment& );
+ void DumpAll(const SkOpSegment& );
+ void DumpAngles(const SkOpSegment& );
+ void DumpCoin(const SkOpSegment& );
+ void DumpPts(const SkOpSegment& , const char* prefix = "seg");
+
+ void Dump(const SkOpPtT& );
+ void DumpAll(const SkOpPtT& );
+
+ void Dump(const SkOpSpanBase& );
+ void DumpCoin(const SkOpSpanBase& );
+ void DumpAll(const SkOpSpanBase& );
+
+ void DumpCoin(const SkOpSpan& );
+ bool DumpSpan(const SkOpSpan& );
+
+ void Dump(const SkDConic& );
+ void DumpID(const SkDConic& , int id);
+
+ void Dump(const SkDCubic& );
+ void DumpID(const SkDCubic& , int id);
+
+ void Dump(const SkDLine& );
+ void DumpID(const SkDLine& , int id);
+
+ void Dump(const SkDQuad& );
+ void DumpID(const SkDQuad& , int id);
+
+ void Dump(const SkDPoint& );
+
+// dummy declarations to fool msvs Visual Studio 2018 Immediate Window
+#define DummyDeclarations(a, b) \
+ void Dump(const SkDebugTCoincident##a##b& ); \
+ \
+ void Dump(const SkDebugTSect##a##b& ); \
+ void DumpBoth(const SkDebugTSect##a##b& , SkDebugTSect##a##b* ); \
+ void DumpBounded(const SkDebugTSect##a##b& , int id); \
+ void DumpBounds(const SkDebugTSect##a##b& ); \
+ void DumpCoin(const SkDebugTSect##a##b& ); \
+ void DumpCoinCurves(const SkDebugTSect##a##b& ); \
+ void DumpCurves(const SkDebugTSect##a##b& ); \
+ \
+ void Dump(const SkDebugTSpan##a##b& ); \
+ void DumpAll(const SkDebugTSpan##a##b& ); \
+ void DumpBounded(const SkDebugTSpan##a##b& , int id); \
+ void DumpBounds(const SkDebugTSpan##a##b& ); \
+ void DumpCoin(const SkDebugTSpan##a##b& )
+
+ DummyDeclarations(Quad, Quad);
+ DummyDeclarations(Conic, Quad);
+ DummyDeclarations(Conic, Conic);
+ DummyDeclarations(Cubic, Quad);
+ DummyDeclarations(Cubic, Conic);
+ DummyDeclarations(Cubic, Cubic);
+#undef DummyDeclarations
+}
// generates tools/path_sorter.htm and path_visualizer.htm compatible data
void DumpQ(const SkDQuad& quad1, const SkDQuad& quad2, int testNo);
void DumpT(const SkDQuad& quad, double t);
+// global path dumps for msvs Visual Studio 17 to use from Immediate Window
+void Dump(const SkPath& path);
+void DumpHex(const SkPath& path);
+
#endif
diff --git a/src/pathops/SkPathOpsTSect.h b/src/pathops/SkPathOpsTSect.h
index 833e735da6..1e78f2a108 100644
--- a/src/pathops/SkPathOpsTSect.h
+++ b/src/pathops/SkPathOpsTSect.h
@@ -415,6 +415,7 @@ SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::addFollowing(
next->fPrev = result;
}
result->resetBounds(fCurve);
+ // world may not be consistent to call validate here
result->validate();
return result;
}
@@ -1797,6 +1798,7 @@ void SkTSect<TCurve, OppCurve>::removeSpanRange(SkTSpan<TCurve, OppCurve>* first
final->fPrev = first;
}
first->fNext = final;
+ // world may not be ready for validation here
first->validate();
}
@@ -1888,6 +1890,7 @@ bool SkTSect<TCurve, OppCurve>::unlinkSpan(SkTSpan<TCurve, OppCurve>* span) {
if (next->fStartT > next->fEndT) {
return false;
}
+ // world may not be ready for validate here
next->validate();
}
} else {