/* * 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<div id=\"quad%d\">\n", testNo); quad1.dumpInner(); SkDebugf("}}, "); quad2.dump(); SkDebugf("</div>\n\n"); } static void dumpTestTrailer() { SkDebugf("</div>\n\n<script type=\"text/javascript\">\n\n"); SkDebugf(" var testDivs = [\n"); } static void dumpTestList(int testNo, double min) { SkDebugf(" quad%d,", testNo); if (min > 0) { SkDebugf(" // %1.9g", min); } SkDebugf("\n"); } void DumpQ(const SkDQuad& quad1, const SkDQuad& quad2, int testNo) { SkDebugf("\n"); dumpTestCase(quad1, quad2, testNo); dumpTestTrailer(); dumpTestList(testNo, 0); SkDebugf("\n"); } void DumpT(const SkDQuad& quad, double t) { SkDLine line = {{quad.ptAtT(t), quad[0]}}; line.dump(); } const SkOpAngle* SkOpAngle::debugAngle(int id) const { return this->segment()->debugAngle(id); } const SkOpCoincidence* SkOpAngle::debugCoincidence() const { return this->segment()->debugCoincidence(); } SkOpContour* SkOpAngle::debugContour(int id) const { return this->segment()->debugContour(id); } const SkOpPtT* SkOpAngle::debugPtT(int id) const { return this->segment()->debugPtT(id); } const SkOpSegment* SkOpAngle::debugSegment(int id) const { return this->segment()->debugSegment(id); } int SkOpAngle::debugSign() const { SkASSERT(fStart->t() != fEnd->t()); return fStart->t() < fEnd->t() ? -1 : 1; } const SkOpSpanBase* SkOpAngle::debugSpan(int id) const { return this->segment()->debugSpan(id); } void SkOpAngle::dump() const { dumpOne(true); SkDebugf("\n"); } void SkOpAngle::dumpOne(bool functionHeader) const { // fSegment->debugValidate(); const SkOpSegment* segment = this->segment(); const SkOpSpan& mSpan = *fStart->starter(fEnd); if (functionHeader) { SkDebugf("%s ", __FUNCTION__); } SkDebugf("[%d", segment->debugID()); SkDebugf("/%d", debugID()); SkDebugf("] next="); if (fNext) { SkDebugf("%d", fNext->fStart->segment()->debugID()); SkDebugf("/%d", fNext->debugID()); } else { SkDebugf("?"); } SkDebugf(" sect=%d/%d ", fSectorStart, fSectorEnd); SkDebugf(" s=%1.9g [%d] e=%1.9g [%d]", fStart->t(), fStart->debugID(), fEnd->t(), fEnd->debugID()); SkDebugf(" sgn=%d windVal=%d", this->debugSign(), mSpan.windValue()); SkDebugf(" windSum="); SkPathOpsDebug::WindingPrintf(mSpan.windSum()); if (mSpan.oppValue() != 0 || mSpan.oppSum() != SK_MinS32) { SkDebugf(" oppVal=%d", mSpan.oppValue()); SkDebugf(" oppSum="); SkPathOpsDebug::WindingPrintf(mSpan.oppSum()); } if (mSpan.done()) { SkDebugf(" done"); } if (unorderable()) { SkDebugf(" unorderable"); } if (segment->operand()) { SkDebugf(" operand"); } } void SkOpAngle::dumpTo(const SkOpSegment* segment, const SkOpAngle* to) const { const SkOpAngle* first = this; const SkOpAngle* next = this; const char* indent = ""; do { SkDebugf("%s", indent); next->dumpOne(false); if (segment == next->fStart->segment()) { if (this == fNext) { SkDebugf(" << from"); } if (to == fNext) { SkDebugf(" << to"); } } SkDebugf("\n"); indent = " "; next = next->fNext; } while (next && next != first); } void SkOpAngle::dumpCurves() const { const SkOpAngle* first = this; const SkOpAngle* next = this; do { next->fPart.fCurve.dumpID(next->segment()->debugID()); next = next->fNext; } while (next && next != first); } void SkOpAngle::dumpLoop() const { const SkOpAngle* first = this; const SkOpAngle* next = this; do { next->dumpOne(false); SkDebugf("\n"); next = next->fNext; } while (next && next != first); } void SkOpAngle::dumpTest() const { const SkOpAngle* first = this; const SkOpAngle* next = this; do { SkDebugf("{ "); SkOpSegment* segment = next->segment(); segment->dumpPts(); SkDebugf(", %d, %1.9g, %1.9g, {} },\n", SkPathOpsVerbToPoints(segment->verb()) + 1, next->start()->t(), next->end()->t()); next = next->fNext; } while (next && next != first); } bool SkOpPtT::debugMatchID(int id) const { int limit = this->debugLoopLimit(false); int loop = 0; const SkOpPtT* ptT = this; do { if (ptT->debugID() == id) { return true; } } while ((!limit || ++loop <= limit) && (ptT = ptT->next()) && ptT != this); return false; } const SkOpAngle* SkOpPtT::debugAngle(int id) const { return this->span()->debugAngle(id); } SkOpContour* SkOpPtT::debugContour(int id) const { return this->span()->debugContour(id); } const SkOpCoincidence* SkOpPtT::debugCoincidence() const { return this->span()->debugCoincidence(); } const SkOpPtT* SkOpPtT::debugPtT(int id) const { return this->span()->debugPtT(id); } const SkOpSegment* SkOpPtT::debugSegment(int id) const { return this->span()->debugSegment(id); } const SkOpSpanBase* SkOpPtT::debugSpan(int id) const { return this->span()->debugSpan(id); } void SkOpPtT::dump() const { SkDebugf("seg=%d span=%d ptT=%d", this->segment()->debugID(), this->span()->debugID(), this->debugID()); this->dumpBase(); SkDebugf("\n"); } void SkOpPtT::dumpAll() const { contour()->indentDump(); const SkOpPtT* next = this; int limit = debugLoopLimit(true); int loop = 0; do { SkDebugf("%.*s", contour()->debugIndent(), " "); SkDebugf("seg=%d span=%d ptT=%d", next->segment()->debugID(), next->span()->debugID(), next->debugID()); next->dumpBase(); SkDebugf("\n"); if (limit && ++loop >= limit) { SkDebugf("*** abort loop ***\n"); break; } } while ((next = next->fNext) && next != this); contour()->outdentDump(); } void SkOpPtT::dumpBase() const { SkDebugf(" t=%1.9g pt=(%1.9g,%1.9g)%s%s%s", this->fT, this->fPt.fX, this->fPt.fY, this->fCoincident ? " coin" : "", this->fDuplicatePt ? " dup" : "", this->fDeleted ? " deleted" : ""); } const SkOpAngle* SkOpSpanBase::debugAngle(int id) const { return this->segment()->debugAngle(id); } const SkOpCoincidence* SkOpSpanBase::debugCoincidence() const { return this->segment()->debugCoincidence(); } SkOpContour* SkOpSpanBase::debugContour(int id) const { return this->segment()->debugContour(id); } const SkOpPtT* SkOpSpanBase::debugPtT(int id) const { return this->segment()->debugPtT(id); } const SkOpSegment* SkOpSpanBase::debugSegment(int id) const { return this->segment()->debugSegment(id); } const SkOpSpanBase* SkOpSpanBase::debugSpan(int id) const { return this->segment()->debugSpan(id); } void SkOpSpanBase::dump() const { this->dumpHead(); this->fPtT.dump(); } void SkOpSpanBase::dumpHead() const { SkDebugf("%.*s", contour()->debugIndent(), " "); SkDebugf("seg=%d span=%d", this->segment()->debugID(), this->debugID()); this->dumpBase(); SkDebugf("\n"); } void SkOpSpanBase::dumpAll() const { this->dumpHead(); this->fPtT.dumpAll(); } void SkOpSpanBase::dumpBase() const { if (this->fAligned) { SkDebugf(" aligned"); } if (this->fChased) { SkDebugf(" chased"); } #ifdef SK_DEBUG if (this->fDebugDeleted) { SkDebugf(" deleted"); } #endif if (!this->final()) { this->upCast()->dumpSpan(); } const SkOpSpanBase* coin = this->coinEnd(); if (this != coin) { SkDebugf(" coinEnd seg/span=%d/%d", coin->segment()->debugID(), coin->debugID()); } else if (this->final() || !this->upCast()->isCoincident()) { const SkOpPtT* oPt = this->ptT()->next(); SkDebugf(" seg/span=%d/%d", oPt->segment()->debugID(), oPt->span()->debugID()); } SkDebugf(" adds=%d", fSpanAdds); } void SkOpSpanBase::dumpCoin() const { const SkOpSpan* span = this->upCastable(); if (!span) { return; } if (!span->isCoincident()) { return; } span->dumpCoin(); } void SkOpSpan::dumpCoin() const { const SkOpSpan* coincident = fCoincident; bool ok = debugCoinLoopCheck(); this->dump(); int loop = 0; do { coincident->dump(); if (!ok && ++loop > 10) { SkDebugf("*** abort loop ***\n"); break; } } while ((coincident = coincident->fCoincident) != this); } bool SkOpSpan::dumpSpan() const { SkOpSpan* coin = fCoincident; if (this != coin) { SkDebugf(" coinStart seg/span=%d/%d", coin->segment()->debugID(), coin->debugID()); } SkDebugf(" windVal=%d", this->windValue()); SkDebugf(" windSum="); SkPathOpsDebug::WindingPrintf(this->windSum()); if (this->oppValue() != 0 || this->oppSum() != SK_MinS32) { SkDebugf(" oppVal=%d", this->oppValue()); SkDebugf(" oppSum="); SkPathOpsDebug::WindingPrintf(this->oppSum()); } if (this->done()) { SkDebugf(" done"); } return this != coin; } const SkOpAngle* SkOpSegment::debugAngle(int id) const { return this->contour()->debugAngle(id); } const SkOpCoincidence* SkOpSegment::debugCoincidence() const { return this->contour()->debugCoincidence(); } SkOpContour* SkOpSegment::debugContour(int id) const { return this->contour()->debugContour(id); } const SkOpPtT* SkOpSegment::debugPtT(int id) const { return this->contour()->debugPtT(id); } const SkOpSegment* SkOpSegment::debugSegment(int id) const { return this->contour()->debugSegment(id); } const SkOpSpanBase* SkOpSegment::debugSpan(int id) const { return this->contour()->debugSpan(id); } void SkOpSegment::dump() const { SkDebugf("%.*s", contour()->debugIndent(), " "); this->dumpPts(); const SkOpSpanBase* span = &fHead; contour()->indentDump(); do { SkDebugf("%.*s span=%d ", contour()->debugIndent(), " ", span->debugID()); span->ptT()->dumpBase(); span->dumpBase(); SkDebugf("\n"); } while (!span->final() && (span = span->upCast()->next())); contour()->outdentDump(); } void SkOpSegment::dumpAll() const { SkDebugf("%.*s", contour()->debugIndent(), " "); this->dumpPts(); const SkOpSpanBase* span = &fHead; contour()->indentDump(); do { span->dumpAll(); } while (!span->final() && (span = span->upCast()->next())); contour()->outdentDump(); } void SkOpSegment::dumpAngles() const { SkDebugf("seg=%d\n", debugID()); const SkOpSpanBase* span = &fHead; do { const SkOpAngle* fAngle = span->fromAngle(); const SkOpAngle* tAngle = span->final() ? nullptr : span->upCast()->toAngle(); if (fAngle) { SkDebugf(" span=%d from=%d ", span->debugID(), fAngle->debugID()); fAngle->dumpTo(this, tAngle); } if (tAngle) { SkDebugf(" span=%d to=%d ", span->debugID(), tAngle->debugID()); tAngle->dumpTo(this, fAngle); } } while (!span->final() && (span = span->upCast()->next())); } void SkOpSegment::dumpCoin() const { const SkOpSpan* span = &fHead; do { span->dumpCoin(); } while ((span = span->next()->upCastable())); } void SkOpSegment::dumpPtsInner(const char* prefix) const { int last = SkPathOpsVerbToPoints(fVerb); SkDebugf("%s=%d {{", prefix, this->debugID()); if (fVerb == SkPath::kConic_Verb) { SkDebugf("{"); } int index = 0; do { SkDPoint::Dump(fPts[index]); SkDebugf(", "); } while (++index < last); SkDPoint::Dump(fPts[index]); SkDebugf("}}"); if (fVerb == SkPath::kConic_Verb) { SkDebugf(", %1.9gf}", fWeight); } } void SkOpSegment::dumpPts(const char* prefix) const { dumpPtsInner(prefix); SkDebugf("\n"); } void SkCoincidentSpans::dump() const { SkDebugf("- seg=%d span=%d ptT=%d ", fCoinPtTStart->segment()->debugID(), fCoinPtTStart->span()->debugID(), fCoinPtTStart->debugID()); fCoinPtTStart->dumpBase(); SkDebugf(" span=%d ptT=%d ", fCoinPtTEnd->span()->debugID(), fCoinPtTEnd->debugID()); fCoinPtTEnd->dumpBase(); if (fCoinPtTStart->segment()->operand()) { SkDebugf(" operand"); } if (fCoinPtTStart->segment()->isXor()) { SkDebugf(" xor"); } SkDebugf("\n"); SkDebugf("+ seg=%d span=%d ptT=%d ", fOppPtTStart->segment()->debugID(), fOppPtTStart->span()->debugID(), fOppPtTStart->debugID()); fOppPtTStart->dumpBase(); SkDebugf(" span=%d ptT=%d ", fOppPtTEnd->span()->debugID(), fOppPtTEnd->debugID()); fOppPtTEnd->dumpBase(); if (fOppPtTStart->segment()->operand()) { SkDebugf(" operand"); } if (fOppPtTStart->segment()->isXor()) { SkDebugf(" xor"); } SkDebugf("\n"); } void SkOpCoincidence::dump() const { SkCoincidentSpans* span = fHead; while (span) { span->dump(); span = span->next(); } if (!fTop || fHead == fTop) { return; } SkDebugf("top:\n"); span = fTop; int count = 0; while (span) { span->dump(); span = span->next(); SkCoincidentSpans* check = fTop; ++count; for (int index = 0; index < count; ++index) { if (span == check) { SkDebugf("(loops to #%d)\n", index); return; } check = check->next(); } } } void SkOpContour::dump() const { SkDebugf("contour=%d count=%d op=%d xor=%d\n", this->debugID(), fCount, fOperand, fXor); if (!fCount) { return; } const SkOpSegment* segment = &fHead; SkDEBUGCODE(fDebugIndent = 0); this->indentDump(); do { segment->dump(); } while ((segment = segment->next())); this->outdentDump(); } void SkOpContour::dumpAll() const { SkDebugf("contour=%d count=%d op=%d xor=%d\n", this->debugID(), fCount, fOperand, fXor); if (!fCount) { return; } const SkOpSegment* segment = &fHead; SkDEBUGCODE(fDebugIndent = 0); this->indentDump(); do { segment->dumpAll(); } while ((segment = segment->next())); this->outdentDump(); } void SkOpContour::dumpAngles() const { SkDebugf("contour=%d\n", this->debugID()); const SkOpSegment* segment = &fHead; do { SkDebugf(" seg=%d ", segment->debugID()); segment->dumpAngles(); } while ((segment = segment->next())); } void SkOpContour::dumpPt(int index) const { const SkOpSegment* segment = &fHead; do { if (segment->debugID() == index) { segment->dumpPts(); } } while ((segment = segment->next())); } void SkOpContour::dumpPts(const char* prefix) const { SkDebugf("contour=%d\n", this->debugID()); const SkOpSegment* segment = &fHead; do { SkDebugf(" %s=%d ", prefix, segment->debugID()); segment->dumpPts(prefix); } while ((segment = segment->next())); } void SkOpContour::dumpPtsX(const char* prefix) const { if (!this->fCount) { SkDebugf("<empty>\n"); return; } const SkOpSegment* segment = &fHead; do { segment->dumpPts(prefix); } while ((segment = segment->next())); } void SkOpContour::dumpSegment(int index) const { debugSegment(index)->dump(); } void SkOpContour::dumpSegments(const char* prefix, SkPathOp op) const { bool firstOp = false; const SkOpContour* c = this; do { if (!firstOp && c->operand()) { #if DEBUG_ACTIVE_OP SkDebugf("op %s\n", SkPathOpsDebug::kPathOpStr[op]); #endif firstOp = true; } c->dumpPtsX(prefix); } while ((c = c->next())); } void SkOpContour::dumpSpan(int index) const { debugSpan(index)->dump(); } void SkOpContour::dumpSpans() const { SkDebugf("contour=%d\n", this->debugID()); const SkOpSegment* segment = &fHead; do { SkDebugf(" seg=%d ", segment->debugID()); segment->dump(); } while ((segment = segment->next())); } void SkOpCurve::dump() const { int count = SkPathOpsVerbToPoints(SkDEBUGRELEASE(fVerb, SkPath::kCubic_Verb)); SkDebugf("{{"); int index; for (index = 0; index <= count - 1; ++index) { SkDebugf("{%1.9gf,%1.9gf}, ", fPts[index].fX, fPts[index].fY); } SkDebugf("{%1.9gf,%1.9gf}}}\n", fPts[index].fX, fPts[index].fY); } #ifdef SK_DEBUG const SkOpAngle* SkOpGlobalState::debugAngle(int id) const { const SkOpContour* contour = fContourHead; do { const SkOpSegment* segment = contour->first(); while (segment) { const SkOpSpan* span = segment->head(); do { SkOpAngle* angle = span->fromAngle(); if (angle && angle->debugID() == id) { return angle; } angle = span->toAngle(); if (angle && angle->debugID() == id) { return angle; } } while ((span = span->next()->upCastable())); const SkOpSpanBase* tail = segment->tail(); SkOpAngle* angle = tail->fromAngle(); if (angle && angle->debugID() == id) { return angle; } segment = segment->next(); } } while ((contour = contour->next())); return nullptr; } SkOpContour* SkOpGlobalState::debugContour(int id) const { SkOpContour* contour = fContourHead; do { if (contour->debugID() == id) { return contour; } } while ((contour = contour->next())); return nullptr; } const SkOpPtT* SkOpGlobalState::debugPtT(int id) const { const SkOpContour* contour = fContourHead; do { const SkOpSegment* segment = contour->first(); while (segment) { const SkOpSpan* span = segment->head(); do { const SkOpPtT* ptT = span->ptT(); if (ptT->debugMatchID(id)) { return ptT; } } while ((span = span->next()->upCastable())); const SkOpSpanBase* tail = segment->tail(); const SkOpPtT* ptT = tail->ptT(); if (ptT->debugMatchID(id)) { return ptT; } segment = segment->next(); } } while ((contour = contour->next())); return nullptr; } const SkOpSegment* SkOpGlobalState::debugSegment(int id) const { const SkOpContour* contour = fContourHead; do { const SkOpSegment* segment = contour->first(); while (segment) { if (segment->debugID() == id) { return segment; } segment = segment->next(); } } while ((contour = contour->next())); return nullptr; } const SkOpSpanBase* SkOpGlobalState::debugSpan(int id) const { const SkOpContour* contour = fContourHead; do { const SkOpSegment* segment = contour->first(); while (segment) { const SkOpSpan* span = segment->head(); do { if (span->debugID() == id) { return span; } } while ((span = span->next()->upCastable())); const SkOpSpanBase* tail = segment->tail(); if (tail->debugID() == id) { return tail; } segment = segment->next(); } } while ((contour = contour->next())); return nullptr; } #endif char SkTCoincident::dumpIsCoincidentStr() const { if (!!fMatch != fMatch) { return '?'; } return fMatch ? '*' : 0; } void SkTCoincident::dump() const { SkDebugf("t=%1.9g pt=(%1.9g,%1.9g)%s\n", fPerpT, fPerpPt.fX, fPerpPt.fY, fMatch ? " match" : ""); } #ifdef SK_DEBUG const SkTSpan* SkTSect::debugSpan(int id) const { const SkTSpan* test = fHead; do { if (test->debugID() == id) { return test; } } while ((test = test->next())); return nullptr; } const SkTSpan* SkTSect::debugT(double t) const { const SkTSpan* test = fHead; const SkTSpan* 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; } #endif void SkTSect::dump() const { dumpCommon(fHead); } extern int gDumpTSectNum; void SkTSect::dumpBoth(SkTSect* 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 } void SkTSect::dumpBounded(int id) const { #ifdef SK_DEBUG const SkTSpan* bounded = debugSpan(id); if (!bounded) { SkDebugf("no span matches %d\n", id); return; } const SkTSpan* test = bounded->debugOpp()->fHead; do { if (test->findOppSpan(bounded)) { test->dump(); SkDebugf(" "); } } while ((test = test->next())); SkDebugf("\n"); #endif } void SkTSect::dumpBounds() const { const SkTSpan* test = fHead; do { test->dumpBounds(); } while ((test = test->next())); } void SkTSect::dumpCoin() const { dumpCommon(fCoincident); } void SkTSect::dumpCoinCurves() const { dumpCommonCurves(fCoincident); } void SkTSect::dumpCommon(const SkTSpan* test) const { SkDebugf("id=%d", debugID()); if (!test) { SkDebugf(" (empty)"); return; } do { SkDebugf(" "); test->dump(); } while ((test = test->next())); } void SkTSect::dumpCommonCurves(const SkTSpan* test) const { #if DEBUG_T_SECT do { test->fPart->dumpID(test->debugID()); } while ((test = test->next())); #endif } void SkTSect::dumpCurves() const { dumpCommonCurves(fHead); } #ifdef SK_DEBUG const SkTSpan* SkTSpan::debugSpan(int id) const { return fDebugSect->debugSpan(id); } const SkTSpan* SkTSpan::debugT(double t) const { return fDebugSect->debugT(t); } #endif void SkTSpan::dumpAll() const { dumpID(); SkDebugf("=(%g,%g) [", fStartT, fEndT); const SkTSpanBounded* testBounded = fBounded; while (testBounded) { const SkTSpan* span = testBounded->fBounded; const SkTSpanBounded* next = testBounded->fNext; span->dumpID(); SkDebugf("=(%g,%g)", span->fStartT, span->fEndT); if (next) { SkDebugf(" "); } testBounded = next; } SkDebugf("]\n"); } void SkTSpan::dump() const { dumpID(); SkDebugf("=(%g,%g) [", fStartT, fEndT); const SkTSpanBounded* testBounded = fBounded; while (testBounded) { const SkTSpan* span = testBounded->fBounded; const SkTSpanBounded* next = testBounded->fNext; span->dumpID(); if (next) { SkDebugf(","); } testBounded = next; } SkDebugf("]"); } void SkTSpan::dumpBounded(int id) const { SkDEBUGCODE(fDebugSect->dumpBounded(id)); } void SkTSpan::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" : ""); } void SkTSpan::dumpCoin() const { dumpID(); SkDebugf(" coinStart "); fCoinStart.dump(); SkDebugf(" coinEnd "); fCoinEnd.dump(); } void SkTSpan::dumpID() const { char cS = fCoinStart.dumpIsCoincidentStr(); if (cS) { SkDebugf("%c", cS); } SkDebugf("%d", debugID()); char cE = fCoinEnd.dumpIsCoincidentStr(); if (cE) { SkDebugf("%c", cE); } } #if DEBUG_T_SECT_DUMP > 1 int gDumpTSectNum; #endif // global path dumps for msvs Visual Studio 17 to use from Immediate Window void Dump(const SkOpContour& contour) { contour.dump(); } void DumpAll(const SkOpContour& contour) { contour.dumpAll(); } void DumpAngles(const SkOpContour& contour) { contour.dumpAngles(); } void DumpContours(const SkOpContour& contour) { contour.dumpContours(); } void DumpContoursAll(const SkOpContour& contour) { contour.dumpContoursAll(); } void DumpContoursAngles(const SkOpContour& contour) { contour.dumpContoursAngles(); } void DumpContoursPts(const SkOpContour& contour) { contour.dumpContoursPts(); } void DumpContoursPt(const SkOpContour& contour, int segmentID) { contour.dumpContoursPt(segmentID); } void DumpContoursSegment(const SkOpContour& contour, int segmentID) { contour.dumpContoursSegment(segmentID); } void DumpContoursSpan(const SkOpContour& contour, int segmentID) { contour.dumpContoursSpan(segmentID); } void DumpContoursSpans(const SkOpContour& contour) { contour.dumpContoursSpans(); } void DumpPt(const SkOpContour& contour, int pt) { contour.dumpPt(pt); } void DumpPts(const SkOpContour& contour, const char* prefix) { contour.dumpPts(prefix); } void DumpSegment(const SkOpContour& contour, int seg) { contour.dumpSegment(seg); } void DumpSegments(const SkOpContour& contour, const char* prefix, SkPathOp op) { contour.dumpSegments(prefix, op); } void DumpSpan(const SkOpContour& contour, int span) { contour.dumpSpan(span); } void DumpSpans(const SkOpContour& contour ) { contour.dumpSpans(); } void Dump(const SkOpSegment& segment) { segment.dump(); } void DumpAll(const SkOpSegment& segment) { segment.dumpAll(); } void DumpAngles(const SkOpSegment& segment) { segment.dumpAngles(); } void DumpCoin(const SkOpSegment& segment) { segment.dumpCoin(); } void DumpPts(const SkOpSegment& segment, const char* prefix) { segment.dumpPts(prefix); } void Dump(const SkOpPtT& ptT) { ptT.dump(); } void DumpAll(const SkOpPtT& ptT) { ptT.dumpAll(); } void Dump(const SkOpSpanBase& spanBase) { spanBase.dump(); } void DumpCoin(const SkOpSpanBase& spanBase) { spanBase.dumpCoin(); } void DumpAll(const SkOpSpanBase& spanBase) { spanBase.dumpAll(); } void DumpCoin(const SkOpSpan& span) { span.dumpCoin(); } bool DumpSpan(const SkOpSpan& span) { return span.dumpSpan(); } void Dump(const SkDConic& conic) { conic.dump(); } void DumpID(const SkDConic& conic, int id) { conic.dumpID(id); } void Dump(const SkDCubic& cubic) { cubic.dump(); } void DumpID(const SkDCubic& cubic, int id) { cubic.dumpID(id); } void Dump(const SkDLine& line) { line.dump(); } void DumpID(const SkDLine& line, int id) { line.dumpID(id); } void Dump(const SkDQuad& quad) { quad.dump(); } void DumpID(const SkDQuad& quad, int id) { quad.dumpID(id); } void Dump(const SkDPoint& point) { point.dump(); } void Dump(const SkOpAngle& angle) { angle.dump(); }