|  | /* | 
|  | * 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 = std::min(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(); | 
|  | } |