| Index: src/pathops/SkPathOpsOp.cpp
|
| diff --git a/src/pathops/SkPathOpsOp.cpp b/src/pathops/SkPathOpsOp.cpp
|
| index be7fae7a8f48a84119e1d4da845d0d97c83701bb..b5e00908fdb858b7457d752e6d0bcf7205d0904c 100644
|
| --- a/src/pathops/SkPathOpsOp.cpp
|
| +++ b/src/pathops/SkPathOpsOp.cpp
|
| @@ -222,6 +222,23 @@ static void dump_op(const SkPath& one, const SkPath& two, SkPathOp op) {
|
| }
|
| #endif
|
|
|
| +
|
| +#if DEBUG_T_SECT_LOOP_COUNT
|
| +
|
| +#include "SkMutex.h"
|
| +
|
| +SK_DECLARE_STATIC_MUTEX(debugWorstLoop);
|
| +
|
| +SkOpGlobalState debugWorstState(nullptr, nullptr SkDEBUGPARAMS(nullptr));
|
| +
|
| +void ReportPathOpsDebugging() {
|
| + debugWorstState.debugLoopReport();
|
| +}
|
| +
|
| +extern void (*gVerboseFinalize)();
|
| +
|
| +#endif
|
| +
|
| bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result,
|
| bool expectSuccess SkDEBUGPARAMS(const char* testName)) {
|
| SkChunkAlloc allocator(4096); // FIXME: add a constant expression here, tune
|
| @@ -263,7 +280,7 @@ bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result,
|
| return false;
|
| }
|
| #if DEBUG_DUMP_SEGMENTS
|
| - contour.dumpSegments(op);
|
| + contourList->dumpSegments("seg", op);
|
| #endif
|
|
|
| const int xorOpMask = builder.xorMask();
|
| @@ -287,6 +304,9 @@ bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result,
|
| if (!HandleCoincidence(contourList, &coincidence, &allocator)) {
|
| return false;
|
| }
|
| +#if DEBUG_ALIGNMENT
|
| + contourList->dumpSegments("aligned");
|
| +#endif
|
| // construct closed contours
|
| result->reset();
|
| result->setFillType(fillType);
|
| @@ -300,9 +320,134 @@ bool OpDebug(const SkPath& one, const SkPath& two, SkPathOp op, SkPath* result,
|
| *result = *assembled.nativePath();
|
| result->setFillType(fillType);
|
| }
|
| +#if DEBUG_T_SECT_LOOP_COUNT
|
| + {
|
| + SkAutoMutexAcquire autoM(debugWorstLoop);
|
| + if (!gVerboseFinalize) {
|
| + gVerboseFinalize = &ReportPathOpsDebugging;
|
| + }
|
| + debugWorstState.debugDoYourWorst(&globalState);
|
| + }
|
| +#endif
|
| 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, true 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;
|
| + }
|
| + 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, true SkDEBUGPARAMS(nullptr));
|
| +#endif
|
| }
|
|
|