formalize host debugging
Pathops writes files, anticipating upcoming crashes, and verifies the results against regions. Formalize these debugging methods so that they are more easily triggered by hosts outside of skia unit tests. TBR=reed@google.com GOLD_TRYBOT_URL= https://gold.skia.org/search?issue=2441763003 Review-Url: https://codereview.chromium.org/2441763003
This commit is contained in:
parent
826167111f
commit
1326068147
@ -8,10 +8,19 @@
|
||||
#include "SkMutex.h"
|
||||
#include "SkOpCoincidence.h"
|
||||
#include "SkOpContour.h"
|
||||
#include "SkOSFile.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkPathOpsDebug.h"
|
||||
#include "SkString.h"
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
bool SkPathOpsDebug::gDumpOp; // set to true to write op to file before a crash
|
||||
bool SkPathOpsDebug::gVerifyOp; // set to true to compare result against regions
|
||||
#endif
|
||||
|
||||
bool SkPathOpsDebug::gRunFail; // set to true to check for success on tests known to fail
|
||||
bool SkPathOpsDebug::gVeryVerbose; // set to true to run extensive checking tests
|
||||
|
||||
#undef FAIL_IF
|
||||
#define FAIL_IF(cond, coin) \
|
||||
do { if (cond) log->record(SkPathOpsDebug::kFail_Glitch, coin); } while (false)
|
||||
@ -27,10 +36,6 @@
|
||||
|
||||
class SkCoincidentSpans;
|
||||
|
||||
#if DEBUG_VALIDATE
|
||||
extern bool FLAGS_runFail;
|
||||
#endif
|
||||
|
||||
#if DEBUG_SORT
|
||||
int SkPathOpsDebug::gSortCountDefault = SK_MaxS32;
|
||||
int SkPathOpsDebug::gSortCount;
|
||||
@ -647,15 +652,9 @@ void SkOpGlobalState::debugResetLoopCounts() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
bool SkOpGlobalState::debugRunFail() const {
|
||||
#if DEBUG_VALIDATE
|
||||
return FLAGS_runFail;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
bool SkOpGlobalState::DebugRunFail() {
|
||||
return SkPathOpsDebug::gRunFail;
|
||||
}
|
||||
#endif
|
||||
|
||||
// this is const so it can be called by const methods that overwise don't alter state
|
||||
#if DEBUG_VALIDATE || DEBUG_COIN
|
||||
@ -1362,8 +1361,8 @@ void SkOpAngle::debugValidate() const {
|
||||
}
|
||||
next = next->fNext;
|
||||
} while (next && next != first);
|
||||
SkASSERT(wind == 0 || !FLAGS_runFail);
|
||||
SkASSERT(opp == 0 || !FLAGS_runFail);
|
||||
SkASSERT(wind == 0 || !SkPathOpsDebug::gRunFail);
|
||||
SkASSERT(opp == 0 || !SkPathOpsDebug::gRunFail);
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -1390,8 +1389,8 @@ void SkOpAngle::debugValidateNext() const {
|
||||
#ifdef SK_DEBUG
|
||||
void SkCoincidentSpans::debugStartCheck(const SkOpSpanBase* outer, const SkOpSpanBase* over,
|
||||
const SkOpGlobalState* debugState) const {
|
||||
SkASSERT(coinPtTEnd()->span() == over || !debugState->debugRunFail());
|
||||
SkASSERT(oppPtTEnd()->span() == outer || !debugState->debugRunFail());
|
||||
SkASSERT(coinPtTEnd()->span() == over || !SkOpGlobalState::DebugRunFail());
|
||||
SkASSERT(oppPtTEnd()->span() == outer || !SkOpGlobalState::DebugRunFail());
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -2906,3 +2905,203 @@ void SkPathOpsDebug::ShowOnePath(const SkPath& path, const char* name, bool incl
|
||||
iter.setPath(path);
|
||||
showPathContours(iter, name);
|
||||
}
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
#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);
|
||||
sk_sp<SkData> data(wStream.detachAsData());
|
||||
fprintf(file, "%.*s\n", (int) data->size(), (char*) data->data());
|
||||
}
|
||||
|
||||
static int dumpID = 0;
|
||||
|
||||
void SkPathOpsDebug::DumpOp(const SkPath& one, const SkPath& two, SkPathOp op,
|
||||
const char* testName) {
|
||||
FILE* file = sk_fopen("op_dump.txt", kWrite_SkFILE_Flag);
|
||||
DumpOp(file, one, two, op, testName);
|
||||
}
|
||||
|
||||
void SkPathOpsDebug::DumpOp(FILE* file, const SkPath& one, const SkPath& two, SkPathOp op,
|
||||
const char* testName) {
|
||||
const char* name = testName ? testName : "op";
|
||||
fprintf(file,
|
||||
"\nstatic void %s_%d(skiatest::Reporter* reporter, const char* filename) {\n",
|
||||
name, ++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\n");
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void SkPathOpsDebug::DumpSimplify(const SkPath& path, const char* testName) {
|
||||
FILE* file = sk_fopen("simplify_dump.txt", kWrite_SkFILE_Flag);
|
||||
DumpSimplify(file, path, testName);
|
||||
}
|
||||
|
||||
void SkPathOpsDebug::DumpSimplify(FILE* file, const SkPath& path, const char* testName) {
|
||||
const char* name = testName ? testName : "simplify";
|
||||
fprintf(file,
|
||||
"\nstatic void %s_%d(skiatest::Reporter* reporter, const char* filename) {\n",
|
||||
name, ++dumpID);
|
||||
fprintf(file, " SkPath path;\n");
|
||||
fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", path.getFillType());
|
||||
dump_path(file, path, false, true);
|
||||
fprintf(file, " testSimplify(reporter, path, filename);\n");
|
||||
fprintf(file, "}\n\n");
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
#include "SkBitmap.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkPaint.h"
|
||||
|
||||
const int bitWidth = 64;
|
||||
const int bitHeight = 64;
|
||||
|
||||
static void debug_scale_matrix(const SkPath& one, const SkPath* two, SkMatrix& scale) {
|
||||
SkRect larger = one.getBounds();
|
||||
if (two) {
|
||||
larger.join(two->getBounds());
|
||||
}
|
||||
SkScalar largerWidth = larger.width();
|
||||
if (largerWidth < 4) {
|
||||
largerWidth = 4;
|
||||
}
|
||||
SkScalar largerHeight = larger.height();
|
||||
if (largerHeight < 4) {
|
||||
largerHeight = 4;
|
||||
}
|
||||
SkScalar hScale = (bitWidth - 2) / largerWidth;
|
||||
SkScalar vScale = (bitHeight - 2) / largerHeight;
|
||||
scale.reset();
|
||||
scale.preScale(hScale, vScale);
|
||||
larger.fLeft *= hScale;
|
||||
larger.fRight *= hScale;
|
||||
larger.fTop *= vScale;
|
||||
larger.fBottom *= vScale;
|
||||
SkScalar dx = -16000 > larger.fLeft ? -16000 - larger.fLeft
|
||||
: 16000 < larger.fRight ? 16000 - larger.fRight : 0;
|
||||
SkScalar dy = -16000 > larger.fTop ? -16000 - larger.fTop
|
||||
: 16000 < larger.fBottom ? 16000 - larger.fBottom : 0;
|
||||
scale.preTranslate(dx, dy);
|
||||
}
|
||||
|
||||
static int debug_paths_draw_the_same(const SkPath& one, const SkPath& two, SkBitmap& bits) {
|
||||
if (bits.width() == 0) {
|
||||
bits.allocN32Pixels(bitWidth * 2, bitHeight);
|
||||
}
|
||||
SkCanvas canvas(bits);
|
||||
canvas.drawColor(SK_ColorWHITE);
|
||||
SkPaint paint;
|
||||
canvas.save();
|
||||
const SkRect& bounds1 = one.getBounds();
|
||||
canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
|
||||
canvas.drawPath(one, paint);
|
||||
canvas.restore();
|
||||
canvas.save();
|
||||
canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
|
||||
canvas.drawPath(two, paint);
|
||||
canvas.restore();
|
||||
int errors = 0;
|
||||
for (int y = 0; y < bitHeight - 1; ++y) {
|
||||
uint32_t* addr1 = bits.getAddr32(0, y);
|
||||
uint32_t* addr2 = bits.getAddr32(0, y + 1);
|
||||
uint32_t* addr3 = bits.getAddr32(bitWidth, y);
|
||||
uint32_t* addr4 = bits.getAddr32(bitWidth, y + 1);
|
||||
for (int x = 0; x < bitWidth - 1; ++x) {
|
||||
// count 2x2 blocks
|
||||
bool err = addr1[x] != addr3[x];
|
||||
if (err) {
|
||||
errors += addr1[x + 1] != addr3[x + 1]
|
||||
&& addr2[x] != addr4[x] && addr2[x + 1] != addr4[x + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
void SkPathOpsDebug::ReportOpFail(const SkPath& one, const SkPath& two, SkPathOp op) {
|
||||
SkDebugf("// Op did not expect failure\n");
|
||||
DumpOp(stderr, one, two, op, "opTest");
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
void SkPathOpsDebug::VerifyOp(const SkPath& one, const SkPath& two, SkPathOp op,
|
||||
const SkPath& result) {
|
||||
SkPath pathOut, scaledPathOut;
|
||||
SkRegion rgnA, rgnB, openClip, rgnOut;
|
||||
openClip.setRect(-16000, -16000, 16000, 16000);
|
||||
rgnA.setPath(one, openClip);
|
||||
rgnB.setPath(two, openClip);
|
||||
rgnOut.op(rgnA, rgnB, (SkRegion::Op) op);
|
||||
rgnOut.getBoundaryPath(&pathOut);
|
||||
SkMatrix scale;
|
||||
debug_scale_matrix(one, &two, scale);
|
||||
SkRegion scaledRgnA, scaledRgnB, scaledRgnOut;
|
||||
SkPath scaledA, scaledB;
|
||||
scaledA.addPath(one, scale);
|
||||
scaledA.setFillType(one.getFillType());
|
||||
scaledB.addPath(two, scale);
|
||||
scaledB.setFillType(two.getFillType());
|
||||
scaledRgnA.setPath(scaledA, openClip);
|
||||
scaledRgnB.setPath(scaledB, openClip);
|
||||
scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) op);
|
||||
scaledRgnOut.getBoundaryPath(&scaledPathOut);
|
||||
SkBitmap bitmap;
|
||||
SkPath scaledOut;
|
||||
scaledOut.addPath(result, scale);
|
||||
scaledOut.setFillType(result.getFillType());
|
||||
int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut, bitmap);
|
||||
const int MAX_ERRORS = 9;
|
||||
if (errors > MAX_ERRORS) {
|
||||
fprintf(stderr, "// Op did not expect errors=%d\n", errors);
|
||||
DumpOp(stderr, one, two, op, "opTest");
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
void SkPathOpsDebug::ReportSimplifyFail(const SkPath& path) {
|
||||
SkDebugf("// Simplify did not expect failure\n");
|
||||
DumpSimplify(stderr, path, "simplifyTest");
|
||||
fflush(stderr);
|
||||
}
|
||||
|
||||
void SkPathOpsDebug::VerifySimplify(const SkPath& path, const SkPath& result) {
|
||||
SkPath pathOut, scaledPathOut;
|
||||
SkRegion rgnA, openClip, rgnOut;
|
||||
openClip.setRect(-16000, -16000, 16000, 16000);
|
||||
rgnA.setPath(path, openClip);
|
||||
rgnOut.getBoundaryPath(&pathOut);
|
||||
SkMatrix scale;
|
||||
debug_scale_matrix(path, nullptr, scale);
|
||||
SkRegion scaledRgnA;
|
||||
SkPath scaledA;
|
||||
scaledA.addPath(path, scale);
|
||||
scaledA.setFillType(path.getFillType());
|
||||
scaledRgnA.setPath(scaledA, openClip);
|
||||
scaledRgnA.getBoundaryPath(&scaledPathOut);
|
||||
SkBitmap bitmap;
|
||||
SkPath scaledOut;
|
||||
scaledOut.addPath(result, scale);
|
||||
scaledOut.setFillType(result.getFillType());
|
||||
int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut, bitmap);
|
||||
const int MAX_ERRORS = 9;
|
||||
if (errors > MAX_ERRORS) {
|
||||
fprintf(stderr, "// Simplify did not expect errors=%d\n", errors);
|
||||
DumpSimplify(stderr, path, "simplifyTest");
|
||||
fflush(stderr);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
@ -371,6 +371,27 @@ public:
|
||||
static void DumpCoinDict();
|
||||
static void DumpGlitchType(GlitchType );
|
||||
#endif
|
||||
|
||||
static bool gRunFail;
|
||||
static bool gVeryVerbose;
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
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
|
||||
|
||||
};
|
||||
|
||||
struct SkDQuad;
|
||||
|
@ -198,44 +198,6 @@ static const bool gOutInverse[kReverseDifference_SkPathOp + 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);
|
||||
sk_sp<SkData> data(wStream.detachAsData());
|
||||
fprintf(file, "%.*s\n", (int) data->size(), (char*) 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
|
||||
|
||||
|
||||
#if DEBUG_T_SECT_LOOP_COUNT
|
||||
|
||||
#include "SkMutex.h"
|
||||
@ -261,8 +223,10 @@ bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result
|
||||
SkOpGlobalState globalState(contourList, &allocator
|
||||
SkDEBUGPARAMS(skipAssert) SkDEBUGPARAMS(testName));
|
||||
SkOpCoincidence coincidence(&globalState);
|
||||
#if DEBUGGING_PATHOPS_FROM_HOST
|
||||
dump_op(one, two, op);
|
||||
#ifdef SK_DEBUG
|
||||
if (SkPathOpsDebug::gDumpOp) {
|
||||
SkPathOpsDebug::DumpOp(one, two, op, testName);
|
||||
}
|
||||
#endif
|
||||
op = gOpInverse[op][one.isInverseFillType()][two.isInverseFillType()];
|
||||
SkPath::FillType fillType = gOutInverse[op][one.isInverseFillType()][two.isInverseFillType()]
|
||||
@ -351,122 +315,16 @@ bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result
|
||||
return true;
|
||||
}
|
||||
|
||||
#define DEBUG_VERIFY 0
|
||||
|
||||
#if DEBUG_VERIFY
|
||||
#include "SkBitmap.h"
|
||||
#include "SkCanvas.h"
|
||||
#include "SkPaint.h"
|
||||
|
||||
const int bitWidth = 64;
|
||||
const int bitHeight = 64;
|
||||
|
||||
static void debug_scale_matrix(const SkPath& one, const SkPath& two, SkMatrix& scale) {
|
||||
SkRect larger = one.getBounds();
|
||||
larger.join(two.getBounds());
|
||||
SkScalar largerWidth = larger.width();
|
||||
if (largerWidth < 4) {
|
||||
largerWidth = 4;
|
||||
}
|
||||
SkScalar largerHeight = larger.height();
|
||||
if (largerHeight < 4) {
|
||||
largerHeight = 4;
|
||||
}
|
||||
SkScalar hScale = (bitWidth - 2) / largerWidth;
|
||||
SkScalar vScale = (bitHeight - 2) / largerHeight;
|
||||
scale.reset();
|
||||
scale.preScale(hScale, vScale);
|
||||
larger.fLeft *= hScale;
|
||||
larger.fRight *= hScale;
|
||||
larger.fTop *= vScale;
|
||||
larger.fBottom *= vScale;
|
||||
SkScalar dx = -16000 > larger.fLeft ? -16000 - larger.fLeft
|
||||
: 16000 < larger.fRight ? 16000 - larger.fRight : 0;
|
||||
SkScalar dy = -16000 > larger.fTop ? -16000 - larger.fTop
|
||||
: 16000 < larger.fBottom ? 16000 - larger.fBottom : 0;
|
||||
scale.preTranslate(dx, dy);
|
||||
}
|
||||
|
||||
static int debug_paths_draw_the_same(const SkPath& one, const SkPath& two, SkBitmap& bits) {
|
||||
if (bits.width() == 0) {
|
||||
bits.allocN32Pixels(bitWidth * 2, bitHeight);
|
||||
}
|
||||
SkCanvas canvas(bits);
|
||||
canvas.drawColor(SK_ColorWHITE);
|
||||
SkPaint paint;
|
||||
canvas.save();
|
||||
const SkRect& bounds1 = one.getBounds();
|
||||
canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1);
|
||||
canvas.drawPath(one, paint);
|
||||
canvas.restore();
|
||||
canvas.save();
|
||||
canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1);
|
||||
canvas.drawPath(two, paint);
|
||||
canvas.restore();
|
||||
int errors = 0;
|
||||
for (int y = 0; y < bitHeight - 1; ++y) {
|
||||
uint32_t* addr1 = bits.getAddr32(0, y);
|
||||
uint32_t* addr2 = bits.getAddr32(0, y + 1);
|
||||
uint32_t* addr3 = bits.getAddr32(bitWidth, y);
|
||||
uint32_t* addr4 = bits.getAddr32(bitWidth, y + 1);
|
||||
for (int x = 0; x < bitWidth - 1; ++x) {
|
||||
// count 2x2 blocks
|
||||
bool err = addr1[x] != addr3[x];
|
||||
if (err) {
|
||||
errors += addr1[x + 1] != addr3[x + 1]
|
||||
&& addr2[x] != addr4[x] && addr2[x + 1] != addr4[x + 1];
|
||||
}
|
||||
}
|
||||
}
|
||||
return errors;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
bool Op(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result) {
|
||||
#if DEBUG_VERIFY
|
||||
if (!OpDebug(one, two, op, result SkDEBUGPARAMS(nullptr))) {
|
||||
SkDebugf("%s did not expect failure\none: fill=%d\n", __FUNCTION__, one.getFillType());
|
||||
one.dumpHex();
|
||||
SkDebugf("two: fill=%d\n", two.getFillType());
|
||||
two.dumpHex();
|
||||
SkASSERT(0);
|
||||
return false;
|
||||
#ifdef SK_DEBUG
|
||||
if (SkPathOpsDebug::gVerifyOp) {
|
||||
if (!OpDebug(one, two, op, result SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr))) {
|
||||
SkPathOpsDebug::ReportOpFail(one, two, op);
|
||||
return false;
|
||||
}
|
||||
SkPathOpsDebug::VerifyOp(one, two, op, *result);
|
||||
return true;
|
||||
}
|
||||
SkPath pathOut, scaledPathOut;
|
||||
SkRegion rgnA, rgnB, openClip, rgnOut;
|
||||
openClip.setRect(-16000, -16000, 16000, 16000);
|
||||
rgnA.setPath(one, openClip);
|
||||
rgnB.setPath(two, openClip);
|
||||
rgnOut.op(rgnA, rgnB, (SkRegion::Op) op);
|
||||
rgnOut.getBoundaryPath(&pathOut);
|
||||
SkMatrix scale;
|
||||
debug_scale_matrix(one, two, scale);
|
||||
SkRegion scaledRgnA, scaledRgnB, scaledRgnOut;
|
||||
SkPath scaledA, scaledB;
|
||||
scaledA.addPath(one, scale);
|
||||
scaledA.setFillType(one.getFillType());
|
||||
scaledB.addPath(two, scale);
|
||||
scaledB.setFillType(two.getFillType());
|
||||
scaledRgnA.setPath(scaledA, openClip);
|
||||
scaledRgnB.setPath(scaledB, openClip);
|
||||
scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) op);
|
||||
scaledRgnOut.getBoundaryPath(&scaledPathOut);
|
||||
SkBitmap bitmap;
|
||||
SkPath scaledOut;
|
||||
scaledOut.addPath(*result, scale);
|
||||
scaledOut.setFillType(result->getFillType());
|
||||
int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut, bitmap);
|
||||
const int MAX_ERRORS = 9;
|
||||
if (errors > MAX_ERRORS) {
|
||||
SkDebugf("%s did not expect failure\none: fill=%d\n", __FUNCTION__, one.getFillType());
|
||||
one.dumpHex();
|
||||
SkDebugf("two: fill=%d\n", two.getFillType());
|
||||
two.dumpHex();
|
||||
SkASSERT(0);
|
||||
}
|
||||
return true;
|
||||
#else
|
||||
return OpDebug(one, two, op, result SkDEBUGPARAMS(true) SkDEBUGPARAMS(nullptr));
|
||||
#endif
|
||||
return OpDebug(one, two, op, result SkDEBUGPARAMS(true) SkDEBUGPARAMS(nullptr));
|
||||
}
|
||||
|
@ -158,6 +158,11 @@ bool SimplifyDebug(const SkPath& path, SkPath* result
|
||||
SkOpGlobalState globalState(contourList, &allocator
|
||||
SkDEBUGPARAMS(skipAssert) SkDEBUGPARAMS(testName));
|
||||
SkOpCoincidence coincidence(&globalState);
|
||||
#ifdef SK_DEBUG
|
||||
if (SkPathOpsDebug::gDumpOp) {
|
||||
SkPathOpsDebug::DumpSimplify(path, testName);
|
||||
}
|
||||
#endif
|
||||
SkScalar scaleFactor = ScaleFactor(path);
|
||||
SkPath scaledPath;
|
||||
const SkPath* workingPath;
|
||||
@ -218,5 +223,15 @@ bool SimplifyDebug(const SkPath& path, SkPath* result
|
||||
}
|
||||
|
||||
bool Simplify(const SkPath& path, SkPath* result) {
|
||||
#ifdef SK_DEBUG
|
||||
if (SkPathOpsDebug::gVerifyOp) {
|
||||
if (!SimplifyDebug(path, result SkDEBUGPARAMS(false) SkDEBUGPARAMS(nullptr))) {
|
||||
SkPathOpsDebug::ReportSimplifyFail(path);
|
||||
return false;
|
||||
}
|
||||
SkPathOpsDebug::VerifySimplify(path, *result);
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
return SimplifyDebug(path, result SkDEBUGPARAMS(true) SkDEBUGPARAMS(nullptr));
|
||||
}
|
||||
|
@ -75,7 +75,11 @@ public:
|
||||
const SkOpCoincidence* debugCoincidence() const;
|
||||
SkOpContour* debugContour(int id) const;
|
||||
const class SkOpPtT* debugPtT(int id) const;
|
||||
bool debugRunFail() const;
|
||||
#endif
|
||||
|
||||
static bool DebugRunFail();
|
||||
|
||||
#ifdef SK_DEBUG
|
||||
const class SkOpSegment* debugSegment(int id) const;
|
||||
bool debugSkipAssert() const { return fDebugSkipAssert; }
|
||||
const class SkOpSpanBase* debugSpan(int id) const;
|
||||
|
@ -88,6 +88,8 @@ static void setupOne(skiatest::Reporter* reporter, int col, int row, int rot, in
|
||||
testOne(reporter, set);
|
||||
}
|
||||
|
||||
#include "SkCommandLineFlags.h"
|
||||
|
||||
DEFINE_int32(processOffset, 0, "Offset the test by this value. This permits multiple processes "
|
||||
"to exercise the same test in parallel with different test values.");
|
||||
DEFINE_int32(processCount, 1, "Test iteration count. This permits multiple "
|
||||
|
@ -13,8 +13,6 @@
|
||||
#include "SkOpSegment.h"
|
||||
#include "SkString.h"
|
||||
|
||||
extern bool FLAGS_runFail;
|
||||
|
||||
inline void DebugDumpDouble(double x) {
|
||||
if (x == floor(x)) {
|
||||
SkDebugf("%.0f", x);
|
||||
|
@ -32,9 +32,6 @@ bool SimplifyDebug(const SkPath& one, SkPath* result
|
||||
|
||||
__SK_FORCE_IMAGE_DECODER_LINKING;
|
||||
|
||||
DEFINE_bool2(runFail, f, false, "run tests known to fail.");
|
||||
DEFINE_bool2(runBinary, f, false, "run tests known to fail binary sect.");
|
||||
|
||||
static const char marker[] =
|
||||
"</div>\n"
|
||||
"\n"
|
||||
|
@ -8,15 +8,11 @@
|
||||
#define PathOpsExtendedTest_DEFINED
|
||||
|
||||
#include "SkBitmap.h"
|
||||
#include "SkCommandLineFlags.h"
|
||||
#include "SkPath.h"
|
||||
#include "SkPathOpsTypes.h"
|
||||
#include "SkStream.h"
|
||||
#include "Test.h"
|
||||
|
||||
DECLARE_bool(runFail);
|
||||
DECLARE_bool(runBinary);
|
||||
|
||||
struct PathOpsThreadState;
|
||||
|
||||
struct TestDesc {
|
||||
|
@ -2093,7 +2093,7 @@ path.close();
|
||||
|
||||
SkPath path2(path);
|
||||
// DEBUG_UNDER_DEVELOPMENT fuzz763_1026368 disable expectation check for now
|
||||
testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, !FLAGS_runFail);
|
||||
testPathOpCheck(reporter, path1, path2, (SkPathOp) 2, filename, !SkOpGlobalState::DebugRunFail());
|
||||
}
|
||||
|
||||
static void fuzz763_5485218(skiatest::Reporter* reporter, const char* filename) {
|
||||
|
@ -473,7 +473,8 @@ static void issue3651_1a(skiatest::Reporter* reporter, const char* filename) {
|
||||
SkPath path = path1_a();
|
||||
SkPath pathB = path2_a();
|
||||
// DEBUG_UNDER_DEVELOPMENT issue3651_1a disable expectation check for now
|
||||
testPathOpCheck(reporter, path, pathB, SkPathOp::kUnion_SkPathOp, filename, !FLAGS_runFail);
|
||||
testPathOpCheck(reporter, path, pathB, SkPathOp::kUnion_SkPathOp, filename,
|
||||
!SkOpGlobalState::DebugRunFail());
|
||||
}
|
||||
|
||||
static SkPath path3() {
|
||||
@ -1204,7 +1205,8 @@ static void issue3651_1(skiatest::Reporter* reporter, const char* filename) {
|
||||
SkPath path = path1();
|
||||
SkPath pathB = path2();
|
||||
// DEBUG_UNDER_DEVELOPMENT issue3651_1 disable expectation check for now
|
||||
testPathOpCheck(reporter, path, pathB, SkPathOp::kUnion_SkPathOp, filename, !FLAGS_runFail);
|
||||
testPathOpCheck(reporter, path, pathB, SkPathOp::kUnion_SkPathOp, filename,
|
||||
!SkOpGlobalState::DebugRunFail());
|
||||
}
|
||||
|
||||
static void issue3651_2(skiatest::Reporter* reporter, const char* filename) {
|
||||
|
@ -524,10 +524,8 @@ DEF_TEST(PathOpsQuadIntersection, reporter) {
|
||||
if (false) QuadraticIntersection_IntersectionFinder();
|
||||
}
|
||||
|
||||
#include "SkCommonFlags.h"
|
||||
|
||||
DEF_TEST(PathOpsQuadBinaryProfile, reporter) {
|
||||
if (!FLAGS_veryVerbose) {
|
||||
if (!SkPathOpsDebug::gVeryVerbose) {
|
||||
return;
|
||||
}
|
||||
SkIntersections intersections;
|
||||
|
@ -27,7 +27,11 @@
|
||||
using namespace skiatest;
|
||||
using namespace sk_gpu_test;
|
||||
|
||||
DEFINE_bool2(dumpOp, d, false, "dump the pathOps to a file to recover mid-crash.");
|
||||
DEFINE_bool2(extendedTest, x, false, "run extended tests for pathOps.");
|
||||
DEFINE_bool2(runFail, f, false, "check for success on tests known to fail.");
|
||||
DEFINE_bool2(verifyOp, y, false, "compare the pathOps result against a region.");
|
||||
|
||||
#if DEBUG_COIN
|
||||
DEFINE_bool2(coinTest, c, false, "detect unused coincidence algorithms.");
|
||||
#endif
|
||||
@ -133,6 +137,12 @@ static bool should_run(const char* testName, bool isGPUTest) {
|
||||
|
||||
int test_main();
|
||||
int test_main() {
|
||||
#ifdef SK_DEBUG
|
||||
SkPathOpsDebug::gDumpOp = FLAGS_dumpOp;
|
||||
SkPathOpsDebug::gVerifyOp = FLAGS_verifyOp;
|
||||
#endif
|
||||
SkPathOpsDebug::gRunFail = FLAGS_runFail;
|
||||
SkPathOpsDebug::gVeryVerbose = FLAGS_veryVerbose;
|
||||
SetupCrashHandler();
|
||||
|
||||
SkAutoGraphics ag;
|
||||
@ -153,6 +163,31 @@ int test_main() {
|
||||
if (!resourcePath.isEmpty()) {
|
||||
header.appendf(" --resourcePath %s", resourcePath.c_str());
|
||||
}
|
||||
#if DEBUG_COIN
|
||||
if (FLAGS_coinTest) {
|
||||
header.appendf(" -c");
|
||||
}
|
||||
#endif
|
||||
if (FLAGS_dumpOp) {
|
||||
header.appendf(" -d");
|
||||
}
|
||||
#if SK_DEBUG
|
||||
if (FLAGS_runFail) {
|
||||
header.appendf(" -f");
|
||||
}
|
||||
#endif
|
||||
if (FLAGS_verbose) {
|
||||
header.appendf(" -v");
|
||||
}
|
||||
if (FLAGS_veryVerbose) {
|
||||
header.appendf(" -V");
|
||||
}
|
||||
if (FLAGS_extendedTest) {
|
||||
header.appendf(" -x");
|
||||
}
|
||||
if (FLAGS_verifyOp) {
|
||||
header.appendf(" -y");
|
||||
}
|
||||
#ifdef SK_DEBUG
|
||||
header.append(" SK_DEBUG");
|
||||
#else
|
||||
|
Loading…
Reference in New Issue
Block a user