b8421edb47
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>
225 lines
6.4 KiB
C++
225 lines
6.4 KiB
C++
/*
|
|
* Copyright 2014 Google Inc.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license that can be
|
|
* found in the LICENSE file.
|
|
*/
|
|
#ifndef PathOpsTSectDebug_DEFINED
|
|
#define PathOpsTSectDebug_DEFINED
|
|
|
|
#include "SkPathOpsTSect.h"
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
char SkTCoincident<TCurve, OppCurve>::dumpIsCoincidentStr() const {
|
|
if (!!fMatch != fMatch) {
|
|
return '?';
|
|
}
|
|
return fMatch ? '*' : 0;
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTCoincident<TCurve, OppCurve>::dump() const {
|
|
SkDebugf("t=%1.9g pt=(%1.9g,%1.9g)%s\n", fPerpT, fPerpPt.fX, fPerpPt.fY,
|
|
fMatch ? " match" : "");
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
const SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::debugSpan(int id) const {
|
|
const SkTSpan<TCurve, OppCurve>* test = fHead;
|
|
do {
|
|
if (test->debugID() == id) {
|
|
return test;
|
|
}
|
|
} while ((test = test->next()));
|
|
return nullptr;
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
const SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::debugT(double t) const {
|
|
const SkTSpan<TCurve, OppCurve>* test = fHead;
|
|
const SkTSpan<TCurve, OppCurve>* closest = nullptr;
|
|
double bestDist = DBL_MAX;
|
|
do {
|
|
if (between(test->fStartT, t, test->fEndT)) {
|
|
return test;
|
|
}
|
|
double testDist = SkTMin(fabs(test->fStartT - t), fabs(test->fEndT - t));
|
|
if (bestDist > testDist) {
|
|
bestDist = testDist;
|
|
closest = test;
|
|
}
|
|
} while ((test = test->next()));
|
|
SkASSERT(closest);
|
|
return closest;
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTSect<TCurve, OppCurve>::dump() const {
|
|
dumpCommon(fHead);
|
|
}
|
|
|
|
extern int gDumpTSectNum;
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTSect<TCurve, OppCurve>::dumpBoth(SkTSect<OppCurve, TCurve>* opp) const {
|
|
#if DEBUG_T_SECT_DUMP <= 2
|
|
#if DEBUG_T_SECT_DUMP == 2
|
|
SkDebugf("%d ", ++gDumpTSectNum);
|
|
#endif
|
|
this->dump();
|
|
SkDebugf("\n");
|
|
opp->dump();
|
|
SkDebugf("\n");
|
|
#elif DEBUG_T_SECT_DUMP == 3
|
|
SkDebugf("<div id=\"sect%d\">\n", ++gDumpTSectNum);
|
|
if (this->fHead) {
|
|
this->dumpCurves();
|
|
}
|
|
if (opp->fHead) {
|
|
opp->dumpCurves();
|
|
}
|
|
SkDebugf("</div>\n\n");
|
|
#endif
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTSect<TCurve, OppCurve>::dumpBounded(int id) const {
|
|
const SkTSpan<TCurve, OppCurve>* bounded = debugSpan(id);
|
|
if (!bounded) {
|
|
SkDebugf("no span matches %d\n", id);
|
|
return;
|
|
}
|
|
const SkTSpan<OppCurve, TCurve>* test = bounded->debugOpp()->fHead;
|
|
do {
|
|
if (test->findOppSpan(bounded)) {
|
|
test->dump();
|
|
SkDebugf(" ");
|
|
}
|
|
} while ((test = test->next()));
|
|
SkDebugf("\n");
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTSect<TCurve, OppCurve>::dumpBounds() const {
|
|
const SkTSpan<TCurve, OppCurve>* test = fHead;
|
|
do {
|
|
test->dumpBounds();
|
|
} while ((test = test->next()));
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTSect<TCurve, OppCurve>::dumpCoin() const {
|
|
dumpCommon(fCoincident);
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTSect<TCurve, OppCurve>::dumpCoinCurves() const {
|
|
dumpCommonCurves(fCoincident);
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTSect<TCurve, OppCurve>::dumpCommon(const SkTSpan<TCurve, OppCurve>* test) const {
|
|
SkDebugf("id=%d", debugID());
|
|
if (!test) {
|
|
SkDebugf(" (empty)");
|
|
return;
|
|
}
|
|
do {
|
|
SkDebugf(" ");
|
|
test->dump();
|
|
} while ((test = test->next()));
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTSect<TCurve, OppCurve>::dumpCommonCurves(const SkTSpan<TCurve, OppCurve>* test) const {
|
|
do {
|
|
test->fPart.dumpID(test->debugID());
|
|
} while ((test = test->next()));
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTSect<TCurve, OppCurve>::dumpCurves() const {
|
|
dumpCommonCurves(fHead);
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
const SkTSpan<TCurve, OppCurve>* SkTSpan<TCurve, OppCurve>::debugSpan(int id) const {
|
|
return SkDEBUGRELEASE(fDebugSect->debugSpan(id), nullptr);
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
const SkTSpan<TCurve, OppCurve>* SkTSpan<TCurve, OppCurve>::debugT(double t) const {
|
|
return SkDEBUGRELEASE(fDebugSect->debugT(t), nullptr);
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTSpan<TCurve, OppCurve>::dumpAll() const {
|
|
dumpID();
|
|
SkDebugf("=(%g,%g) [", fStartT, fEndT);
|
|
const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded;
|
|
while (testBounded) {
|
|
const SkTSpan<OppCurve, TCurve>* span = testBounded->fBounded;
|
|
const SkTSpanBounded<OppCurve, TCurve>* next = testBounded->fNext;
|
|
span->dumpID();
|
|
SkDebugf("=(%g,%g)", span->fStartT, span->fEndT);
|
|
if (next) {
|
|
SkDebugf(" ");
|
|
}
|
|
testBounded = next;
|
|
}
|
|
SkDebugf("]\n");
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTSpan<TCurve, OppCurve>::dump() const {
|
|
dumpID();
|
|
SkDebugf("=(%g,%g) [", fStartT, fEndT);
|
|
const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded;
|
|
while (testBounded) {
|
|
const SkTSpan<OppCurve, TCurve>* span = testBounded->fBounded;
|
|
const SkTSpanBounded<OppCurve, TCurve>* next = testBounded->fNext;
|
|
span->dumpID();
|
|
if (next) {
|
|
SkDebugf(",");
|
|
}
|
|
testBounded = next;
|
|
}
|
|
SkDebugf("]");
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTSpan<TCurve, OppCurve>::dumpBounded(int id) const {
|
|
SkDEBUGCODE(fDebugSect->dumpBounded(id));
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTSpan<TCurve, OppCurve>::dumpBounds() const {
|
|
dumpID();
|
|
SkDebugf(" bounds=(%1.9g,%1.9g, %1.9g,%1.9g) boundsMax=%1.9g%s\n",
|
|
fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom, fBoundsMax,
|
|
fCollapsed ? " collapsed" : "");
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTSpan<TCurve, OppCurve>::dumpCoin() const {
|
|
dumpID();
|
|
SkDebugf(" coinStart ");
|
|
fCoinStart.dump();
|
|
SkDebugf(" coinEnd ");
|
|
fCoinEnd.dump();
|
|
}
|
|
|
|
template<typename TCurve, typename OppCurve>
|
|
void SkTSpan<TCurve, OppCurve>::dumpID() const {
|
|
char cS = fCoinStart.dumpIsCoincidentStr();
|
|
if (cS) {
|
|
SkDebugf("%c", cS);
|
|
}
|
|
SkDebugf("%d", debugID());
|
|
char cE = fCoinEnd.dumpIsCoincidentStr();
|
|
if (cE) {
|
|
SkDebugf("%c", cE);
|
|
}
|
|
}
|
|
#endif // PathOpsTSectDebug_DEFINED
|