/* * Copyright 2014 Google Inc. * * Use of this source code is governed by a BSD-style license that can be * found in the LICENSE file. */ #include "PathOpsTSectDebug.h" #include "SkOpCoincidence.h" #include "SkOpContour.h" #include "SkIntersectionHelper.h" #include "SkOpSegment.h" #include "SkString.h" inline void DebugDumpDouble(double x) { if (x == floor(x)) { SkDebugf("%.0f", x); } else { SkDebugf("%1.19g", x); } } inline void DebugDumpFloat(float x) { if (x == floorf(x)) { SkDebugf("%.0f", x); } else { SkDebugf("%1.9gf", x); } } inline void DebugDumpHexFloat(float x) { SkDebugf("SkBits2Float(0x%08x)", SkFloat2Bits(x)); } #if DEBUG_SHOW_TEST_NAME static void output_scalar(SkScalar num) { if (num == (int) num) { SkDebugf("%d", (int) num); } else { SkString str; str.printf("%1.9g", num); int width = (int) str.size(); const char* cStr = str.c_str(); while (cStr[width - 1] == '0') { --width; } str.resize(width); SkDebugf("%sf", str.c_str()); } } static void output_points(const SkPoint* pts, int count) { for (int index = 0; index < count; ++index) { output_scalar(pts[index].fX); SkDebugf(", "); output_scalar(pts[index].fY); if (index + 1 < count) { SkDebugf(", "); } } } static void showPathContours(SkPath::RawIter& iter, const char* pathName) { uint8_t verb; SkPoint pts[4]; while ((verb = iter.next(pts)) != SkPath::kDone_Verb) { switch (verb) { case SkPath::kMove_Verb: SkDebugf(" %s.moveTo(", pathName); output_points(&pts[0], 1); SkDebugf(");\n"); continue; case SkPath::kLine_Verb: SkDebugf(" %s.lineTo(", pathName); output_points(&pts[1], 1); SkDebugf(");\n"); break; case SkPath::kQuad_Verb: SkDebugf(" %s.quadTo(", pathName); output_points(&pts[1], 2); SkDebugf(");\n"); break; case SkPath::kConic_Verb: SkDebugf(" %s.conicTo(", pathName); output_points(&pts[1], 2); SkDebugf(", %1.9gf);\n", iter.conicWeight()); break; case SkPath::kCubic_Verb: SkDebugf(" %s.cubicTo(", pathName); output_points(&pts[1], 3); SkDebugf(");\n"); break; case SkPath::kClose_Verb: SkDebugf(" %s.close();\n", pathName); break; default: SkDEBUGFAIL("bad verb"); return; } } } static const char* gFillTypeStr[] = { "kWinding_FillType", "kEvenOdd_FillType", "kInverseWinding_FillType", "kInverseEvenOdd_FillType" }; void SkPathOpsDebug::ShowOnePath(const SkPath& path, const char* name, bool includeDeclaration) { SkPath::RawIter iter(path); #define SUPPORT_RECT_CONTOUR_DETECTION 0 #if SUPPORT_RECT_CONTOUR_DETECTION int rectCount = path.isRectContours() ? path.rectContours(NULL, NULL) : 0; if (rectCount > 0) { SkTDArray rects; SkTDArray directions; rects.setCount(rectCount); directions.setCount(rectCount); path.rectContours(rects.begin(), directions.begin()); for (int contour = 0; contour < rectCount; ++contour) { const SkRect& rect = rects[contour]; SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLeft, rect.fTop, rect.fRight, rect.fBottom, directions[contour] == SkPath::kCCW_Direction ? "SkPath::kCCW_Direction" : "SkPath::kCW_Direction"); } return; } #endif SkPath::FillType fillType = path.getFillType(); SkASSERT(fillType >= SkPath::kWinding_FillType && fillType <= SkPath::kInverseEvenOdd_FillType); if (includeDeclaration) { SkDebugf(" SkPath %s;\n", name); } SkDebugf(" %s.setFillType(SkPath::%s);\n", name, gFillTypeStr[fillType]); iter.setPath(path); showPathContours(iter, name); } static void show_function_header(const char* functionName) { SkDebugf("\nstatic void %s(skiatest::Reporter* reporter, const char* filename) {\n", functionName); if (strcmp("skphealth_com76", functionName) == 0) { SkDebugf("found it\n"); } } static const char* gOpStrs[] = { "kDifference_SkPathOp", "kIntersect_SkPathOp", "kUnion_SkPathOp", "kXor_PathOp", "kReverseDifference_SkPathOp", }; static void show_op(SkPathOp op, const char* pathOne, const char* pathTwo) { SkDebugf(" testPathOp(reporter, %s, %s, %s, filename);\n", pathOne, pathTwo, gOpStrs[op]); SkDebugf("}\n"); } SK_DECLARE_STATIC_MUTEX(gTestMutex); void SkPathOpsDebug::ShowPath(const SkPath& a, const SkPath& b, SkPathOp shapeOp, const char* testName) { SkAutoMutexAcquire ac(gTestMutex); show_function_header(testName); ShowOnePath(a, "path", true); ShowOnePath(b, "pathB", true); show_op(shapeOp, "path", "pathB"); } #endif // if not defined by PathOpsDebug.cpp ... #if !defined SK_DEBUG && FORCE_RELEASE bool SkPathOpsDebug::ValidWind(int wind) { return wind > SK_MinS32 + 0xFFFF && wind < SK_MaxS32 - 0xFFFF; } void SkPathOpsDebug::WindingPrintf(int wind) { if (wind == SK_MinS32) { SkDebugf("?"); } else { SkDebugf("%d", wind); } } #endif void SkDCubic::dump() const { dumpInner(); SkDebugf("}},\n"); } void SkDCubic::dumpID(int id) const { dumpInner(); SkDebugf("}} id=%d\n", id); } static inline bool double_is_NaN(double x) { return x != x; } void SkDCubic::dumpInner() const { SkDebugf("{{"); int index = 0; do { if (index != 0) { if (double_is_NaN(fPts[index].fX) && double_is_NaN(fPts[index].fY)) { return; } SkDebugf(", "); } fPts[index].dump(); } while (++index < 3); if (double_is_NaN(fPts[index].fX) && double_is_NaN(fPts[index].fY)) { return; } SkDebugf(", "); fPts[index].dump(); } void SkDLine::dump() const { SkDebugf("{{"); fPts[0].dump(); SkDebugf(", "); fPts[1].dump(); SkDebugf("}},\n"); } void SkDPoint::dump() const { SkDebugf("{"); DebugDumpDouble(fX); SkDebugf(", "); DebugDumpDouble(fY); SkDebugf("}"); } void SkDPoint::Dump(const SkPoint& pt) { SkDebugf("{"); DebugDumpFloat(pt.fX); SkDebugf(", "); DebugDumpFloat(pt.fY); SkDebugf("}"); } void SkDPoint::DumpHex(const SkPoint& pt) { SkDebugf("{"); DebugDumpHexFloat(pt.fX); SkDebugf(", "); DebugDumpHexFloat(pt.fY); SkDebugf("}"); } void SkDQuad::dump() const { dumpInner(); SkDebugf("}},\n"); } void SkDQuad::dumpID(int id) const { dumpInner(); SkDebugf("}} id=%d\n", id); } void SkDQuad::dumpInner() const { SkDebugf("{{"); int index = 0; do { fPts[index].dump(); SkDebugf(", "); } while (++index < 2); fPts[index].dump(); } void SkIntersections::dump() const { SkDebugf("used=%d of %d", fUsed, fMax); for (int index = 0; index < fUsed; ++index) { SkDebugf(" t=(%s%1.9g,%s%1.9g) pt=(%1.9g,%1.9g)", fIsCoincident[0] & (1 << index) ? "*" : "", fT[0][index], fIsCoincident[1] & (1 << index) ? "*" : "", fT[1][index], fPt[index].fX, fPt[index].fY); if (index < 2 && fNearlySame[index]) { SkDebugf(" pt2=(%1.9g,%1.9g)",fPt2[index].fX, fPt2[index].fY); } } SkDebugf("\n"); } const SkOpAngle* SkPathOpsDebug::DebugAngleAngle(const SkOpAngle* angle, int id) { return angle->debugAngle(id); } SkOpContour* SkPathOpsDebug::DebugAngleContour(SkOpAngle* angle, int id) { return angle->debugContour(id); } const SkOpPtT* SkPathOpsDebug::DebugAnglePtT(const SkOpAngle* angle, int id) { return angle->debugPtT(id); } const SkOpSegment* SkPathOpsDebug::DebugAngleSegment(const SkOpAngle* angle, int id) { return angle->debugSegment(id); } const SkOpSpanBase* SkPathOpsDebug::DebugAngleSpan(const SkOpAngle* angle, int id) { return angle->debugSpan(id); } const SkOpAngle* SkPathOpsDebug::DebugContourAngle(SkOpContour* contour, int id) { return contour->debugAngle(id); } SkOpContour* SkPathOpsDebug::DebugContourContour(SkOpContour* contour, int id) { return contour->debugContour(id); } const SkOpPtT* SkPathOpsDebug::DebugContourPtT(SkOpContour* contour, int id) { return contour->debugPtT(id); } const SkOpSegment* SkPathOpsDebug::DebugContourSegment(SkOpContour* contour, int id) { return contour->debugSegment(id); } const SkOpSpanBase* SkPathOpsDebug::DebugContourSpan(SkOpContour* contour, int id) { return contour->debugSpan(id); } const SkOpAngle* SkPathOpsDebug::DebugPtTAngle(const SkOpPtT* ptT, int id) { return ptT->debugAngle(id); } SkOpContour* SkPathOpsDebug::DebugPtTContour(SkOpPtT* ptT, int id) { return ptT->debugContour(id); } const SkOpPtT* SkPathOpsDebug::DebugPtTPtT(const SkOpPtT* ptT, int id) { return ptT->debugPtT(id); } const SkOpSegment* SkPathOpsDebug::DebugPtTSegment(const SkOpPtT* ptT, int id) { return ptT->debugSegment(id); } const SkOpSpanBase* SkPathOpsDebug::DebugPtTSpan(const SkOpPtT* ptT, int id) { return ptT->debugSpan(id); } const SkOpAngle* SkPathOpsDebug::DebugSegmentAngle(const SkOpSegment* span, int id) { return span->debugAngle(id); } SkOpContour* SkPathOpsDebug::DebugSegmentContour(SkOpSegment* span, int id) { return span->debugContour(id); } const SkOpPtT* SkPathOpsDebug::DebugSegmentPtT(const SkOpSegment* span, int id) { return span->debugPtT(id); } const SkOpSegment* SkPathOpsDebug::DebugSegmentSegment(const SkOpSegment* span, int id) { return span->debugSegment(id); } const SkOpSpanBase* SkPathOpsDebug::DebugSegmentSpan(const SkOpSegment* span, int id) { return span->debugSpan(id); } const SkOpAngle* SkPathOpsDebug::DebugSpanAngle(const SkOpSpanBase* span, int id) { return span->debugAngle(id); } SkOpContour* SkPathOpsDebug::DebugSpanContour(SkOpSpanBase* span, int id) { return span->debugContour(id); } const SkOpPtT* SkPathOpsDebug::DebugSpanPtT(const SkOpSpanBase* span, int id) { return span->debugPtT(id); } const SkOpSegment* SkPathOpsDebug::DebugSpanSegment(const SkOpSpanBase* span, int id) { return span->debugSegment(id); } const SkOpSpanBase* SkPathOpsDebug::DebugSpanSpan(const SkOpSpanBase* span, int id) { return span->debugSpan(id); } void SkPathOpsDebug::DumpContours(SkTDArray* contours) { int count = contours->count(); for (int index = 0; index < count; ++index) { (*contours)[index]->dump(); } } void SkPathOpsDebug::DumpContoursAll(SkTDArray* contours) { int count = contours->count(); for (int index = 0; index < count; ++index) { (*contours)[index]->dumpAll(); } } void SkPathOpsDebug::DumpContoursAngles(const SkTDArray* contours) { int count = contours->count(); for (int index = 0; index < count; ++index) { (*contours)[index]->dumpAngles(); } } void SkPathOpsDebug::DumpContoursPts(const SkTDArray* contours) { int count = contours->count(); for (int index = 0; index < count; ++index) { (*contours)[index]->dumpPts(); } } void SkPathOpsDebug::DumpContoursPt(const SkTDArray* contours, int segmentID) { int count = contours->count(); for (int index = 0; index < count; ++index) { (*contours)[index]->dumpPt(segmentID); } } void SkPathOpsDebug::DumpContoursSegment(const SkTDArray* contours, int segmentID) { if (contours->count()) { (*contours)[0]->dumpSegment(segmentID); } } void SkPathOpsDebug::DumpContoursSpan(const SkTDArray* contours, int spanID) { if (contours->count()) { (*contours)[0]->dumpSpan(spanID); } } void SkPathOpsDebug::DumpContoursSpans(const SkTDArray* contours) { int count = contours->count(); for (int index = 0; index < count; ++index) { (*contours)[index]->dumpSpans(); } } const SkTSpan* DebugSpan(const SkTSect* sect, int id) { return sect->debugSpan(id); } const SkTSpan* DebugSpan(const SkTSect* sect, int id) { return sect->debugSpan(id); } const SkTSpan* DebugT(const SkTSect* sect, double t) { return sect->debugT(t); } const SkTSpan* DebugT(const SkTSect* sect, double t) { return sect->debugT(t); } const SkTSpan* DebugSpan(const SkTSpan* span, int id) { return span->debugSpan(id); } const SkTSpan* DebugSpan(const SkTSpan* span, int id) { return span->debugSpan(id); } const SkTSpan* DebugT(const SkTSpan* span, double t) { return span->debugT(t); } const SkTSpan* DebugT(const SkTSpan* span, double t) { return span->debugT(t); } void Dump(const SkTSect* sect) { sect->dump(); } void Dump(const SkTSect* sect) { sect->dump(); } void Dump(const SkTSpan* span) { span->dump(); } void Dump(const SkTSpan* span) { span->dump(); } void DumpBoth(SkTSect* sect1, SkTSect* sect2) { sect1->dumpBoth(sect2); } void DumpBoth(SkTSect* sect1, SkTSect* sect2) { sect1->dumpBoth(sect2); } void DumpCoin(SkTSect* sect1) { sect1->dumpCoin(); } void DumpCoin(SkTSect* sect1) { sect1->dumpCoin(); } void DumpCoinCurves(SkTSect* sect1) { sect1->dumpCoinCurves(); } void DumpCoinCurves(SkTSect* sect1) { sect1->dumpCoinCurves(); } void DumpCurves(const SkTSect* sect) { sect->dumpCurves(); } void DumpCurves(const SkTSect* sect) { sect->dumpCurves(); } static void dumpTestCase(const SkDQuad& quad1, const SkDQuad& quad2, int testNo) { SkDebugf("\n
\n", testNo); quad1.dumpInner(); SkDebugf("}}, "); quad2.dump(); SkDebugf("
\n\n"); } static void dumpTestTrailer() { SkDebugf("\n\n