/* * 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 "include/core/SkString.h" #include "include/private/SkMutex.h" #include "src/pathops/SkIntersectionHelper.h" #include "src/pathops/SkOpCoincidence.h" #include "src/pathops/SkOpContour.h" #include "src/pathops/SkOpSegment.h" #include "tests/PathOpsDebug.h" #include "tests/PathOpsTSectDebug.h" bool PathOpsDebug::gJson; bool PathOpsDebug::gMarkJsonFlaky; bool PathOpsDebug::gOutFirst; bool PathOpsDebug::gCheckForDuplicateNames; bool PathOpsDebug::gOutputSVG; FILE* PathOpsDebug::gOut; 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 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 static void DumpID(int id) { SkDebugf("} "); if (id >= 0) { SkDebugf("id=%d", id); } SkDebugf("\n"); } void SkDConic::dump() const { dumpInner(); SkDebugf("},\n"); } void SkDConic::dumpID(int id) const { dumpInner(); DumpID(id); } void SkDConic::dumpInner() const { SkDebugf("{"); fPts.dumpInner(); SkDebugf("}}, %1.9gf", fWeight); } void SkDCubic::dump() const { this->dumpInner(); SkDebugf("}},\n"); } void SkDCubic::dumpID(int id) const { this->dumpInner(); SkDebugf("}"); DumpID(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 SkDCurve::dump() const { dumpID(-1); } void SkDCurve::dumpID(int id) const { #ifndef SK_RELEASE switch(fVerb) { case SkPath::kLine_Verb: fLine.dumpID(id); break; case SkPath::kQuad_Verb: fQuad.dumpID(id); break; case SkPath::kConic_Verb: fConic.dumpID(id); break; case SkPath::kCubic_Verb: fCubic.dumpID(id); break; default: SkASSERT(0); } #else fCubic.dumpID(id); #endif } void SkDLine::dump() const { this->dumpInner(); SkDebugf("}},\n"); } void SkDLine::dumpID(int id) const { this->dumpInner(); SkDebugf("}"); DumpID(id); } void SkDLine::dumpInner() const { SkDebugf("{{"); fPts[0].dump(); SkDebugf(", "); fPts[1].dump(); } 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("}"); DumpID(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* AngleAngle(const SkOpAngle* angle, int id) { return angle->debugAngle(id); } SkOpContour* AngleContour(SkOpAngle* angle, int id) { return angle->debugContour(id); } const SkOpPtT* AnglePtT(const SkOpAngle* angle, int id) { return angle->debugPtT(id); } const SkOpSegment* AngleSegment(const SkOpAngle* angle, int id) { return angle->debugSegment(id); } const SkOpSpanBase* AngleSpan(const SkOpAngle* angle, int id) { return angle->debugSpan(id); } const SkOpAngle* ContourAngle(SkOpContour* contour, int id) { return contour->debugAngle(id); } SkOpContour* ContourContour(SkOpContour* contour, int id) { return contour->debugContour(id); } const SkOpPtT* ContourPtT(SkOpContour* contour, int id) { return contour->debugPtT(id); } const SkOpSegment* ContourSegment(SkOpContour* contour, int id) { return contour->debugSegment(id); } const SkOpSpanBase* ContourSpan(SkOpContour* contour, int id) { return contour->debugSpan(id); } const SkOpAngle* CoincidenceAngle(SkOpCoincidence* coin, int id) { return coin->debugAngle(id); } SkOpContour* CoincidenceContour(SkOpCoincidence* coin, int id) { return coin->debugContour(id); } const SkOpPtT* CoincidencePtT(SkOpCoincidence* coin, int id) { return coin->debugPtT(id); } const SkOpSegment* CoincidenceSegment(SkOpCoincidence* coin, int id) { return coin->debugSegment(id); } const SkOpSpanBase* CoincidenceSpan(SkOpCoincidence* coin, int id) { return coin->debugSpan(id); } const SkOpAngle* PtTAngle(const SkOpPtT* ptT, int id) { return ptT->debugAngle(id); } SkOpContour* PtTContour(SkOpPtT* ptT, int id) { return ptT->debugContour(id); } const SkOpPtT* PtTPtT(const SkOpPtT* ptT, int id) { return ptT->debugPtT(id); } const SkOpSegment* PtTSegment(const SkOpPtT* ptT, int id) { return ptT->debugSegment(id); } const SkOpSpanBase* PtTSpan(const SkOpPtT* ptT, int id) { return ptT->debugSpan(id); } const SkOpAngle* SegmentAngle(const SkOpSegment* span, int id) { return span->debugAngle(id); } SkOpContour* SegmentContour(SkOpSegment* span, int id) { return span->debugContour(id); } const SkOpPtT* SegmentPtT(const SkOpSegment* span, int id) { return span->debugPtT(id); } const SkOpSegment* SegmentSegment(const SkOpSegment* span, int id) { return span->debugSegment(id); } const SkOpSpanBase* SegmentSpan(const SkOpSegment* span, int id) { return span->debugSpan(id); } const SkOpAngle* SpanAngle(const SkOpSpanBase* span, int id) { return span->debugAngle(id); } SkOpContour* SpanContour(SkOpSpanBase* span, int id) { return span->debugContour(id); } const SkOpPtT* SpanPtT(const SkOpSpanBase* span, int id) { return span->debugPtT(id); } const SkOpSegment* SpanSegment(const SkOpSpanBase* span, int id) { return span->debugSegment(id); } const SkOpSpanBase* SpanSpan(const SkOpSpanBase* span, int id) { return span->debugSpan(id); } #if DEBUG_COIN void SkPathOpsDebug::DumpCoinDict() { SkPathOpsDebug::gCoinSumChangedDict.dump("unused coin algorithm", false); SkPathOpsDebug::gCoinSumVisitedDict.dump("visited coin function", true); } void SkPathOpsDebug::CoinDict::dump(const char* str, bool visitCheck) const { int count = fDict.count(); for (int index = 0; index < count; ++index) { const auto& entry = fDict[index]; if (visitCheck || entry.fGlitchType == kUninitialized_Glitch) { SkDebugf("%s %s : line %d iteration %d", str, entry.fFunctionName, entry.fLineNumber, entry.fIteration); DumpGlitchType(entry.fGlitchType); SkDebugf("\n"); } } } #endif void SkOpContour::dumpContours() const { SkOpContour* contour = this->globalState()->contourHead(); do { contour->dump(); } while ((contour = contour->next())); } void SkOpContour::dumpContoursAll() const { SkOpContour* contour = this->globalState()->contourHead(); do { contour->dumpAll(); } while ((contour = contour->next())); } void SkOpContour::dumpContoursAngles() const { SkOpContour* contour = this->globalState()->contourHead(); do { contour->dumpAngles(); } while ((contour = contour->next())); } void SkOpContour::dumpContoursPts() const { SkOpContour* contour = this->globalState()->contourHead(); do { contour->dumpPts(); } while ((contour = contour->next())); } void SkOpContour::dumpContoursPt(int segmentID) const { SkOpContour* contour = this->globalState()->contourHead(); do { contour->dumpPt(segmentID); } while ((contour = contour->next())); } void SkOpContour::dumpContoursSegment(int segmentID) const { SkOpContour* contour = this->globalState()->contourHead(); do { contour->dumpSegment(segmentID); } while ((contour = contour->next())); } void SkOpContour::dumpContoursSpan(int spanID) const { SkOpContour* contour = this->globalState()->contourHead(); do { contour->dumpSpan(spanID); } while ((contour = contour->next())); } void SkOpContour::dumpContoursSpans() const { SkOpContour* contour = this->globalState()->contourHead(); do { contour->dumpSpans(); } while ((contour = contour->next())); } #ifdef SK_DEBUG const SkTSpan* DebugSpan(const SkTSect* sect, int id) { return sect->debugSpan(id); } const SkTSpan* DebugT(const SkTSect* sect, double t) { return sect->debugT(t); } #endif void Dump(const SkTSect* sect) { sect->dump(); } void DumpBoth(SkTSect* sect1, SkTSect* sect2) { sect1->dumpBoth(sect2); } void DumpBounded(SkTSect* sect1, int id) { sect1->dumpBounded(id); } void DumpBounds(SkTSect* sect1) { sect1->dumpBounds(); } void DumpCoin(SkTSect* sect1) { sect1->dumpCoin(); } void DumpCoinCurves(SkTSect* sect1) { sect1->dumpCoinCurves(); } void DumpCurves(const SkTSect* sect) { sect->dumpCurves(); } void Dump(const SkTSpan* span) { span->dump(); } void DumpAll(const SkTSpan* span) { span->dumpAll(); } void DumpBounded(const SkTSpan* span) { span->dumpBounded(0); } void DumpCoin(const SkTSpan* span) { span->dumpCoin(); } 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