35bool SkPathOpsDebug::gDumpOp;
36bool SkPathOpsDebug::gVerifyOp;
42#define FAIL_IF_COIN(cond, coin) \
43 do { if (cond) log->record(SkPathOpsDebug::kFail_Glitch, coin); } while (false)
45#undef FAIL_WITH_NULL_IF
46#define FAIL_WITH_NULL_IF(cond, span) \
47 do { if (cond) log->record(SkPathOpsDebug::kFail_Glitch, span); } while (false)
49#define RETURN_FALSE_IF(cond, span) \
50 do { if (cond) log->record(SkPathOpsDebug::kReturnFalse_Glitch, span); \
54int SkPathOpsDebug::gSortCountDefault =
SK_MaxS32;
55int SkPathOpsDebug::gSortCount;
59const char* SkPathOpsDebug::kPathOpStr[] = {
"diff",
"sect",
"union",
"xor",
"rdiff"};
62#if defined SK_DEBUG || !FORCE_RELEASE
64int SkPathOpsDebug::gContourID = 0;
65int SkPathOpsDebug::gSegmentID = 0;
69 for (
int index = 0; index < chaseArray.
size(); ++index) {
80SkString SkPathOpsDebug::gActiveSpans;
89SkPathOpsDebug::CoinDict SkPathOpsDebug::gCoinSumChangedDict;
90SkPathOpsDebug::CoinDict SkPathOpsDebug::gCoinSumVisitedDict;
92static const int kGlitchType_Count = SkPathOpsDebug::kUnalignedTail_Glitch + 1;
108 SkPathOpsDebug::GlitchType fType;
110 void dumpType()
const;
113struct SkPathOpsDebug::GlitchLog {
115 fGlobalState =
state;
118 SpanGlitch* recordCommon(GlitchType
type) {
119 SpanGlitch* glitch = fGlitches.append();
120 glitch->fBase =
nullptr;
121 glitch->fSuspect =
nullptr;
122 glitch->fSegment =
nullptr;
123 glitch->fOppSegment =
nullptr;
124 glitch->fCoinSpan =
nullptr;
125 glitch->fEndSpan =
nullptr;
126 glitch->fOppSpan =
nullptr;
127 glitch->fOppEndSpan =
nullptr;
133 glitch->fType =
type;
138 SpanGlitch* glitch = recordCommon(
type);
139 glitch->fBase =
base;
140 glitch->fSuspect = suspect;
144 SpanGlitch* glitch = recordCommon(
type);
145 glitch->fBase =
base;
146 glitch->fCoinSpan = ptT;
149 void record(GlitchType
type,
152 SpanGlitch* glitch = recordCommon(
type);
156 glitch->fOppSpan = opp->coinPtTStart();
157 glitch->fOppEndSpan = opp->coinPtTEnd();
163 SpanGlitch* glitch = recordCommon(
type);
164 glitch->fBase =
base;
165 glitch->fSegment = seg;
172 SpanGlitch* glitch = recordCommon(
type);
173 glitch->fBase =
base;
180 SpanGlitch* glitch = recordCommon(
type);
183 glitch->fEndSpan = endSpan;
184 glitch->fOppSpan = coinSpan;
185 glitch->fOppEndSpan = endSpan;
190 SpanGlitch* glitch = recordCommon(
type);
191 glitch->fBase =
base;
198 SpanGlitch* glitch = recordCommon(
type);
199 glitch->fCoinSpan = ptTS;
200 glitch->fEndSpan = ptTE;
201 glitch->fOppSpan = oPtTS;
202 glitch->fOppEndSpan = oPtTE;
206 double endT,
const SkOpSegment* oppSeg,
double oppStartT,
double oppEndT) {
207 SpanGlitch* glitch = recordCommon(
type);
208 glitch->fSegment = seg;
209 glitch->fStartT = startT;
210 glitch->fEndT = endT;
211 glitch->fOppSegment = oppSeg;
212 glitch->fOppStartT = oppStartT;
213 glitch->fOppEndT = oppEndT;
218 SpanGlitch* glitch = recordCommon(
type);
219 glitch->fSegment = seg;
220 glitch->fBase = span;
224 SpanGlitch* glitch = recordCommon(
type);
226 glitch->fBase = span;
230 SpanGlitch* glitch = recordCommon(
type);
231 glitch->fSegment = seg;
236 SpanGlitch* glitch = recordCommon(
type);
238 glitch->fEndSpan = ptT;
246void SkPathOpsDebug::CoinDict::add(
const SkPathOpsDebug::CoinDict& dict) {
247 int count = dict.fDict.size();
248 for (
int index = 0; index <
count; ++index) {
249 this->add(dict.fDict[index]);
253void SkPathOpsDebug::CoinDict::add(
const CoinDictEntry&
key) {
254 int count = fDict.size();
255 for (
int index = 0; index <
count; ++index) {
256 CoinDictEntry* entry = &fDict[index];
257 if (entry->fIteration ==
key.fIteration && entry->fLineNumber ==
key.fLineNumber) {
258 SkASSERT(!strcmp(entry->fFunctionName,
key.fFunctionName));
259 if (entry->fGlitchType == kUninitialized_Glitch) {
260 entry->fGlitchType =
key.fGlitchType;
265 *fDict.append() =
key;
276 contour->debugMissingCoincidence(glitches);
285 contour->debugMoveMultiples(glitches);
293 contour->debugMoveNearby(glitches);
300void SkOpGlobalState::debugAddToCoinChangedDict() {
306 SkPathOpsDebug::GlitchLog glitches;
307 const char* funcName = fCoinDictEntry.fFunctionName;
308 if (!strcmp(
"calc_angles", funcName)) {
310 }
else if (!strcmp(
"missing_coincidence", funcName)) {
312 }
else if (!strcmp(
"move_multiples", funcName)) {
314 }
else if (!strcmp(
"move_nearby", funcName)) {
316 }
else if (!strcmp(
"addExpanded", funcName)) {
317 fCoincidence->debugAddExpanded(&glitches);
318 }
else if (!strcmp(
"addMissing", funcName)) {
320 fCoincidence->debugAddMissing(&glitches, &added);
321 }
else if (!strcmp(
"addEndMovedSpans", funcName)) {
322 fCoincidence->debugAddEndMovedSpans(&glitches);
323 }
else if (!strcmp(
"correctEnds", funcName)) {
324 fCoincidence->debugCorrectEnds(&glitches);
325 }
else if (!strcmp(
"expand", funcName)) {
326 fCoincidence->debugExpand(&glitches);
327 }
else if (!strcmp(
"findOverlaps", funcName)) {
329 }
else if (!strcmp(
"mark", funcName)) {
330 fCoincidence->debugMark(&glitches);
331 }
else if (!strcmp(
"apply", funcName)) {
336 if (glitches.fGlitches.size()) {
337 fCoinDictEntry.fGlitchType = glitches.fGlitches[0].fType;
339 fCoinChangedDict.add(fCoinDictEntry);
344#if DEBUG_ACTIVE_SPANS
348 contour->debugShowActiveSpans(&str);
350 if (!gActiveSpans.equals(str)) {
351 const char*
s = str.
c_str();
353 while ((
end = strchr(
s,
'\n'))) {
357 gActiveSpans.set(str);
362#if DEBUG_COINCIDENCE || DEBUG_COIN
365 contourList->
globalState()->debugSetCheckHealth(
true);
371 coincidence->debugCheckValid(&glitches);
373 contour->debugCheckHealth(&glitches);
374 contour->debugMissingCoincidence(&glitches);
377 coincidence->debugAddMissing(&glitches, &added);
378 coincidence->debugExpand(&glitches);
379 coincidence->debugAddExpanded(&glitches);
380 coincidence->debugMark(&glitches);
382 for (
int index = 0; index < glitches.fGlitches.size(); ++index) {
383 const SpanGlitch& glitch = glitches.fGlitches[index];
384 mask |= 1 << glitch.fType;
386 for (
int index = 0; index < kGlitchType_Count; ++index) {
387 SkDebugf(mask & (1 << index) ?
"x" :
"-");
390 for (
int index = 0; index < glitches.fGlitches.size(); ++index) {
391 const SpanGlitch& glitch = glitches.fGlitches[index];
394 SkDebugf(
" seg/base=%d/%d", glitch.fBase->segment()->debugID(),
395 glitch.fBase->debugID());
397 if (glitch.fSuspect) {
398 SkDebugf(
" seg/base=%d/%d", glitch.fSuspect->segment()->debugID(),
399 glitch.fSuspect->debugID());
401 if (glitch.fSegment) {
402 SkDebugf(
" segment=%d", glitch.fSegment->debugID());
404 if (glitch.fCoinSpan) {
405 SkDebugf(
" coinSeg/Span/PtT=%d/%d/%d", glitch.fCoinSpan->segment()->debugID(),
406 glitch.fCoinSpan->span()->debugID(), glitch.fCoinSpan->debugID());
408 if (glitch.fEndSpan) {
409 SkDebugf(
" endSpan=%d", glitch.fEndSpan->debugID());
411 if (glitch.fOppSpan) {
412 SkDebugf(
" oppSeg/Span/PtT=%d/%d/%d", glitch.fOppSpan->segment()->debugID(),
413 glitch.fOppSpan->span()->debugID(), glitch.fOppSpan->debugID());
415 if (glitch.fOppEndSpan) {
416 SkDebugf(
" oppEndSpan=%d", glitch.fOppEndSpan->debugID());
418 if (!
SkIsNaN(glitch.fStartT)) {
419 SkDebugf(
" startT=%g", glitch.fStartT);
424 if (glitch.fOppSegment) {
425 SkDebugf(
" segment=%d", glitch.fOppSegment->debugID());
427 if (!
SkIsNaN(glitch.fOppStartT)) {
428 SkDebugf(
" oppStartT=%g", glitch.fOppStartT);
430 if (!
SkIsNaN(glitch.fOppEndT)) {
431 SkDebugf(
" oppEndT=%g", glitch.fOppEndT);
434 SkDebugf(
" pt=%g,%g", glitch.fPt.fX, glitch.fPt.fY);
436 DumpGlitchType(glitch.fType);
440 contourList->
globalState()->debugSetCheckHealth(
false);
442#if 01 && DEBUG_ACTIVE_SPANS
451void SkPathOpsDebug::DumpGlitchType(GlitchType glitchType) {
452 switch (glitchType) {
453 case kAddCorruptCoin_Glitch:
SkDebugf(
" AddCorruptCoin");
break;
454 case kAddExpandedCoin_Glitch:
SkDebugf(
" AddExpandedCoin");
break;
455 case kAddExpandedFail_Glitch:
SkDebugf(
" AddExpandedFail");
break;
456 case kAddIfCollapsed_Glitch:
SkDebugf(
" AddIfCollapsed");
break;
457 case kAddIfMissingCoin_Glitch:
SkDebugf(
" AddIfMissingCoin");
break;
458 case kAddMissingCoin_Glitch:
SkDebugf(
" AddMissingCoin");
break;
459 case kAddMissingExtend_Glitch:
SkDebugf(
" AddMissingExtend");
break;
460 case kAddOrOverlap_Glitch:
SkDebugf(
" AAddOrOverlap");
break;
461 case kCollapsedCoin_Glitch:
SkDebugf(
" CollapsedCoin");
break;
462 case kCollapsedDone_Glitch:
SkDebugf(
" CollapsedDone");
break;
463 case kCollapsedOppValue_Glitch:
SkDebugf(
" CollapsedOppValue");
break;
464 case kCollapsedSpan_Glitch:
SkDebugf(
" CollapsedSpan");
break;
465 case kCollapsedWindValue_Glitch:
SkDebugf(
" CollapsedWindValue");
break;
466 case kCorrectEnd_Glitch:
SkDebugf(
" CorrectEnd");
break;
467 case kDeletedCoin_Glitch:
SkDebugf(
" DeletedCoin");
break;
468 case kExpandCoin_Glitch:
SkDebugf(
" ExpandCoin");
break;
469 case kFail_Glitch:
SkDebugf(
" Fail");
break;
470 case kMarkCoinEnd_Glitch:
SkDebugf(
" MarkCoinEnd");
break;
471 case kMarkCoinInsert_Glitch:
SkDebugf(
" MarkCoinInsert");
break;
472 case kMarkCoinMissing_Glitch:
SkDebugf(
" MarkCoinMissing");
break;
473 case kMarkCoinStart_Glitch:
SkDebugf(
" MarkCoinStart");
break;
474 case kMergeMatches_Glitch:
SkDebugf(
" MergeMatches");
break;
475 case kMissingCoin_Glitch:
SkDebugf(
" MissingCoin");
break;
476 case kMissingDone_Glitch:
SkDebugf(
" MissingDone");
break;
477 case kMissingIntersection_Glitch:
SkDebugf(
" MissingIntersection");
break;
478 case kMoveMultiple_Glitch:
SkDebugf(
" MoveMultiple");
break;
479 case kMoveNearbyClearAll_Glitch:
SkDebugf(
" MoveNearbyClearAll");
break;
480 case kMoveNearbyClearAll2_Glitch:
SkDebugf(
" MoveNearbyClearAll2");
break;
481 case kMoveNearbyMerge_Glitch:
SkDebugf(
" MoveNearbyMerge");
break;
482 case kMoveNearbyMergeFinal_Glitch:
SkDebugf(
" MoveNearbyMergeFinal");
break;
483 case kMoveNearbyRelease_Glitch:
SkDebugf(
" MoveNearbyRelease");
break;
484 case kMoveNearbyReleaseFinal_Glitch:
SkDebugf(
" MoveNearbyReleaseFinal");
break;
485 case kReleasedSpan_Glitch:
SkDebugf(
" ReleasedSpan");
break;
486 case kReturnFalse_Glitch:
SkDebugf(
" ReturnFalse");
break;
487 case kUnaligned_Glitch:
SkDebugf(
" Unaligned");
break;
488 case kUnalignedHead_Glitch:
SkDebugf(
" UnalignedHead");
break;
489 case kUnalignedTail_Glitch:
SkDebugf(
" UnalignedTail");
break;
490 case kUninitialized_Glitch:
break;
496#if defined SK_DEBUG || !FORCE_RELEASE
498 size_t len = strlen(str);
500 for (
size_t idx = 0; idx <
len; ++idx) {
501 if (num && str[idx] ==
'e') {
502 if (
len + 2 >= bufferLen) {
505 memmove(&str[idx + 2], &str[idx + 1],
len - idx);
510 num = str[idx] >=
'0' && str[idx] <=
'9';
529 SkDebugf(
"\nstatic void %s(skiatest::Reporter* reporter, const char* filename) {\n", functionName);
530 if (strcmp(
"skphealth_com76", functionName) == 0) {
536 "kDifference_SkPathOp",
537 "kIntersect_SkPathOp",
540 "kReverseDifference_SkPathOp",
548 SkDebugf(
" testPathOp(reporter, %s, %s, %s, filename);\n", pathOne, pathTwo,
gOpStrs[op]);
554 static SkMutex& mutex = *(
new SkMutex);
560 show_op(shapeOp,
"path",
"pathB");
565void SkOpGlobalState::debugAddToGlobalCoinDicts() {
566 static SkMutex& mutex = *(
new SkMutex);
568 SkPathOpsDebug::gCoinSumChangedDict.add(fCoinChangedDict);
569 SkPathOpsDebug::gCoinSumVisitedDict.add(fCoinVisitedDict);
574#if DEBUG_T_SECT_LOOP_COUNT
577 for (
int index = 0; index < (
int)
std::size(fDebugLoopCount); ++index) {
579 if (fDebugLoopCount[index] >=
i->debugLoopCount(looper)) {
582 fDebugLoopCount[index] =
i->debugLoopCount(looper);
584 fDebugWorstVerb[index * 2 + 1] = wn.
segment()->
verb();
586 memcpy(&fDebugWorstPts[index * 2 * 4], wt.
pts(),
588 memcpy(&fDebugWorstPts[(index * 2 + 1) * 4], wn.
pts(),
590 fDebugWorstWeight[index * 2] = wt.
weight();
591 fDebugWorstWeight[index * 2 + 1] = wn.
weight();
593 i->debugResetLoopCount();
597 for (
int index = 0; index < (
int)
std::size(fDebugLoopCount); ++index) {
598 if (fDebugLoopCount[index] >=
local->fDebugLoopCount[index]) {
601 fDebugLoopCount[index] =
local->fDebugLoopCount[index];
602 fDebugWorstVerb[index * 2] =
local->fDebugWorstVerb[index * 2];
603 fDebugWorstVerb[index * 2 + 1] =
local->fDebugWorstVerb[index * 2 + 1];
604 memcpy(&fDebugWorstPts[index * 2 * 4], &
local->fDebugWorstPts[index * 2 * 4],
606 fDebugWorstWeight[index * 2] =
local->fDebugWorstWeight[index * 2];
607 fDebugWorstWeight[index * 2 + 1] =
local->fDebugWorstWeight[index * 2 + 1];
609 local->debugResetLoopCounts();
616 const char* verbs[] = {
"",
"line",
"quad",
"conic",
"cubic" };
619 for (
int index = 0; index <= ptCount; ++index) {
621 if (index < ptCount - 1) {
628 if (weight == floorf(weight)) {
637void SkOpGlobalState::debugLoopReport() {
638 const char* loops[] = {
"iterations",
"coinChecks",
"perpCalcs" };
640 for (
int index = 0; index < (
int)
std::size(fDebugLoopCount); ++index) {
641 SkDebugf(
"%s: %d\n", loops[index], fDebugLoopCount[index]);
642 dump_curve(fDebugWorstVerb[index * 2], fDebugWorstPts[index * 2 * 4],
643 fDebugWorstWeight[index * 2]);
644 dump_curve(fDebugWorstVerb[index * 2 + 1], fDebugWorstPts[(index * 2 + 1) * 4],
645 fDebugWorstWeight[index * 2 + 1]);
649void SkOpGlobalState::debugResetLoopCounts() {
650 sk_bzero(fDebugLoopCount,
sizeof(fDebugLoopCount));
651 sk_bzero(fDebugWorstVerb,
sizeof(fDebugWorstVerb));
652 sk_bzero(fDebugWorstPts,
sizeof(fDebugWorstPts));
653 sk_bzero(fDebugWorstWeight,
sizeof(fDebugWorstWeight));
662#if DEBUG_VALIDATE || DEBUG_COIN
669 SkPathOpsDebug::CoinDictEntry* entry = &writable->fCoinDictEntry;
670 writable->fPreviousFuncName = entry->fFunctionName;
671 entry->fIteration = iteration;
672 entry->fLineNumber = lineNo;
673 entry->fGlitchType = SkPathOpsDebug::kUninitialized_Glitch;
674 entry->fFunctionName = funcName;
675 writable->fCoinVisitedDict.add(*entry);
676 writable->debugAddToCoinChangedDict();
681#if DEBUG_T_SECT_LOOP_COUNT
683 fDebugLoopCount[index]++;
687 return fDebugLoopCount[index];
691 sk_bzero(fDebugLoopCount,
sizeof(fDebugLoopCount));
728 const SkOpPtT* SkOpSegment::debugAddT(
double t, SkPathOpsDebug::GlitchLog*
log)
const {
734 if (t ==
result->fT || this->match(
result,
this, t, pt)) {
738 if (t < result->fT) {
760void SkOpSegment::debugCheckAngleCoin()
const {
765 if (angle && angle->debugCheckCoincidence()) {
766 angle->debugCheckNearCoincidence();
771 span =
base->upCast();
773 if (angle && angle->debugCheckCoincidence()) {
774 angle->debugCheckNearCoincidence();
782void SkOpSegment::debugCheckHealth(SkPathOpsDebug::GlitchLog* glitches)
const {
783 debugMoveMultiples(glitches);
784 debugMoveNearby(glitches);
785 debugMissingCoincidence(glitches);
789void SkOpSegment::debugClearAll(SkPathOpsDebug::GlitchLog* glitches)
const {
792 this->debugClearOne(span, glitches);
798void SkOpSegment::debugClearOne(
const SkOpSpan* span, SkPathOpsDebug::GlitchLog* glitches)
const {
799 if (span->
windValue()) glitches->record(SkPathOpsDebug::kCollapsedWindValue_Glitch, span);
800 if (span->
oppValue()) glitches->record(SkPathOpsDebug::kCollapsedOppValue_Glitch, span);
801 if (!span->
done()) glitches->record(SkPathOpsDebug::kCollapsedDone_Glitch, span);
820void SkOpSegment::DebugClearVisited(
const SkOpSpanBase* span) {
823 const SkOpPtT* ptT = span->
ptT(), * stopPtT = ptT;
824 while ((ptT = ptT->
next()) != stopPtT) {
826 opp->resetDebugVisited();
843void SkOpSegment::debugMissingCoincidence(SkPathOpsDebug::GlitchLog*
log)
const {
851 const SkOpPtT* ptT = spanBase->
ptT(), * spanStopPtT = ptT;
853 while ((ptT = ptT->
next()) != spanStopPtT) {
862 if (!opp->debugVisited()) {
865 if (spanBase == &fHead) {
880 const SkOpPtT* priorPtT =
nullptr, * priorStopPtT;
884 while (!priorOpp && priorTest) {
885 priorStopPtT = priorPtT = priorTest->
ptT();
886 while ((priorPtT = priorPtT->
next()) != priorStopPtT) {
891 if (segment == opp) {
897 priorTest = priorTest->
prev();
902 if (priorPtT == ptT) {
907 bool swapped = priorPtT->
fT > ptT->
fT;
911 swap(oppStart, oppEnd);
918 if (coincidence->
contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) {
923#if DEBUG_COINCIDENCE_VERBOSE
928 log->record(SkPathOpsDebug::kMissingCoin_Glitch, priorPtT, ptT, oppStart, oppEnd);
942 }
while ((spanBase = spanBase->
final() ?
nullptr : spanBase->
upCast()->
next()));
943 DebugClearVisited(&fHead);
949void SkOpSegment::debugMoveMultiples(SkPathOpsDebug::GlitchLog* glitches)
const {
953 int addCount =
test->spanAddsCount();
959 const SkOpPtT* testPtT = startPtT;
969 if (oppSegment ==
this) {
975 while ((oppPrev = oppPrev->
prev())) {
989 while ((oppNext = oppNext->
final() ?
nullptr : oppNext->
upCast()->
next())) {
1001 if (oppFirst == oppLast) {
1006 if (oppTest == oppSpan) {
1012 const SkOpPtT* oppPtT = oppStartPtT;
1013 while ((oppPtT = oppPtT->
next()) != oppStartPtT) {
1015 if (oppPtTSegment ==
this) {
1018 const SkOpPtT* matchPtT = startPtT;
1020 if (matchPtT->
segment() == oppPtTSegment) {
1023 }
while ((matchPtT = matchPtT->
next()) != startPtT);
1027 oppTest->debugMergeMatches(glitches, oppSpan);
1028 oppTest->debugAddOpp(glitches, oppSpan);
1034 }
while (oppTest != oppLast && (oppTest = oppTest->
upCast()->
next()));
1035 }
while ((testPtT = testPtT->
next()) != startPtT);
1038 }
while ((
test =
test->final() ?
nullptr :
test->upCast()->next()));
1045void SkOpSegment::debugMoveNearby(SkPathOpsDebug::GlitchLog* glitches)
const {
1052 while ((ptT = ptT->
next()) != headPtT) {
1055 &&
test->ptT() == ptT) {
1056 if (
test->final()) {
1057 if (spanBase == &fHead) {
1058 glitches->record(SkPathOpsDebug::kMoveNearbyClearAll_Glitch,
this);
1061 glitches->record(SkPathOpsDebug::kMoveNearbyReleaseFinal_Glitch, spanBase, ptT);
1062 }
else if (
test->prev()) {
1063 glitches->record(SkPathOpsDebug::kMoveNearbyRelease_Glitch,
test, headPtT);
1069 }
while (!spanBase->
final());
1077 glitches->record(SkPathOpsDebug::kMoveNearbyMergeFinal_Glitch,
test);
1080 if (
test->final()) {
1081 if (spanBase->
prev()) {
1082 glitches->record(SkPathOpsDebug::kMoveNearbyMergeFinal_Glitch,
test);
1084 glitches->record(SkPathOpsDebug::kMoveNearbyClearAll2_Glitch,
this);
1088 glitches->record(SkPathOpsDebug::kMoveNearbyMerge_Glitch, spanBase);
1092 }
while (!spanBase->
final());
1101#if DEBUG_COINCIDENCE_ORDER
1102void SkOpSegment::debugSetCoinT(
int index,
SkScalar t)
const {
1103 if (fDebugBaseMax < 0 || fDebugBaseIndex == index) {
1104 fDebugBaseIndex = index;
1105 fDebugBaseMin =
std::min(t, fDebugBaseMin);
1106 fDebugBaseMax =
std::max(t, fDebugBaseMax);
1109 SkASSERT(fDebugBaseMin >= t || t >= fDebugBaseMax);
1110 if (fDebugLastMax < 0 || fDebugLastIndex == index) {
1111 fDebugLastIndex = index;
1112 fDebugLastMin =
std::min(t, fDebugLastMin);
1113 fDebugLastMax =
std::max(t, fDebugLastMax);
1116 SkASSERT(fDebugLastMin >= t || t >= fDebugLastMax);
1117 SkASSERT((t - fDebugBaseMin > 0) == (fDebugLastMin - fDebugBaseMin > 0));
1121#if DEBUG_ACTIVE_SPANS
1122void SkOpSegment::debugShowActiveSpans(
SkString* str)
const {
1134 if (lastId == this->
debugID() && lastT == span->
t()) {
1146 str->
appendf(
" %1.9g,%1.9g",
pts[vIndex].fX,
pts[vIndex].fY);
1151 str->
appendf(
") t=%1.9g tEnd=%1.9g", span->
t(), span->
next()->
t());
1172void SkOpSegment::debugShowNewWinding(
const char* fun,
const SkOpSpan* span,
int winding) {
1175 SkDebugf(
" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
1177 SkDebugf(
" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
1179 SkDebugf(
") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=",
1195void SkOpSegment::debugShowNewWinding(
const char* fun,
const SkOpSpan* span,
int winding,
1199 SkDebugf(
" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
1201 SkDebugf(
" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
1203 SkDebugf(
") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=",
1239void SkOpAngle::debugCheckNearCoincidence()
const {
1243 double testStartT =
test->start()->t();
1245 double testEndT =
test->end()->t();
1248 SkDebugf(
"%s testLenSq=%1.9g id=%d\n", __FUNCTION__, testLenSq, testSegment->
debugID());
1249 double testMidT = (testStartT + testEndT) / 2;
1251 while ((
next =
next->fNext) !=
this) {
1253 double testMidDistSq = testSegment->distSq(testMidT,
next);
1254 double testEndDistSq = testSegment->distSq(testEndT,
next);
1258 double nextEndT =
next->
end()->
t();
1259 double nextMidT = (nextStartT + nextEndT) / 2;
1260 double nextMidDistSq = nextSegment->distSq(nextMidT,
test);
1261 double nextEndDistSq = nextSegment->distSq(nextEndT,
test);
1262 SkDebugf(
"%s distSq=%1.9g testId=%d nextId=%d\n", __FUNCTION__, distSq,
1264 SkDebugf(
"%s testMidDistSq=%1.9g\n", __FUNCTION__, testMidDistSq);
1265 SkDebugf(
"%s testEndDistSq=%1.9g\n", __FUNCTION__, testEndDistSq);
1266 SkDebugf(
"%s nextMidDistSq=%1.9g\n", __FUNCTION__, nextMidDistSq);
1267 SkDebugf(
"%s nextEndDistSq=%1.9g\n", __FUNCTION__, nextEndDistSq);
1270 SkDebugf(
"%s nextLenSq=%1.9g\n", __FUNCTION__, nextLenSq);
1274 }
while (
test->fNext !=
this);
1279SkString SkOpAngle::debugPart()
const {
1281 switch (this->
segment()->verb()) {
1284 this->segment()->debugID());
1288 this->segment()->debugID());
1293 this->segment()->debugID());
1297 this->segment()->debugID());
1307void SkOpAngle::debugLoop()
const {
1324#if DEBUG_COINCIDENCE
1325 if (this->globalState()->debugCheckHealth()) {
1335 int lastOppXor = -1;
1350 bool useXor = op ? oppXor : isXor;
1351 SkASSERT(lastXor == -1 || lastXor == (
int) useXor);
1352 lastXor = (
int) useXor;
1357 useXor = op ? isXor : oppXor;
1358 SkASSERT(lastOppXor == -1 || lastOppXor == (
int) useXor);
1359 lastOppXor = (
int) useXor;
1380 if (
next == first) {
1401void SkCoincidentSpans::debugCorrectOneEnd(SkPathOpsDebug::GlitchLog*
log,
1404 const SkOpPtT* origPtT = (this->*getEnd)();
1409 if (origPtT != testPtT) {
1410 log->record(SkPathOpsDebug::kCorrectEnd_Glitch,
this, origPtT, testPtT);
1419void SkCoincidentSpans::debugCorrectEnds(SkPathOpsDebug::GlitchLog*
log)
const {
1428bool SkCoincidentSpans::debugExpand(SkPathOpsDebug::GlitchLog*
log)
const {
1429 bool expanded =
false;
1436 if (!
prev || !(oppPtT =
prev->contains(oppSegment))) {
1439 double midT = (
prev->t() +
start->t()) / 2;
1440 if (!segment->
isClose(midT, oppSegment)) {
1443 if (
log)
log->record(SkPathOpsDebug::kExpandCoin_Glitch,
this,
prev->ptT(), oppPtT);
1456 double midT = (
end->t() +
next->t()) / 2;
1457 if (!segment->
isClose(midT, oppSegment)) {
1460 if (
log)
log->record(SkPathOpsDebug::kExpandCoin_Glitch,
this,
next->ptT(), oppPtT);
1467void SkOpCoincidence::debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog*
log,
const SkOpSpan*
base,
const SkOpSpanBase* testSpan)
const {
1469 const SkOpPtT* stopPtT = testPtT;
1471 while ((testPtT = testPtT->
next()) != stopPtT) {
1476 if (testSeg == baseSeg) {
1479 if (testPtT->
span()->
ptT() != testPtT) {
1482 if (this->
contains(baseSeg, testSeg, testPtT->
fT)) {
1491 for (
int index = 0; index <
i.used(); ++index) {
1492 double t =
i[0][index];
1502 if (oppStart == testPtT) {
1512 double coinTs, coinTe, oppTs, oppTe;
1513 if (
Ordered(coinSeg, oppSeg)) {
1515 coinTe = testSpan->
t();
1516 oppTs = oppStart->
fT;
1517 oppTe = testPtT->
fT;
1520 swap(coinSeg, oppSeg);
1521 coinTs = oppStart->
fT;
1522 coinTe = testPtT->
fT;
1524 oppTe = testSpan->
t();
1526 if (coinTs > coinTe) {
1528 swap(coinTs, coinTe);
1532 this->debugAddOrOverlap(
log, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &added);
1539void SkOpCoincidence::debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog*
log,
const SkOpPtT* ptT)
const {
1544 if (!
prev->isCanceled()) {
1545 this->debugAddEndMovedSpans(
log,
base,
base->prev());
1547 if (!
base->isCanceled()) {
1548 this->debugAddEndMovedSpans(
log,
base,
base->next());
1562void SkOpCoincidence::debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog*
log)
const {
1578 }
else if (oOnEnd) {
1589 }
else if (oOnEnd) {
1593 }
while ((span = span->
next()));
1601void SkOpCoincidence::debugAddExpanded(SkPathOpsDebug::GlitchLog*
log)
const {
1610 double priorT = startPtT->
fT;
1611 double oPriorT = oStartPtT->
fT;
1626 while (
test !=
end || oTest != oEnd) {
1627 const SkOpPtT* containedOpp =
test->ptT()->contains(oSeg);
1629 if (!containedOpp || !containedThis) {
1631 double nextT, oNextT;
1634 oNextT = containedOpp->
fT;
1635 }
else if (containedThis) {
1636 nextT = containedThis->
fT;
1637 oNextT = oTest->
t();
1649 oNextT = walkOpp->
fT;
1652 double startRange = nextT - priorT;
1654 double startPart = (
test->t() - priorT) / startRange;
1655 double oStartRange = oNextT - oPriorT;
1657 double oStartPart = (oTest->
t() - oStartPtT->
fT) / oStartRange;
1659 bool addToOpp = !containedOpp && !containedThis ? startPart < oStartPart
1661 bool startOver =
false;
1662 addToOpp ?
log->record(SkPathOpsDebug::kAddExpandedCoin_Glitch,
1663 oPriorT + oStartRange * startPart,
test)
1664 :
log->record(SkPathOpsDebug::kAddExpandedCoin_Glitch,
1665 priorT + startRange * oStartPart, oTest);
1679 if (oTest != oEnd) {
1680 oPriorT = oTest->
t();
1685 }
while ((coin = coin->
next()));
1691void SkOpCoincidence::debugAddIfMissing(SkPathOpsDebug::GlitchLog*
log,
const SkOpPtT* over1s,
const SkOpPtT* over2s,
1707 double coinTs, coinTe, oppTs, oppTe;
1712 return log->record(SkPathOpsDebug::kAddIfCollapsed_Glitch, coinSeg);
1718 return log->record(SkPathOpsDebug::kAddIfCollapsed_Glitch, oppSeg);
1720 if (coinTs > coinTe) {
1722 swap(coinTs, coinTe);
1725 this->debugAddOrOverlap(
log, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added);
1732void SkOpCoincidence::debugAddOrOverlap(SkPathOpsDebug::GlitchLog*
log,
1734 double coinTs,
double coinTe,
double oppTs,
double oppTe,
bool* added)
const {
1737 if (fTop && !this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe,
1741 if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs,
1742 coinTe, oppTs, oppTe, &overlaps)) {
1746 for (
int index = 1; index < overlaps.
size(); ++index) {
1749 log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap,
test->coinPtTStart());
1752 log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap,
test->coinPtTEnd());
1757 log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap,
test->oppPtTStart());
1762 log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap,
test->oppPtTEnd());
1764 if (!fHead) { this->debugRelease(
log, fHead,
test);
1765 this->debugRelease(
log, fTop,
test);
1779 const SkOpPtT* csExisting = !cs ? coinSeg->
existing(coinTs,
nullptr) :
nullptr;
1780 const SkOpPtT* ceExisting = !ce ? coinSeg->
existing(coinTe,
nullptr) :
nullptr;
1783 csExisting->
contains(ceExisting ? ceExisting : ce)), coinSeg);
1785 ceExisting->
contains(csExisting ? csExisting : cs)), coinSeg);
1786 const SkOpPtT* osExisting = !os ? oppSeg->
existing(oppTs,
nullptr) :
nullptr;
1787 const SkOpPtT* oeExisting = !oe ? oppSeg->
existing(oppTe,
nullptr) :
nullptr;
1790 osExisting->
contains(oeExisting ? oeExisting : oe)), oppSeg);
1792 oeExisting->
contains(osExisting ? osExisting : os)), oppSeg);
1793 bool csDeleted =
false, osDeleted =
false, ceDeleted =
false, oeDeleted =
false;
1797 cs = coinSeg->debugAddT(coinTs,
log);
1799 os = oppSeg->debugAddT(oppTs,
log);
1801 if (cs && os) cs->
span()->debugAddOpp(
log, os->
span());
1808 ce = coinSeg->debugAddT(coinTe,
log);
1810 oe = oppSeg->debugAddT(oppTe,
log);
1811 if (ce && oe) ce->
span()->debugAddOpp(
log, oe->
span());
1824 log->record(SkPathOpsDebug::kAddMissingExtend_Glitch, coinSeg, coinTs, coinTe, oppSeg, oppTs, oppTe);
1826 if (oppTs > oppTe) {
1828 swap(coinTs, coinTe);
1831 log->record(SkPathOpsDebug::kAddMissingExtend_Glitch, oppSeg, oppTs, oppTe, coinSeg, coinTs, coinTe);
1833#if 0 && DEBUG_COINCIDENCE_VERBOSE
1839 log->record(SkPathOpsDebug::kAddMissingCoin_Glitch, coinSeg, coinTs, coinTe, oppSeg, oppTs, oppTe);
1840#if 0 && DEBUG_COINCIDENCE_VERBOSE
1852void SkOpCoincidence::debugAddMissing(SkPathOpsDebug::GlitchLog*
log,
bool* added)
const {
1877 while ((inner = inner->
next())) {
1879 double overS, overE;
1890 if (outerCoin == innerCoin) {
1897 if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) {
1899 overS, overE, outerOpp, innerOpp, added,
1903 }
else if (outerCoin == innerOpp) {
1908 if (outerOpp != innerCoin && this->overlap(ocs, oce,
ios, ioe, &overS, &overE)) {
1909 this->debugAddIfMissing(
log, ocs->
starter(oce),
ios->starter(ioe),
1910 overS, overE, outerOpp, innerCoin, added,
1912 ios->debugEnder(ioe));
1914 }
else if (outerOpp == innerCoin) {
1920 if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) {
1922 overS, overE, outerCoin, innerOpp, added,
1926 }
else if (outerOpp == innerOpp) {
1934 if (this->overlap(oos, ooe,
ios, ioe, &overS, &overE)) {
1935 this->debugAddIfMissing(
log, oos->
starter(ooe),
ios->starter(ioe),
1936 overS, overE, outerCoin, innerCoin, added,
1938 ios->debugEnder(ioe));
1943 }
while ((outer = outer->
next()));
1958 }
else if (
head == fHead) {
1963 log->record(SkPathOpsDebug::kReleasedSpan_Glitch, coin);
1966 }
while ((coin =
next));
1970void SkOpCoincidence::debugRelease(SkPathOpsDebug::GlitchLog*
log,
const SkOpSegment* deleted)
const {
1980 log->record(SkPathOpsDebug::kReleasedSpan_Glitch, coin);
1982 }
while ((coin = coin->
next()));
1987bool SkOpCoincidence::debugExpand(SkPathOpsDebug::GlitchLog*
log)
const {
1992 bool expanded =
false;
1994 if (coin->debugExpand(
log)) {
2003 if (
log)
log->record(SkPathOpsDebug::kExpandCoin_Glitch, fHead,
test->coinPtTStart());
2009 }
while ((coin = coin->
next()));
2015void SkOpCoincidence::debugMark(SkPathOpsDebug::GlitchLog*
log)
const {
2030 bool flipped = coin->
flipped();
2038 end->debugInsertCoinEnd(
log, oEnd);
2047 next->upCast()->debugInsertCoincidence(
log, oSegment, flipped, ordered);
2049 while ((oNext = oNext->
upCast()->
next()) != oEnd) {
2051 oNext->
upCast()->debugInsertCoincidence(
log, segment, flipped, ordered);
2053 }
while ((coin = coin->
next()));
2065 log->record(SkPathOpsDebug::kCollapsedCoin_Glitch, coin);
2068 log->record(SkPathOpsDebug::kCollapsedCoin_Glitch, coin);
2070 this->debugRelease(
log,
head, coin);
2072 coin = coin->
next();
2077void SkOpCoincidence::debugMarkCollapsed(SkPathOpsDebug::GlitchLog*
log,
const SkOpPtT*
test)
const {
2078 this->debugMarkCollapsed(
log, fHead,
test);
2079 this->debugMarkCollapsed(
log, fTop,
test);
2091#if DEBUG_COINCIDENCE
2095 span = span->
next();
2102 double oStart,
double oEnd,
const SkOpSegment* oSegment,
2103 SkPathOpsDebug::GlitchLog*
log) {
2113 bool somethingBetween =
false;
2118 if (ptT == checkPtT) {
2121 bool looped =
false;
2123 if ((looped = checkPtT == ptT)) {
2126 checkPtT = checkPtT->
next();
2135 if (ptT->
segment() != oSegment) {
2138 somethingBetween |=
between(oStart, ptT->
fT, oEnd);
2145 SkPathOpsDebug::GlitchLog*
log) {
2159 double tos =
test->oppPtTStart()->fT;
2161 double toe =
test->oppPtTEnd()->fT;
2169 double lcs, lce, los, loe;
2199 }
while ((list = list->
next()));
2204 SkPathOpsDebug::GlitchLog*
log) {
2210 DebugCheckOverlap(
test, opt,
log);
2216 SkPathOpsDebug::GlitchLog*
log) {
2226 coin = coin->
next();
2228 DebugCheckOverlapTop(
head, opt,
log);
2233#if DEBUG_COINCIDENCE
2234 DebugValidate(fHead, fTop,
nullptr);
2235 DebugValidate(fTop,
nullptr,
nullptr);
2241 SkPathOpsDebug::GlitchLog*
log) {
2251 coin = coin->
next();
2253 DebugCheckOverlapTop(
head, opt,
log);
2258#if DEBUG_COINCIDENCE
2259 if (fGlobalState->debugCheckHealth()) {
2262 DebugCheckBetween(fHead, fTop,
nullptr);
2263 DebugCheckBetween(fTop,
nullptr,
nullptr);
2268void SkOpContour::debugCheckHealth(SkPathOpsDebug::GlitchLog*
log)
const {
2271 segment->debugCheckHealth(
log);
2272 }
while ((segment = segment->
next()));
2275void SkOpCoincidence::debugCheckValid(SkPathOpsDebug::GlitchLog*
log)
const {
2277 DebugValidate(fHead, fTop,
log);
2278 DebugValidate(fTop,
nullptr,
log);
2282void SkOpCoincidence::debugCorrectEnds(SkPathOpsDebug::GlitchLog*
log)
const {
2288 coin->debugCorrectEnds(
log);
2289 }
while ((coin = coin->
next()));
2293void SkOpContour::debugMissingCoincidence(SkPathOpsDebug::GlitchLog*
log)
const {
2298 segment->debugMissingCoincidence(
log);
2299 segment = segment->
next();
2304void SkOpContour::debugMoveMultiples(SkPathOpsDebug::GlitchLog*
log)
const {
2308 segment->debugMoveMultiples(
log);
2309 }
while ((segment = segment->
next()));
2313void SkOpContour::debugMoveNearby(SkPathOpsDebug::GlitchLog*
log)
const {
2317 segment->debugMoveNearby(
log);
2318 }
while ((segment = segment->
next()));
2322#if DEBUG_COINCIDENCE_ORDER
2323void SkOpSegment::debugResetCoinT()
const {
2324 fDebugBaseIndex = -1;
2327 fDebugLastIndex = -1;
2334#if DEBUG_COINCIDENCE_ORDER
2347#if DEBUG_COINCIDENCE
2359 if (!span->
final()) {
2367 double t = span->
ptT()->
fT;
2383void SkOpSpanBase::debugAddOpp(SkPathOpsDebug::GlitchLog*
log,
const SkOpSpanBase* opp)
const {
2388 this->debugMergeMatches(
log, opp);
2390 this->debugCheckForCollapsedCoincidence(
log);
2394void SkOpSpanBase::debugCheckForCollapsedCoincidence(SkPathOpsDebug::GlitchLog*
log)
const {
2405 if (!
test->coincident()) {
2408 coins->debugMarkCollapsed(
log,
test);
2418 nextCoin =
next->fCoinEnd;
2423 for (
int inner =
check + 1; inner < loop; ++inner) {
2425 if (checkCoin == innerCoin) {
2426 SkDebugf(
"*** bad coincident end loop ***\n");
2432 }
while ((
next = nextCoin) &&
next !=
this);
2438void SkOpSpanBase::debugInsertCoinEnd(SkPathOpsDebug::GlitchLog*
log,
const SkOpSpanBase* coin)
const {
2445 log->record(SkPathOpsDebug::kMarkCoinEnd_Glitch,
this, coin);
2457void SkOpSpanBase::debugMergeMatches(SkPathOpsDebug::GlitchLog*
log,
const SkOpSpanBase* opp)
const {
2462 testNext =
test->next();
2463 if (
test->deleted()) {
2473 const SkOpPtT* innerStop = inner;
2487 log->record(SkPathOpsDebug::kMergeMatches_Glitch, innerBase,
test);
2491 log->record(SkPathOpsDebug::kMergeMatches_Glitch, testBase, inner);
2493 log->record(SkPathOpsDebug::kMergeMatches_Glitch,
segment);
2501 const SkOpPtT* debugInner = inner;
2502 while ((debugInner = debugInner->
next()) != innerStop) {
2515 }
while ((inner = inner->
next()) != innerStop);
2516 }
while ((
test = testNext) != stop);
2517 this->debugCheckForCollapsedCoincidence(
log);
2523#if DEBUG_COINCIDENCE_ORDER
2533#if DEBUG_COINCIDENCE_ORDER
2548 if (
t() <
end->t()) {
2558#if DEBUG_COINCIDENCE
2572 if (!this->
final()) {
2578 if (!this->
final() && this->
upCast()->toAngle()) {
2589 nextCoin =
next->fCoincident;
2590 SkASSERT(nextCoin ==
this || nextCoin->fCoincident != nextCoin);
2592 const SkOpSpan* checkCoin = this->fCoincident;
2593 const SkOpSpan* innerCoin = checkCoin;
2594 for (
int inner =
check + 1; inner < loop; ++inner) {
2595 innerCoin = innerCoin->fCoincident;
2596 if (checkCoin == innerCoin) {
2597 SkDebugf(
"*** bad coincident loop ***\n");
2603 }
while ((
next = nextCoin) &&
next !=
this);
2609void SkOpSpan::debugInsertCoincidence(SkPathOpsDebug::GlitchLog*
log,
const SkOpSpan* coin)
const {
2616 log->record(SkPathOpsDebug::kMarkCoinStart_Glitch,
this, coin);
2623void SkOpSpan::debugInsertCoincidence(SkPathOpsDebug::GlitchLog*
log,
const SkOpSegment* segment,
bool flipped,
bool ordered)
const {
2639 span =
base->prev();
2644 span =
base->upCast();
2646 log->record(SkPathOpsDebug::kMarkCoinInsert_Glitch, span);
2650 log->record(SkPathOpsDebug::kMarkCoinMissing_Glitch,
segment,
this);
2657 if (!fIsCoincident[0]) {
2663 for (
int index = 0; index < fUsed; ++index) {
2664 if (fIsCoincident[0] & (1 << index)) {
2668 if (fIsCoincident[1] & (1 << index)) {
2697 for (
int index = 0; index < links; ++index) {
2717 for (
int index = 0; index < links; ++index) {
2736 const SkOpPtT* innerPtT = checkPtT;
2737 for (
int inner =
check + 1; inner < loop; ++inner) {
2738 innerPtT = innerPtT->
fNext;
2739 if (checkPtT == innerPtT) {
2741 SkDebugf(
"*** bad ptT loop ***\n");
2750 if (++loop > 1000) {
2751 SkDebugf(
"*** loop count exceeds 1000 ***\n");
2763#if DEBUG_COINCIDENCE_ORDER
2764 this->
segment()->debugResetCoinT();
2769#if DEBUG_COINCIDENCE_ORDER
2770 this->
segment()->debugSetCoinT(index,
fT);
2775#if DEBUG_COINCIDENCE
2793 if (num == (
int) num) {
2797 str.
printf(
"%1.9g", num);
2799 const char* cStr = str.
c_str();
2800 while (cStr[
width - 1] ==
'0') {
2809 for (
int index = 0; index <
count; ++index) {
2813 if (index + 1 <
count) {
2838 SkDebugf(
" %s.conicTo(", pathName);
2843 SkDebugf(
" %s.cubicTo(", pathName);
2848 SkDebugf(
" %s.close();\n", pathName);
2865#define SUPPORT_RECT_CONTOUR_DETECTION 0
2866#if SUPPORT_RECT_CONTOUR_DETECTION
2867 int rectCount =
path.isRectContours() ?
path.rectContours(
nullptr,
nullptr) : 0;
2868 if (rectCount > 0) {
2871 rects.setCount(rectCount);
2872 directions.setCount(rectCount);
2876 SkDebugf(
"path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n",
rect.fLeft,
rect.fTop,
2878 ?
"SkPathDirection::kCCW" :
"SkPathDirection::kCW");
2885 if (includeDeclaration) {
2892#if DEBUG_DUMP_VERIFY
2896static void dump_path(FILE*
file,
const SkPath&
path,
bool dumpAsHex) {
2898 path.dump(&wStream, dumpAsHex);
2900 fprintf(
file,
"%.*s\n", (
int)
data->size(), (
char*)
data->data());
2903static int dumpID = 0;
2915 "\nstatic void %s_%d(skiatest::Reporter* reporter, const char* filename) {\n",
2917 fprintf(
file,
" SkPath path;\n");
2918 fprintf(
file,
" path.setFillType((SkPath::FillType) %d);\n", one.
getFillType());
2919 dump_path(
file, one,
true);
2920 fprintf(
file,
" SkPath path1(path);\n");
2921 fprintf(
file,
" path.reset();\n");
2922 fprintf(
file,
" path.setFillType((SkPath::FillType) %d);\n",
two.getFillType());
2924 fprintf(
file,
" SkPath path2(path);\n");
2925 fprintf(
file,
" testPathOp(reporter, path1, path2, (SkPathOp) %d, filename);\n", op);
2926 fprintf(
file,
"}\n\n");
2938 "\nstatic void %s_%d(skiatest::Reporter* reporter, const char* filename) {\n",
2940 fprintf(
file,
" SkPath path;\n");
2941 fprintf(
file,
" path.setFillType((SkPath::FillType) %d);\n",
path.getFillType());
2943 fprintf(
file,
" testSimplify(reporter, path, filename);\n");
2944 fprintf(
file,
"}\n\n");
2953const int bitWidth = 64;
2954const int bitHeight = 64;
2959 larger.
join(
two->getBounds());
2962 if (largerWidth < 4) {
2966 if (largerHeight < 4) {
2969 SkScalar hScale = (bitWidth - 2) / largerWidth;
2970 SkScalar vScale = (bitHeight - 2) / largerHeight;
2972 scale.preScale(hScale, vScale);
2973 larger.
fLeft *= hScale;
2975 larger.
fTop *= vScale;
2985 if (
bits.width() == 0) {
2986 bits.allocN32Pixels(bitWidth * 2, bitHeight);
2993 canvas.translate(-bounds1.
fLeft + 1, -bounds1.
fTop + 1);
2994 canvas.drawPath(one,
paint);
2997 canvas.translate(-bounds1.
fLeft + 1 + bitWidth, -bounds1.
fTop + 1);
3001 for (
int y = 0;
y < bitHeight - 1; ++
y) {
3002 uint32_t* addr1 =
bits.getAddr32(0,
y);
3003 uint32_t* addr2 =
bits.getAddr32(0,
y + 1);
3004 uint32_t* addr3 =
bits.getAddr32(bitWidth,
y);
3005 uint32_t* addr4 =
bits.getAddr32(bitWidth,
y + 1);
3006 for (
int x = 0;
x < bitWidth - 1; ++
x) {
3008 bool err = addr1[
x] != addr3[
x];
3010 errors += addr1[
x + 1] != addr3[
x + 1]
3011 && addr2[
x] != addr4[
x] && addr2[
x + 1] != addr4[
x + 1];
3019 SkDebugf(
"// Op did not expect failure\n");
3020 DumpOp(stderr, one,
two, op,
"opTest");
3026 SkPath pathOut, scaledPathOut;
3027 SkRegion rgnA, rgnB, openClip, rgnOut;
3028 openClip.
setRect({-16000, -16000, 16000, 16000});
3034 debug_scale_matrix(one, &
two,
scale);
3035 SkRegion scaledRgnA, scaledRgnB, scaledRgnOut;
3041 scaledRgnA.
setPath(scaledA, openClip);
3042 scaledRgnB.
setPath(scaledB, openClip);
3049 int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut,
bitmap);
3050 const int MAX_ERRORS = 9;
3051 if (
errors > MAX_ERRORS) {
3052 fprintf(stderr,
"// Op did not expect errors=%d\n",
errors);
3053 DumpOp(stderr, one,
two, op,
"opTest");
3059 SkDebugf(
"// Simplify did not expect failure\n");
3060 DumpSimplify(stderr,
path,
"simplifyTest");
3065 SkPath pathOut, scaledPathOut;
3067 openClip.
setRect({-16000, -16000, 16000, 16000});
3071 debug_scale_matrix(
path,
nullptr,
scale);
3076 scaledRgnA.
setPath(scaledA, openClip);
3082 int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut,
bitmap);
3083 const int MAX_ERRORS = 9;
3084 if (
errors > MAX_ERRORS) {
3085 fprintf(stderr,
"// Simplify did not expect errors=%d\n",
errors);
3086 DumpSimplify(stderr,
path,
"simplifyTest");
sk_bzero(glyphs, sizeof(glyphs))
static float next(float f)
static float prev(float f)
#define check(reporter, ref, unref, make, kill)
#define SkDEBUGFAIL(message)
#define SkASSERT_RELEASE(cond)
constexpr SkColor SK_ColorWHITE
void SK_SPI SkDebugf(const char format[],...) SK_PRINTF_LIKE(1
static constexpr bool SkIsNaN(T x)
static constexpr int32_t SK_MinS32
static constexpr int32_t SK_MaxS32
FILE * sk_fopen(const char path[], SkFILE_Flags)
static bool move_nearby(SkOpContourHead *contourList DEBUG_COIN_DECLARE_PARAMS())
static bool missing_coincidence(SkOpContourHead *contourList DEBUG_COIN_DECLARE_PARAMS())
static bool move_multiples(SkOpContourHead *contourList DEBUG_COIN_DECLARE_PARAMS())
static void(*const CurveIntersectRay[])(const SkPoint[], SkScalar, const SkDLine &, SkIntersections *)
static void output_points(const SkPoint *pts, int count)
static const char * gOpStrs[]
#define FAIL_WITH_NULL_IF(cond, span)
#define FAIL_IF_COIN(cond, coin)
void DumpHex(const SkPath &path)
static const char * gFillTypeStr[]
static void show_op(SkPathOp op, const char *pathOne, const char *pathTwo)
void Dump(const SkPath &path)
static void output_scalar(SkScalar num)
static void showPathContours(const SkPath &path, const char *pathName)
#define RETURN_FALSE_IF(cond, span)
static void show_function_header(const char *functionName)
#define CONIC_DEBUG_DATA(c, w)
#define DEBUG_LIMIT_WIND_SUM
#define DEBUG_COIN_DECLARE_PARAMS()
#define SkDEBUGPARAMS(...)
#define LINE_DEBUG_DATA(l)
#define CUBIC_DEBUG_DATA(c)
#define QUAD_DEBUG_DATA(q)
bool between(double a, double b, double c)
bool roughly_equal(double x, double y)
bool zero_or_one(double x)
int SkPathOpsVerbToPoints(SkPath::Verb verb)
@ kClose
SkPath::RawIter returns 0 points.
@ kCubic
SkPath::RawIter returns 4 points.
@ kConic
SkPath::RawIter returns 3 points + 1 weight.
@ kQuad
SkPath::RawIter returns 3 points.
@ kMove
SkPath::RawIter returns 1 point.
@ kLine
SkPath::RawIter returns 2 points.
void swap(sk_sp< T > &a, sk_sp< T > &b)
SkDEBUGCODE(SK_SPI) SkThreadID SkGetThreadID()
const SkOpPtT * oppPtTEnd() const
bool contains(const SkOpPtT *s, const SkOpPtT *e) const
SkCoincidentSpans * next()
SkOpPtT * oppPtTStartWritable() const
SkOpPtT * coinPtTStartWritable() const
const SkOpPtT * coinPtTEnd() const
SkOpPtT * coinPtTEndWritable() const
SkOpPtT * oppPtTEndWritable() const
const SkOpPtT * coinPtTStart() const
const char * debugID() const
bool ordered(bool *result) const
bool collapsed(const SkOpPtT *) const
const SkOpPtT * oppPtTStart() const
sk_sp< SkData > detachAsData()
SkOpSegment * segment() const
const SkPoint * pts() const
int debugLoopCount(DebugLoop) const
int debugCoincidentUsed() const
void debugResetLoopCount()
void debugBumpLoopCount(DebugLoop)
SkOpSegment * segment() const
SkOpSpanBase * end() const
void dumpOne(bool functionHeader) const
void debugValidate() const
void debugValidateNext() const
SkOpSpanBase * start() const
void debugShowCoincidence() const
bool contains(const SkOpPtT *coinPtTStart, const SkOpPtT *coinPtTEnd, const SkOpPtT *oppPtTStart, const SkOpPtT *oppPtTEnd) const
void debugCheckBetween() const
static bool Ordered(const SkOpPtT *coinPtTStart, const SkOpPtT *oppPtTStart)
void debugValidate() const
SkOpGlobalState * globalState() const
void setPhase(SkOpPhase phase)
SkOpCoincidence * coincidence()
static bool DebugRunFail()
void setAllocatedOpSpan()
const SkOpSpanBase * span() const
const SkOpPtT * next() const
SkOpGlobalState * globalState() const
int debugLoopLimit(bool report) const
void debugValidate() const
SkOpPtT * oppPrev(const SkOpPtT *opp) const
bool debugContains(const SkOpPtT *) const
const SkOpSegment * segment() const
void debugSetCoinT(int) const
void debugResetCoinT() const
SkOpContour * contour() const
void debugAddOpp(const SkOpPtT *opp, const SkOpPtT *oppPrev) const
const SkOpPtT * debugEnder(const SkOpPtT *end) const
const SkOpPtT * debugOppPrev(const SkOpPtT *opp) const
bool contains(const SkOpPtT *) const
const SkOpPtT * starter(const SkOpPtT *end) const
SkDVector dSlopeAtT(double mid) const
void debugValidate() const
SkOpSpanBase::Collapsed collapsed(double startT, double endT) const
SkPath::Verb verb() const
bool testForCoincidence(const SkOpPtT *priorPtT, const SkOpPtT *ptT, const SkOpSpanBase *prior, const SkOpSpanBase *spanBase, const SkOpSegment *opp) const
bool isClose(double t, const SkOpSegment *opp) const
SkPoint ptAtT(double mid) const
const SkOpSegment * prev() const
void init(SkPoint pts[], SkScalar weight, SkOpContour *parent, SkPath::Verb verb)
SkOpAngle * debugLastAngle()
SkOpGlobalState * globalState() const
bool subDivide(const SkOpSpanBase *start, const SkOpSpanBase *end, SkDCurve *result) const
const SkOpPtT * existing(double t, const SkOpSegment *opp) const
const SkOpSpan * head() const
SkDPoint dPtAtT(double mid) const
const SkPoint * pts() const
SkOpSegment * next() const
SkOpContour * contour() const
bool spansNearby(const SkOpSpanBase *ref, const SkOpSpanBase *check, bool *found) const
const SkOpSpan * prev() const
void debugValidate() const
bool containsCoinEnd(const SkOpSpanBase *coin) const
int spanAddsCount() const
SkOpGlobalState * globalState() const
bool addOpp(SkOpSpanBase *opp)
const SkOpSpan * debugStarter(SkOpSpanBase const **endPtr) const
void debugResetCoinT() const
bool debugCoinEndLoopCheck() const
bool contains(const SkOpSpanBase *) const
const SkOpSpan * starter(const SkOpSpanBase *end) const
void debugSetCoinT(int) const
SkOpSegment * segment() const
const SkOpPtT * ptT() const
SkOpSpanBase * next() const
SkOpAngle * toAngle() const
bool containsCoincidence(const SkOpSegment *) const
bool debugCoinLoopCheck() const
static void ShowPath(const SkPath &one, const SkPath &two, SkPathOp op, const char *name)
static const char * OpStr(SkPathOp)
static void ShowActiveSpans(SkOpContourHead *contourList)
static void MathematicaIze(char *str, size_t bufferSize)
static void ShowOnePath(const SkPath &path, const char *name, bool includeDeclaration)
static bool ValidWind(int winding)
static void CheckHealth(class SkOpContourHead *contourList)
static bool ChaseContains(const SkTDArray< SkOpSpanBase * > &, const SkOpSpanBase *)
static void WindingPrintf(int winding)
SkPathFillType getFillType() const
void setFillType(SkPathFillType ft)
SkPath & addPath(const SkPath &src, SkScalar dx, SkScalar dy, AddPathMode mode=kAppend_AddPathMode)
const SkRect & getBounds() const
bool getBoundaryPath(SkPath *path) const
bool op(const SkIRect &rect, Op op)
bool setRect(const SkIRect &rect)
bool setPath(const SkPath &path, const SkRegion &clip)
void printf(const char format[],...) SK_PRINTF_LIKE(2
const char * c_str() const
void void void appendf(const char format[],...) SK_PRINTF_LIKE(2
void push_back(const T &v)
static float max(float r, float g, float b)
static float min(float r, float g, float b)
sk_sp< SkBlender > blender SkRect rect
skia_private::AutoTArray< sk_sp< SkImageFilter > > filters TypedMatrix matrix TypedMatrix matrix SkScalar dx
SK_API sk_sp< SkSurface > ios(9.0)
DEF_SWITCHES_START aot vmservice shared library Name of the *so containing AOT compiled Dart assets for launching the service isolate vm snapshot The VM snapshot data that will be memory mapped as read only SnapshotAssetPath must be present isolate snapshot The isolate snapshot data that will be memory mapped as read only SnapshotAssetPath must be present cache dir path
DEF_SWITCHES_START aot vmservice shared library name
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
void debugSet(const SkDPoint *pts, SkScalar weight)
void debugSet(const SkDPoint *pts)
SkDPoint fPts[kPointCount]
double distanceSquared(const SkDPoint &a) const
bool approximatelyEqual(const SkDPoint &a) const
static void Dump(const SkPoint &pt)
void debugSet(const SkDPoint *pts)
SkDPoint fPts[kPointCount]
SkDCubic debugToCubic() const
SkScalar fBottom
larger y-axis bounds
SkScalar fLeft
smaller x-axis bounds
SkScalar fRight
larger x-axis bounds
constexpr float height() const
constexpr float width() const
void join(const SkRect &r)
SkScalar fTop
smaller y-axis bounds
std::shared_ptr< const fml::Mapping > data