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>
This commit is contained in:
Cary Clark 2018-03-14 15:55:02 -04:00 committed by Skia Commit-Bot
parent c2ec4e8d83
commit b8421edb47
7 changed files with 492 additions and 112 deletions

View File

@ -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) {

View File

@ -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();
}

View File

@ -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 );
#endif
static bool gRunFail;
static bool gVeryVerbose;
#if DEBUG_DUMP_VERIFY
static bool gDumpOp;
static bool gVerifyOp;
static 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,
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,
const SkPath& result);
static void VerifySimplify(const SkPath& path, const SkPath& result);
#endif
#if DEBUG_ACTIVE_SPANS
static SkString gActiveSpans;
static void DumpCoinDict();
static void DumpGlitchType(GlitchType );
#endif
};
struct SkDQuad;
// 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);
#if DEBUG_DUMP_VERIFY
void DumpOp(const SkPath& one, const SkPath& two, SkPathOp op,
const char* testName);
void DumpOp(FILE* file, const SkPath& one, const SkPath& two, SkPathOp op,
const char* testName);
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);
void VerifySimplify(const SkPath& path, const SkPath& result);
#endif
// 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

View File

@ -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 {

View File

@ -208,130 +208,134 @@ void SkIntersections::dump() const {
SkDebugf("\n");
}
const SkOpAngle* SkPathOpsDebug::DebugAngleAngle(const SkOpAngle* angle, int id) {
namespace SkOpDebug {
const ::SkOpAngle* AngleAngle(const ::SkOpAngle* angle, int id) {
return angle->debugAngle(id);
}
SkOpContour* SkPathOpsDebug::DebugAngleContour(SkOpAngle* angle, int id) {
::SkOpContour* AngleContour(::SkOpAngle* angle, int id) {
return angle->debugContour(id);
}
const SkOpPtT* SkPathOpsDebug::DebugAnglePtT(const SkOpAngle* angle, int id) {
const ::SkOpPtT* AnglePtT(const ::SkOpAngle* angle, int id) {
return angle->debugPtT(id);
}
const SkOpSegment* SkPathOpsDebug::DebugAngleSegment(const SkOpAngle* angle, int id) {
const ::SkOpSegment* AngleSegment(const ::SkOpAngle* angle, int id) {
return angle->debugSegment(id);
}
const SkOpSpanBase* SkPathOpsDebug::DebugAngleSpan(const SkOpAngle* angle, int id) {
const ::SkOpSpanBase* AngleSpan(const ::SkOpAngle* angle, int id) {
return angle->debugSpan(id);
}
const SkOpAngle* SkPathOpsDebug::DebugContourAngle(SkOpContour* contour, int id) {
const ::SkOpAngle* ContourAngle(::SkOpContour* contour, int id) {
return contour->debugAngle(id);
}
SkOpContour* SkPathOpsDebug::DebugContourContour(SkOpContour* contour, int id) {
::SkOpContour* ContourContour(::SkOpContour* contour, int id) {
return contour->debugContour(id);
}
const SkOpPtT* SkPathOpsDebug::DebugContourPtT(SkOpContour* contour, int id) {
const ::SkOpPtT* ContourPtT(::SkOpContour* contour, int id) {
return contour->debugPtT(id);
}
const SkOpSegment* SkPathOpsDebug::DebugContourSegment(SkOpContour* contour, int id) {
const ::SkOpSegment* ContourSegment(::SkOpContour* contour, int id) {
return contour->debugSegment(id);
}
const SkOpSpanBase* SkPathOpsDebug::DebugContourSpan(SkOpContour* contour, int id) {
const ::SkOpSpanBase* ContourSpan(::SkOpContour* contour, int id) {
return contour->debugSpan(id);
}
const SkOpAngle* SkPathOpsDebug::DebugCoincidenceAngle(SkOpCoincidence* coin, int id) {
const ::SkOpAngle* CoincidenceAngle(::SkOpCoincidence* coin, int id) {
return coin->debugAngle(id);
}
SkOpContour* SkPathOpsDebug::DebugCoincidenceContour(SkOpCoincidence* coin, int id) {
::SkOpContour* CoincidenceContour(::SkOpCoincidence* coin, int id) {
return coin->debugContour(id);
}
const SkOpPtT* SkPathOpsDebug::DebugCoincidencePtT(SkOpCoincidence* coin, int id) {
const ::SkOpPtT* CoincidencePtT(::SkOpCoincidence* coin, int id) {
return coin->debugPtT(id);
}
const SkOpSegment* SkPathOpsDebug::DebugCoincidenceSegment(SkOpCoincidence* coin, int id) {
const ::SkOpSegment* CoincidenceSegment(::SkOpCoincidence* coin, int id) {
return coin->debugSegment(id);
}
const SkOpSpanBase* SkPathOpsDebug::DebugCoincidenceSpan(SkOpCoincidence* coin, int id) {
const ::SkOpSpanBase* CoincidenceSpan(::SkOpCoincidence* coin, int id) {
return coin->debugSpan(id);
}
const SkOpAngle* SkPathOpsDebug::DebugPtTAngle(const SkOpPtT* ptT, int id) {
const ::SkOpAngle* PtTAngle(const ::SkOpPtT* ptT, int id) {
return ptT->debugAngle(id);
}
SkOpContour* SkPathOpsDebug::DebugPtTContour(SkOpPtT* ptT, int id) {
::SkOpContour* PtTContour(::SkOpPtT* ptT, int id) {
return ptT->debugContour(id);
}
const SkOpPtT* SkPathOpsDebug::DebugPtTPtT(const SkOpPtT* ptT, int id) {
const ::SkOpPtT* PtTPtT(const ::SkOpPtT* ptT, int id) {
return ptT->debugPtT(id);
}
const SkOpSegment* SkPathOpsDebug::DebugPtTSegment(const SkOpPtT* ptT, int id) {
const ::SkOpSegment* PtTSegment(const ::SkOpPtT* ptT, int id) {
return ptT->debugSegment(id);
}
const SkOpSpanBase* SkPathOpsDebug::DebugPtTSpan(const SkOpPtT* ptT, int id) {
const ::SkOpSpanBase* PtTSpan(const ::SkOpPtT* ptT, int id) {
return ptT->debugSpan(id);
}
const SkOpAngle* SkPathOpsDebug::DebugSegmentAngle(const SkOpSegment* span, int id) {
const ::SkOpAngle* SegmentAngle(const ::SkOpSegment* span, int id) {
return span->debugAngle(id);
}
SkOpContour* SkPathOpsDebug::DebugSegmentContour(SkOpSegment* span, int id) {
::SkOpContour* SegmentContour(::SkOpSegment* span, int id) {
return span->debugContour(id);
}
const SkOpPtT* SkPathOpsDebug::DebugSegmentPtT(const SkOpSegment* span, int id) {
const ::SkOpPtT* SegmentPtT(const ::SkOpSegment* span, int id) {
return span->debugPtT(id);
}
const SkOpSegment* SkPathOpsDebug::DebugSegmentSegment(const SkOpSegment* span, int id) {
const ::SkOpSegment* SegmentSegment(const ::SkOpSegment* span, int id) {
return span->debugSegment(id);
}
const SkOpSpanBase* SkPathOpsDebug::DebugSegmentSpan(const SkOpSegment* span, int id) {
const ::SkOpSpanBase* SegmentSpan(const ::SkOpSegment* span, int id) {
return span->debugSpan(id);
}
const SkOpAngle* SkPathOpsDebug::DebugSpanAngle(const SkOpSpanBase* span, int id) {
const ::SkOpAngle* SpanAngle(const ::SkOpSpanBase* span, int id) {
return span->debugAngle(id);
}
SkOpContour* SkPathOpsDebug::DebugSpanContour(SkOpSpanBase* span, int id) {
::SkOpContour* SpanContour(::SkOpSpanBase* span, int id) {
return span->debugContour(id);
}
const SkOpPtT* SkPathOpsDebug::DebugSpanPtT(const SkOpSpanBase* span, int id) {
const ::SkOpPtT* SpanPtT(const ::SkOpSpanBase* span, int id) {
return span->debugPtT(id);
}
const SkOpSegment* SkPathOpsDebug::DebugSpanSegment(const SkOpSpanBase* span, int id) {
const ::SkOpSegment* SpanSegment(const ::SkOpSpanBase* span, int id) {
return span->debugSegment(id);
}
const SkOpSpanBase* SkPathOpsDebug::DebugSpanSpan(const SkOpSpanBase* span, int id) {
const ::SkOpSpanBase* SpanSpan(const ::SkOpSpanBase* span, int id) {
return span->debugSpan(id);
}
} // namespace SkPathOpsDebug
#if DEBUG_COIN
void SkPathOpsDebug::DumpCoinDict() {
gCoinSumChangedDict.dump("unused coin algorithm", false);
gCoinSumVisitedDict.dump("visited coin function", true);
SkPathOpsDebug::gCoinSumChangedDict.dump("unused coin algorithm", false);
SkPathOpsDebug::gCoinSumVisitedDict.dump("visited coin function", true);
}
void SkPathOpsDebug::CoinDict::dump(const char* str, bool visitCheck) const {
@ -1479,3 +1483,223 @@ const SkOpSpanBase* SkOpGlobalState::debugSpan(int id) const {
#if DEBUG_T_SECT_DUMP > 1
int gDumpTSectNum;
#endif
// global path dumps for msvs Visual Studio 17 to use from Immediate Window
namespace SkOpDebug {
void Dump(const SkOpContour& contour) {
contour.dump();
}
void DumpAll(const SkOpContour& contour) {
contour.dumpAll();
}
void DumpAngles(const SkOpContour& contour) {
contour.dumpAngles();
}
void DumpContours(const SkOpContour& contour) {
contour.dumpContours();
}
void DumpContoursAll(const SkOpContour& contour) {
contour.dumpContoursAll();
}
void DumpContoursAngles(const SkOpContour& contour) {
contour.dumpContoursAngles();
}
void DumpContoursPts(const SkOpContour& contour) {
contour.dumpContoursPts();
}
void DumpContoursPt(const SkOpContour& contour, int segmentID) {
contour.dumpContoursPt(segmentID);
}
void DumpContoursSegment(const SkOpContour& contour, int segmentID) {
contour.dumpContoursSegment(segmentID);
}
void DumpContoursSpan(const SkOpContour& contour, int segmentID) {
contour.dumpContoursSpan(segmentID);
}
void DumpContoursSpans(const SkOpContour& contour) {
contour.dumpContoursSpans();
}
void DumpPt(const SkOpContour& contour, int pt) {
contour.dumpPt(pt);
}
void DumpPts(const SkOpContour& contour, const char* prefix) {
contour.dumpPts(prefix);
}
void DumpSegment(const SkOpContour& contour, int seg) {
contour.dumpSegment(seg);
}
void DumpSegments(const SkOpContour& contour, const char* prefix, SkPathOp op) {
contour.dumpSegments(prefix, op);
}
void DumpSpan(const SkOpContour& contour, int span) {
contour.dumpSpan(span);
}
void DumpSpans(const SkOpContour& contour ) {
contour.dumpSpans();
}
void Dump(const SkOpSegment& segment) {
segment.dump();
}
void DumpAll(const SkOpSegment& segment) {
segment.dumpAll();
}
void DumpAngles(const SkOpSegment& segment) {
segment.dumpAngles();
}
void DumpCoin(const SkOpSegment& segment) {
segment.dumpCoin();
}
void DumpPts(const SkOpSegment& segment, const char* prefix) {
segment.dumpPts(prefix);
}
void Dump(const SkOpPtT& ptT) {
ptT.dump();
}
void DumpAll(const SkOpPtT& ptT) {
ptT.dumpAll();
}
void Dump(const SkOpSpanBase& spanBase) {
spanBase.dump();
}
void DumpCoin(const SkOpSpanBase& spanBase) {
spanBase.dumpCoin();
}
void DumpAll(const SkOpSpanBase& spanBase) {
spanBase.dumpAll();
}
void DumpCoin(const SkOpSpan& span) {
span.dumpCoin();
}
bool DumpSpan(const SkOpSpan& span) {
return span.dumpSpan();
}
void Dump(const SkDConic& conic) {
conic.dump();
}
void DumpID(const SkDConic& conic, int id) {
conic.dumpID(id);
}
void Dump(const SkDCubic& cubic) {
cubic.dump();
}
void DumpID(const SkDCubic& cubic, int id) {
cubic.dumpID(id);
}
void Dump(const SkDLine& line) {
line.dump();
}
void DumpID(const SkDLine& line, int id) {
line.dumpID(id);
}
void Dump(const SkDQuad& quad) {
quad.dump();
}
void DumpID(const SkDQuad& quad, int id) {
quad.dumpID(id);
}
void Dump(const SkDPoint& point) {
point.dump();
}
// dummy definitions to fool msvs Visual Studio 2018 Immediate Window
#define DummyDefinitions(a, b) \
\
void Dump(const SkDebugTCoincident##a##b& curve) { \
((const SkTCoincident<SkD##a, SkD##b>& ) curve).dump(); \
} \
\
void Dump(const SkDebugTSect##a##b& curve) { \
((const SkTSect<SkD##a, SkD##b>& ) curve).dump(); \
} \
\
void DumpBoth(const SkDebugTSect##a##b& curve, SkDebugTSect##a##b* opp) { \
((const SkTSect<SkD##a, SkD##b>& ) curve).dumpBoth((SkTSect<SkD##b, SkD##a>* ) opp); \
} \
\
void DumpBounded(const SkDebugTSect##a##b& curve, int id) { \
((const SkTSect<SkD##a, SkD##b>& ) curve).dumpBounded(id); \
} \
\
void DumpBounds(const SkDebugTSect##a##b& curve) { \
((const SkTSect<SkD##a, SkD##b>& ) curve).dumpBounds(); \
} \
\
void DumpCoin(const SkDebugTSect##a##b& curve) { \
((const SkTSect<SkD##a, SkD##b>& ) curve).dumpCoin(); \
} \
\
void DumpCoinCurves(const SkDebugTSect##a##b& curve) { \
((const SkTSect<SkD##a, SkD##b>& ) curve).dumpCoinCurves(); \
} \
\
void DumpCurves(const SkDebugTSect##a##b& curve) { \
((const SkTSect<SkD##a, SkD##b>& ) curve).dumpCurves(); \
} \
\
void Dump(const SkDebugTSpan##a##b& curve) { \
((const SkTSpan<SkD##a, SkD##b>& ) curve).dump(); \
} \
\
void DumpAll(const SkDebugTSpan##a##b& curve) { \
((const SkTSpan<SkD##a, SkD##b>& ) curve).dumpAll(); \
} \
\
void DumpBounded(const SkDebugTSpan##a##b& curve, int id) { \
((const SkTSpan<SkD##a, SkD##b>& ) curve).dumpBounded(id); \
} \
\
void DumpBounds(const SkDebugTSpan##a##b& curve) { \
((const SkTSpan<SkD##a, SkD##b>& ) curve).dumpBounds(); \
} \
\
void DumpCoin(const SkDebugTSpan##a##b& curve) { \
((const SkTSpan<SkD##a, SkD##b>& ) curve).dumpCoin(); \
}
DummyDefinitions(Quad, Quad);
DummyDefinitions(Conic, Quad);
DummyDefinitions(Conic, Conic);
DummyDefinitions(Cubic, Quad);
DummyDefinitions(Cubic, Conic);
DummyDefinitions(Cubic, Cubic);
#undef DummyDefinitions
}

View File

@ -217,20 +217,57 @@ path.close();
static void fuzz_x3(skiatest::Reporter* reporter, const char* filename) {
SkPath path;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
path.cubicTo(SkBits2Float(0x92743420), SkBits2Float(0x74747474), SkBits2Float(0x0f747c74), SkBits2Float(0xff538565), SkBits2Float(0x74744374), SkBits2Float(0x20437474)); // -7.70571e-28f, 7.74708e+31f, 1.20541e-29f, -2.8116e+38f, 7.74102e+31f, 1.65557e-19f
path.conicTo(SkBits2Float(0x7474926d), SkBits2Float(0x7c747474), SkBits2Float(0x00170f74), SkBits2Float(0x3a7410d7), SkBits2Float(0x3a3a3a3a)); // 7.7508e+31f, 5.07713e+36f, 2.11776e-39f, 0.000931037f, 0.000710401f
path.quadTo(SkBits2Float(0x203a3a3a), SkBits2Float(0x7459f43a), SkBits2Float(0x74747474), SkBits2Float(0x2043ad6e)); // 1.57741e-19f, 6.90724e+31f, 7.74708e+31f, 1.65745e-19f
path.conicTo(SkBits2Float(0x7474b374), SkBits2Float(0x74747474), SkBits2Float(0x0f747c74), SkBits2Float(0xff537065), SkBits2Float(0x74744374)); // 7.75488e+31f, 7.74708e+31f, 1.20541e-29f, -2.81051e+38f, 7.74102e+31f
path.cubicTo(SkBits2Float(0x3a3a3a3a), SkBits2Float(0x3a2c103a), SkBits2Float(0x7474263a), SkBits2Float(0x74976507), SkBits2Float(0x000000ff), SkBits2Float(0x00000000)); // 0.000710401f, 0.00065637f, 7.7374e+31f, 9.59578e+31f, 3.57331e-43f, 0
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
path.cubicTo(SkBits2Float(0x92743420), SkBits2Float(0x74747474), SkBits2Float(0x0f747c74), SkBits2Float(0xff538565), SkBits2Float(0x74744374), SkBits2Float(0x20437474)); // -7.70571e-28f, 7.74708e+31f, 1.20541e-29f, -2.8116e+38f, 7.74102e+31f, 1.65557e-19f
path.conicTo(SkBits2Float(0x7474926d), SkBits2Float(0x7c747474), SkBits2Float(0x00170f74), SkBits2Float(0x3a7410d7), SkBits2Float(0x3a3a3a3a)); // 7.7508e+31f, 5.07713e+36f, 2.11776e-39f, 0.000931037f, 0.000710401f
path.quadTo(SkBits2Float(0x203a3a3a), SkBits2Float(0x7459f43a), SkBits2Float(0x74747474), SkBits2Float(0x2043ad6e)); // 1.57741e-19f, 6.90724e+31f, 7.74708e+31f, 1.65745e-19f
path.conicTo(SkBits2Float(0x7474b374), SkBits2Float(0x74747474), SkBits2Float(0x0f747c74), SkBits2Float(0xff537065), SkBits2Float(0x74744374)); // 7.75488e+31f, 7.74708e+31f, 1.20541e-29f, -2.81051e+38f, 7.74102e+31f
path.cubicTo(SkBits2Float(0x3a3a3a3a), SkBits2Float(0x3a2c103a), SkBits2Float(0x7474263a), SkBits2Float(0x74976507), SkBits2Float(0x000000ff), SkBits2Float(0x00000000)); // 0.000710401f, 0.00065637f, 7.7374e+31f, 9.59578e+31f, 3.57331e-43f, 0
testSimplifyFuzz(reporter, path, filename);
}
static void fuzz_k1(skiatest::Reporter* reporter, const char* filename) {
SkPath path;
path.setFillType(SkPath::kWinding_FillType);
path.moveTo(SkBits2Float(0x00000000), SkBits2Float(0x00000000)); // 0, 0
path.conicTo(SkBits2Float(0x2073732f), SkBits2Float(0x73f17f00), SkBits2Float(0x737b7b73), SkBits2Float(0x73916773), SkBits2Float(0x00738773)); // 2.0621e-19f, 3.82666e+31f, 1.99245e+31f, 2.30402e+31f, 1.06097e-38f
path.lineTo(SkBits2Float(0x5803736d), SkBits2Float(0x807b5ba1)); // 5.78127e+14f, -1.13286e-38f
path.cubicTo(SkBits2Float(0x7b7f7f7b), SkBits2Float(0x7373737b), SkBits2Float(0x1b617380), SkBits2Float(0x48541b10), SkBits2Float(0x73817373), SkBits2Float(0x00717373)); // 1.32662e+36f, 1.92882e+31f, 1.86489e-22f, 217196, 2.05123e+31f, 1.04188e-38f
path.moveTo(SkBits2Float(0x7373739a), SkBits2Float(0x50001073)); // 1.92882e+31f, 8.59425e+09f
path.cubicTo(SkBits2Float(0x7b738364), SkBits2Float(0x73607380), SkBits2Float(0x7b738362), SkBits2Float(0x00007180), SkBits2Float(0x7373739a), SkBits2Float(0x50001073)); // 1.26439e+36f, 1.77829e+31f, 1.26439e+36f, 4.07161e-41f, 1.92882e+31f, 8.59425e+09f
path.cubicTo(SkBits2Float(0x7b737364), SkBits2Float(0x73607380), SkBits2Float(0x7b738366), SkBits2Float(0x73737380), SkBits2Float(0x73738873), SkBits2Float(0x96737353)); // 1.26407e+36f, 1.77829e+31f, 1.26439e+36f, 1.92882e+31f, 1.92947e+31f, -1.96658e-25f
path.moveTo(SkBits2Float(0x00640000), SkBits2Float(0x73737373)); // 9.18355e-39f, 1.92882e+31f
path.lineTo(SkBits2Float(0x40005d7b), SkBits2Float(0x58435460)); // 2.00571f, 8.59069e+14f
path.cubicTo(SkBits2Float(0x7b7f7f7b), SkBits2Float(0x7373737b), SkBits2Float(0x1b617380), SkBits2Float(0x48400010), SkBits2Float(0x73817373), SkBits2Float(0x00717373)); // 1.32662e+36f, 1.92882e+31f, 1.86489e-22f, 196608, 2.05123e+31f, 1.04188e-38f
path.moveTo(SkBits2Float(0x06737376), SkBits2Float(0x50001073)); // 4.5788e-35f, 8.59425e+09f
path.cubicTo(SkBits2Float(0x7b737364), SkBits2Float(0x73737373), SkBits2Float(0x53737388), SkBits2Float(0x00967373), SkBits2Float(0x00640000), SkBits2Float(0x73737373)); // 1.26407e+36f, 1.92882e+31f, 1.04562e+12f, 1.38167e-38f, 9.18355e-39f, 1.92882e+31f
path.lineTo(SkBits2Float(0x40005d7b), SkBits2Float(0x5843546d)); // 2.00571f, 8.59069e+14f
path.cubicTo(SkBits2Float(0x7b7f7f7b), SkBits2Float(0x7373737b), SkBits2Float(0x1b617380), SkBits2Float(0x4840001e), SkBits2Float(0x73817373), SkBits2Float(0x007e7373)); // 1.32662e+36f, 1.92882e+31f, 1.86489e-22f, 196608, 2.05123e+31f, 1.16127e-38f
path.moveTo(SkBits2Float(0x06737376), SkBits2Float(0x50001073)); // 4.5788e-35f, 8.59425e+09f
path.cubicTo(SkBits2Float(0x7b737364), SkBits2Float(0x73607380), SkBits2Float(0x01008366), SkBits2Float(0x73737380), SkBits2Float(0x737d8873), SkBits2Float(0x7b4e7b53)); // 1.26407e+36f, 1.77829e+31f, 2.36042e-38f, 1.92882e+31f, 2.0087e+31f, 1.07211e+36f
path.cubicTo(SkBits2Float(0x667b7b7b), SkBits2Float(0x73737b7b), SkBits2Float(0x73739167), SkBits2Float(0x40007387), SkBits2Float(0x5803736d), SkBits2Float(0x807b5ba1)); // 2.96898e+23f, 1.92907e+31f, 1.92974e+31f, 2.00705f, 5.78127e+14f, -1.13286e-38f
path.cubicTo(SkBits2Float(0x7b7f7f7b), SkBits2Float(0x7373737b), SkBits2Float(0x1b617380), SkBits2Float(0x48401b10), SkBits2Float(0x73817373), SkBits2Float(0x00717373)); // 1.32662e+36f, 1.92882e+31f, 1.86489e-22f, 196716, 2.05123e+31f, 1.04188e-38f
path.moveTo(SkBits2Float(0x7373739a), SkBits2Float(0x50001073)); // 1.92882e+31f, 8.59425e+09f
path.cubicTo(SkBits2Float(0x7b737364), SkBits2Float(0x73607380), SkBits2Float(0x7b738366), SkBits2Float(0x00007180), SkBits2Float(0x7373739a), SkBits2Float(0x50001073)); // 1.26407e+36f, 1.77829e+31f, 1.26439e+36f, 4.07161e-41f, 1.92882e+31f, 8.59425e+09f
path.cubicTo(SkBits2Float(0x7b737364), SkBits2Float(0x73607380), SkBits2Float(0x79738366), SkBits2Float(0x79797979), SkBits2Float(0xff000079), SkBits2Float(0xf2f2f2ff)); // 1.26407e+36f, 1.77829e+31f, 7.90246e+34f, 8.09591e+34f, -1.70144e+38f, -9.62421e+30f
path.cubicTo(SkBits2Float(0x6579796a), SkBits2Float(0x79795979), SkBits2Float(0x4d4d7b57), SkBits2Float(0x4d574d66), SkBits2Float(0x7968ac4d), SkBits2Float(0x79797979)); // 7.36318e+22f, 8.09185e+34f, 2.15463e+08f, 2.25761e+08f, 7.55067e+34f, 8.09591e+34f
path.quadTo(SkBits2Float(0xf2f27b79), SkBits2Float(0x867b9c7b), SkBits2Float(0xddf2f2f2), SkBits2Float(0x1379796a)); // -9.60571e+30f, -4.73228e-35f, -2.18829e+18f, 3.14881e-27f
path.lineTo(SkBits2Float(0x7373739a), SkBits2Float(0x50001073)); // 1.92882e+31f, 8.59425e+09f
path.close();
path.moveTo(SkBits2Float(0x7373739a), SkBits2Float(0x50001073)); // 1.92882e+31f, 8.59425e+09f
path.quadTo(SkBits2Float(0xe7797979), SkBits2Float(0xf2794d4d), SkBits2Float(0x79a8ddf2), SkBits2Float(0x13132513)); // -1.17811e+24f, -4.93793e+30f, 1.09601e+35f, 1.85723e-27f
path.lineTo(SkBits2Float(0x7373739a), SkBits2Float(0x50001073)); // 1.92882e+31f, 8.59425e+09f
path.close();
path.moveTo(SkBits2Float(0x7373739a), SkBits2Float(0x50001073)); // 1.92882e+31f, 8.59425e+09f
path.quadTo(SkBits2Float(0x7b9c7b79), SkBits2Float(0xf4f2d886), SkBits2Float(0xf4f4f4f4), SkBits2Float(0xf4f4f4f4)); // 1.62501e+36f, -1.53922e+32f, -1.5526e+32f, -1.5526e+32f
testSimplifyFuzz(reporter, path, filename);
}
#define TEST(test) test(reporter, #test)
DEF_TEST(PathOpsSimplifyFail, reporter) {
TEST(fuzz_k1);
TEST(fuzz_x3);
TEST(fuzz763_2);
TEST(fuzz763_1);

View File

@ -67,7 +67,7 @@ void SkTSect<TCurve, OppCurve>::dumpBoth(SkTSect<OppCurve, TCurve>* opp) const {
SkDebugf("%d ", ++gDumpTSectNum);
#endif
this->dump();
SkDebugf(" ");
SkDebugf("\n");
opp->dump();
SkDebugf("\n");
#elif DEBUG_T_SECT_DUMP == 3