1cb93a386Sopenharmony_ci/* 2cb93a386Sopenharmony_ci * Copyright 2013 Google Inc. 3cb93a386Sopenharmony_ci * 4cb93a386Sopenharmony_ci * Use of this source code is governed by a BSD-style license that can be 5cb93a386Sopenharmony_ci * found in the LICENSE file. 6cb93a386Sopenharmony_ci */ 7cb93a386Sopenharmony_ci 8cb93a386Sopenharmony_ci#include "include/core/SkPath.h" 9cb93a386Sopenharmony_ci#include "include/core/SkString.h" 10cb93a386Sopenharmony_ci#include "include/private/SkMutex.h" 11cb93a386Sopenharmony_ci#include "src/core/SkOSFile.h" 12cb93a386Sopenharmony_ci#include "src/core/SkPathPriv.h" 13cb93a386Sopenharmony_ci#include "src/pathops/SkOpCoincidence.h" 14cb93a386Sopenharmony_ci#include "src/pathops/SkOpContour.h" 15cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsDebug.h" 16cb93a386Sopenharmony_ci 17cb93a386Sopenharmony_ci#include <utility> 18cb93a386Sopenharmony_ci 19cb93a386Sopenharmony_ci#if DEBUG_DUMP_VERIFY 20cb93a386Sopenharmony_cibool SkPathOpsDebug::gDumpOp; // set to true to write op to file before a crash 21cb93a386Sopenharmony_cibool SkPathOpsDebug::gVerifyOp; // set to true to compare result against regions 22cb93a386Sopenharmony_ci#endif 23cb93a386Sopenharmony_ci 24cb93a386Sopenharmony_cibool SkPathOpsDebug::gRunFail; // set to true to check for success on tests known to fail 25cb93a386Sopenharmony_cibool SkPathOpsDebug::gVeryVerbose; // set to true to run extensive checking tests 26cb93a386Sopenharmony_ci 27cb93a386Sopenharmony_ci#undef FAIL_IF 28cb93a386Sopenharmony_ci#define FAIL_IF(cond, coin) \ 29cb93a386Sopenharmony_ci do { if (cond) log->record(SkPathOpsDebug::kFail_Glitch, coin); } while (false) 30cb93a386Sopenharmony_ci 31cb93a386Sopenharmony_ci#undef FAIL_WITH_NULL_IF 32cb93a386Sopenharmony_ci#define FAIL_WITH_NULL_IF(cond, span) \ 33cb93a386Sopenharmony_ci do { if (cond) log->record(SkPathOpsDebug::kFail_Glitch, span); } while (false) 34cb93a386Sopenharmony_ci 35cb93a386Sopenharmony_ci#define RETURN_FALSE_IF(cond, span) \ 36cb93a386Sopenharmony_ci do { if (cond) log->record(SkPathOpsDebug::kReturnFalse_Glitch, span); \ 37cb93a386Sopenharmony_ci } while (false) 38cb93a386Sopenharmony_ci 39cb93a386Sopenharmony_ciclass SkCoincidentSpans; 40cb93a386Sopenharmony_ci 41cb93a386Sopenharmony_ci#if DEBUG_SORT 42cb93a386Sopenharmony_ciint SkPathOpsDebug::gSortCountDefault = SK_MaxS32; 43cb93a386Sopenharmony_ciint SkPathOpsDebug::gSortCount; 44cb93a386Sopenharmony_ci#endif 45cb93a386Sopenharmony_ci 46cb93a386Sopenharmony_ci#if DEBUG_ACTIVE_OP 47cb93a386Sopenharmony_ciconst char* SkPathOpsDebug::kPathOpStr[] = {"diff", "sect", "union", "xor", "rdiff"}; 48cb93a386Sopenharmony_ci#endif 49cb93a386Sopenharmony_ci 50cb93a386Sopenharmony_ci#if defined SK_DEBUG || !FORCE_RELEASE 51cb93a386Sopenharmony_ci 52cb93a386Sopenharmony_ciint SkPathOpsDebug::gContourID = 0; 53cb93a386Sopenharmony_ciint SkPathOpsDebug::gSegmentID = 0; 54cb93a386Sopenharmony_ci 55cb93a386Sopenharmony_cibool SkPathOpsDebug::ChaseContains(const SkTDArray<SkOpSpanBase* >& chaseArray, 56cb93a386Sopenharmony_ci const SkOpSpanBase* span) { 57cb93a386Sopenharmony_ci for (int index = 0; index < chaseArray.count(); ++index) { 58cb93a386Sopenharmony_ci const SkOpSpanBase* entry = chaseArray[index]; 59cb93a386Sopenharmony_ci if (entry == span) { 60cb93a386Sopenharmony_ci return true; 61cb93a386Sopenharmony_ci } 62cb93a386Sopenharmony_ci } 63cb93a386Sopenharmony_ci return false; 64cb93a386Sopenharmony_ci} 65cb93a386Sopenharmony_ci#endif 66cb93a386Sopenharmony_ci 67cb93a386Sopenharmony_ci#if DEBUG_ACTIVE_SPANS 68cb93a386Sopenharmony_ciSkString SkPathOpsDebug::gActiveSpans; 69cb93a386Sopenharmony_ci#endif 70cb93a386Sopenharmony_ci 71cb93a386Sopenharmony_ci#if DEBUG_COIN 72cb93a386Sopenharmony_ci 73cb93a386Sopenharmony_ciSkPathOpsDebug::CoinDict SkPathOpsDebug::gCoinSumChangedDict; 74cb93a386Sopenharmony_ciSkPathOpsDebug::CoinDict SkPathOpsDebug::gCoinSumVisitedDict; 75cb93a386Sopenharmony_ci 76cb93a386Sopenharmony_cistatic const int kGlitchType_Count = SkPathOpsDebug::kUnalignedTail_Glitch + 1; 77cb93a386Sopenharmony_ci 78cb93a386Sopenharmony_cistruct SpanGlitch { 79cb93a386Sopenharmony_ci const SkOpSpanBase* fBase; 80cb93a386Sopenharmony_ci const SkOpSpanBase* fSuspect; 81cb93a386Sopenharmony_ci const SkOpSegment* fSegment; 82cb93a386Sopenharmony_ci const SkOpSegment* fOppSegment; 83cb93a386Sopenharmony_ci const SkOpPtT* fCoinSpan; 84cb93a386Sopenharmony_ci const SkOpPtT* fEndSpan; 85cb93a386Sopenharmony_ci const SkOpPtT* fOppSpan; 86cb93a386Sopenharmony_ci const SkOpPtT* fOppEndSpan; 87cb93a386Sopenharmony_ci double fStartT; 88cb93a386Sopenharmony_ci double fEndT; 89cb93a386Sopenharmony_ci double fOppStartT; 90cb93a386Sopenharmony_ci double fOppEndT; 91cb93a386Sopenharmony_ci SkPoint fPt; 92cb93a386Sopenharmony_ci SkPathOpsDebug::GlitchType fType; 93cb93a386Sopenharmony_ci 94cb93a386Sopenharmony_ci void dumpType() const; 95cb93a386Sopenharmony_ci}; 96cb93a386Sopenharmony_ci 97cb93a386Sopenharmony_cistruct SkPathOpsDebug::GlitchLog { 98cb93a386Sopenharmony_ci void init(const SkOpGlobalState* state) { 99cb93a386Sopenharmony_ci fGlobalState = state; 100cb93a386Sopenharmony_ci } 101cb93a386Sopenharmony_ci 102cb93a386Sopenharmony_ci SpanGlitch* recordCommon(GlitchType type) { 103cb93a386Sopenharmony_ci SpanGlitch* glitch = fGlitches.push(); 104cb93a386Sopenharmony_ci glitch->fBase = nullptr; 105cb93a386Sopenharmony_ci glitch->fSuspect = nullptr; 106cb93a386Sopenharmony_ci glitch->fSegment = nullptr; 107cb93a386Sopenharmony_ci glitch->fOppSegment = nullptr; 108cb93a386Sopenharmony_ci glitch->fCoinSpan = nullptr; 109cb93a386Sopenharmony_ci glitch->fEndSpan = nullptr; 110cb93a386Sopenharmony_ci glitch->fOppSpan = nullptr; 111cb93a386Sopenharmony_ci glitch->fOppEndSpan = nullptr; 112cb93a386Sopenharmony_ci glitch->fStartT = SK_ScalarNaN; 113cb93a386Sopenharmony_ci glitch->fEndT = SK_ScalarNaN; 114cb93a386Sopenharmony_ci glitch->fOppStartT = SK_ScalarNaN; 115cb93a386Sopenharmony_ci glitch->fOppEndT = SK_ScalarNaN; 116cb93a386Sopenharmony_ci glitch->fPt = { SK_ScalarNaN, SK_ScalarNaN }; 117cb93a386Sopenharmony_ci glitch->fType = type; 118cb93a386Sopenharmony_ci return glitch; 119cb93a386Sopenharmony_ci } 120cb93a386Sopenharmony_ci 121cb93a386Sopenharmony_ci void record(GlitchType type, const SkOpSpanBase* base, 122cb93a386Sopenharmony_ci const SkOpSpanBase* suspect = NULL) { 123cb93a386Sopenharmony_ci SpanGlitch* glitch = recordCommon(type); 124cb93a386Sopenharmony_ci glitch->fBase = base; 125cb93a386Sopenharmony_ci glitch->fSuspect = suspect; 126cb93a386Sopenharmony_ci } 127cb93a386Sopenharmony_ci 128cb93a386Sopenharmony_ci void record(GlitchType type, const SkOpSpanBase* base, 129cb93a386Sopenharmony_ci const SkOpPtT* ptT) { 130cb93a386Sopenharmony_ci SpanGlitch* glitch = recordCommon(type); 131cb93a386Sopenharmony_ci glitch->fBase = base; 132cb93a386Sopenharmony_ci glitch->fCoinSpan = ptT; 133cb93a386Sopenharmony_ci } 134cb93a386Sopenharmony_ci 135cb93a386Sopenharmony_ci void record(GlitchType type, const SkCoincidentSpans* coin, 136cb93a386Sopenharmony_ci const SkCoincidentSpans* opp = NULL) { 137cb93a386Sopenharmony_ci SpanGlitch* glitch = recordCommon(type); 138cb93a386Sopenharmony_ci glitch->fCoinSpan = coin->coinPtTStart(); 139cb93a386Sopenharmony_ci glitch->fEndSpan = coin->coinPtTEnd(); 140cb93a386Sopenharmony_ci if (opp) { 141cb93a386Sopenharmony_ci glitch->fOppSpan = opp->coinPtTStart(); 142cb93a386Sopenharmony_ci glitch->fOppEndSpan = opp->coinPtTEnd(); 143cb93a386Sopenharmony_ci } 144cb93a386Sopenharmony_ci } 145cb93a386Sopenharmony_ci 146cb93a386Sopenharmony_ci void record(GlitchType type, const SkOpSpanBase* base, 147cb93a386Sopenharmony_ci const SkOpSegment* seg, double t, SkPoint pt) { 148cb93a386Sopenharmony_ci SpanGlitch* glitch = recordCommon(type); 149cb93a386Sopenharmony_ci glitch->fBase = base; 150cb93a386Sopenharmony_ci glitch->fSegment = seg; 151cb93a386Sopenharmony_ci glitch->fStartT = t; 152cb93a386Sopenharmony_ci glitch->fPt = pt; 153cb93a386Sopenharmony_ci } 154cb93a386Sopenharmony_ci 155cb93a386Sopenharmony_ci void record(GlitchType type, const SkOpSpanBase* base, double t, 156cb93a386Sopenharmony_ci SkPoint pt) { 157cb93a386Sopenharmony_ci SpanGlitch* glitch = recordCommon(type); 158cb93a386Sopenharmony_ci glitch->fBase = base; 159cb93a386Sopenharmony_ci glitch->fStartT = t; 160cb93a386Sopenharmony_ci glitch->fPt = pt; 161cb93a386Sopenharmony_ci } 162cb93a386Sopenharmony_ci 163cb93a386Sopenharmony_ci void record(GlitchType type, const SkCoincidentSpans* coin, 164cb93a386Sopenharmony_ci const SkOpPtT* coinSpan, const SkOpPtT* endSpan) { 165cb93a386Sopenharmony_ci SpanGlitch* glitch = recordCommon(type); 166cb93a386Sopenharmony_ci glitch->fCoinSpan = coin->coinPtTStart(); 167cb93a386Sopenharmony_ci glitch->fEndSpan = coin->coinPtTEnd(); 168cb93a386Sopenharmony_ci glitch->fEndSpan = endSpan; 169cb93a386Sopenharmony_ci glitch->fOppSpan = coinSpan; 170cb93a386Sopenharmony_ci glitch->fOppEndSpan = endSpan; 171cb93a386Sopenharmony_ci } 172cb93a386Sopenharmony_ci 173cb93a386Sopenharmony_ci void record(GlitchType type, const SkCoincidentSpans* coin, 174cb93a386Sopenharmony_ci const SkOpSpanBase* base) { 175cb93a386Sopenharmony_ci SpanGlitch* glitch = recordCommon(type); 176cb93a386Sopenharmony_ci glitch->fBase = base; 177cb93a386Sopenharmony_ci glitch->fCoinSpan = coin->coinPtTStart(); 178cb93a386Sopenharmony_ci glitch->fEndSpan = coin->coinPtTEnd(); 179cb93a386Sopenharmony_ci } 180cb93a386Sopenharmony_ci 181cb93a386Sopenharmony_ci void record(GlitchType type, const SkOpPtT* ptTS, const SkOpPtT* ptTE, 182cb93a386Sopenharmony_ci const SkOpPtT* oPtTS, const SkOpPtT* oPtTE) { 183cb93a386Sopenharmony_ci SpanGlitch* glitch = recordCommon(type); 184cb93a386Sopenharmony_ci glitch->fCoinSpan = ptTS; 185cb93a386Sopenharmony_ci glitch->fEndSpan = ptTE; 186cb93a386Sopenharmony_ci glitch->fOppSpan = oPtTS; 187cb93a386Sopenharmony_ci glitch->fOppEndSpan = oPtTE; 188cb93a386Sopenharmony_ci } 189cb93a386Sopenharmony_ci 190cb93a386Sopenharmony_ci void record(GlitchType type, const SkOpSegment* seg, double startT, 191cb93a386Sopenharmony_ci double endT, const SkOpSegment* oppSeg, double oppStartT, double oppEndT) { 192cb93a386Sopenharmony_ci SpanGlitch* glitch = recordCommon(type); 193cb93a386Sopenharmony_ci glitch->fSegment = seg; 194cb93a386Sopenharmony_ci glitch->fStartT = startT; 195cb93a386Sopenharmony_ci glitch->fEndT = endT; 196cb93a386Sopenharmony_ci glitch->fOppSegment = oppSeg; 197cb93a386Sopenharmony_ci glitch->fOppStartT = oppStartT; 198cb93a386Sopenharmony_ci glitch->fOppEndT = oppEndT; 199cb93a386Sopenharmony_ci } 200cb93a386Sopenharmony_ci 201cb93a386Sopenharmony_ci void record(GlitchType type, const SkOpSegment* seg, 202cb93a386Sopenharmony_ci const SkOpSpan* span) { 203cb93a386Sopenharmony_ci SpanGlitch* glitch = recordCommon(type); 204cb93a386Sopenharmony_ci glitch->fSegment = seg; 205cb93a386Sopenharmony_ci glitch->fBase = span; 206cb93a386Sopenharmony_ci } 207cb93a386Sopenharmony_ci 208cb93a386Sopenharmony_ci void record(GlitchType type, double t, const SkOpSpanBase* span) { 209cb93a386Sopenharmony_ci SpanGlitch* glitch = recordCommon(type); 210cb93a386Sopenharmony_ci glitch->fStartT = t; 211cb93a386Sopenharmony_ci glitch->fBase = span; 212cb93a386Sopenharmony_ci } 213cb93a386Sopenharmony_ci 214cb93a386Sopenharmony_ci void record(GlitchType type, const SkOpSegment* seg) { 215cb93a386Sopenharmony_ci SpanGlitch* glitch = recordCommon(type); 216cb93a386Sopenharmony_ci glitch->fSegment = seg; 217cb93a386Sopenharmony_ci } 218cb93a386Sopenharmony_ci 219cb93a386Sopenharmony_ci void record(GlitchType type, const SkCoincidentSpans* coin, 220cb93a386Sopenharmony_ci const SkOpPtT* ptT) { 221cb93a386Sopenharmony_ci SpanGlitch* glitch = recordCommon(type); 222cb93a386Sopenharmony_ci glitch->fCoinSpan = coin->coinPtTStart(); 223cb93a386Sopenharmony_ci glitch->fEndSpan = ptT; 224cb93a386Sopenharmony_ci } 225cb93a386Sopenharmony_ci 226cb93a386Sopenharmony_ci SkTDArray<SpanGlitch> fGlitches; 227cb93a386Sopenharmony_ci const SkOpGlobalState* fGlobalState; 228cb93a386Sopenharmony_ci}; 229cb93a386Sopenharmony_ci 230cb93a386Sopenharmony_ci 231cb93a386Sopenharmony_civoid SkPathOpsDebug::CoinDict::add(const SkPathOpsDebug::CoinDict& dict) { 232cb93a386Sopenharmony_ci int count = dict.fDict.count(); 233cb93a386Sopenharmony_ci for (int index = 0; index < count; ++index) { 234cb93a386Sopenharmony_ci this->add(dict.fDict[index]); 235cb93a386Sopenharmony_ci } 236cb93a386Sopenharmony_ci} 237cb93a386Sopenharmony_ci 238cb93a386Sopenharmony_civoid SkPathOpsDebug::CoinDict::add(const CoinDictEntry& key) { 239cb93a386Sopenharmony_ci int count = fDict.count(); 240cb93a386Sopenharmony_ci for (int index = 0; index < count; ++index) { 241cb93a386Sopenharmony_ci CoinDictEntry* entry = &fDict[index]; 242cb93a386Sopenharmony_ci if (entry->fIteration == key.fIteration && entry->fLineNumber == key.fLineNumber) { 243cb93a386Sopenharmony_ci SkASSERT(!strcmp(entry->fFunctionName, key.fFunctionName)); 244cb93a386Sopenharmony_ci if (entry->fGlitchType == kUninitialized_Glitch) { 245cb93a386Sopenharmony_ci entry->fGlitchType = key.fGlitchType; 246cb93a386Sopenharmony_ci } 247cb93a386Sopenharmony_ci return; 248cb93a386Sopenharmony_ci } 249cb93a386Sopenharmony_ci } 250cb93a386Sopenharmony_ci *fDict.append() = key; 251cb93a386Sopenharmony_ci} 252cb93a386Sopenharmony_ci 253cb93a386Sopenharmony_ci#endif 254cb93a386Sopenharmony_ci 255cb93a386Sopenharmony_ci#if DEBUG_COIN 256cb93a386Sopenharmony_cistatic void missing_coincidence(SkPathOpsDebug::GlitchLog* glitches, const SkOpContourHead* contourList) { 257cb93a386Sopenharmony_ci const SkOpContour* contour = contourList; 258cb93a386Sopenharmony_ci // bool result = false; 259cb93a386Sopenharmony_ci do { 260cb93a386Sopenharmony_ci /* result |= */ contour->debugMissingCoincidence(glitches); 261cb93a386Sopenharmony_ci } while ((contour = contour->next())); 262cb93a386Sopenharmony_ci return; 263cb93a386Sopenharmony_ci} 264cb93a386Sopenharmony_ci 265cb93a386Sopenharmony_cistatic void move_multiples(SkPathOpsDebug::GlitchLog* glitches, const SkOpContourHead* contourList) { 266cb93a386Sopenharmony_ci const SkOpContour* contour = contourList; 267cb93a386Sopenharmony_ci do { 268cb93a386Sopenharmony_ci if (contour->debugMoveMultiples(glitches), false) { 269cb93a386Sopenharmony_ci return; 270cb93a386Sopenharmony_ci } 271cb93a386Sopenharmony_ci } while ((contour = contour->next())); 272cb93a386Sopenharmony_ci return; 273cb93a386Sopenharmony_ci} 274cb93a386Sopenharmony_ci 275cb93a386Sopenharmony_cistatic void move_nearby(SkPathOpsDebug::GlitchLog* glitches, const SkOpContourHead* contourList) { 276cb93a386Sopenharmony_ci const SkOpContour* contour = contourList; 277cb93a386Sopenharmony_ci do { 278cb93a386Sopenharmony_ci contour->debugMoveNearby(glitches); 279cb93a386Sopenharmony_ci } while ((contour = contour->next())); 280cb93a386Sopenharmony_ci} 281cb93a386Sopenharmony_ci 282cb93a386Sopenharmony_ci 283cb93a386Sopenharmony_ci#endif 284cb93a386Sopenharmony_ci 285cb93a386Sopenharmony_ci#if DEBUG_COIN 286cb93a386Sopenharmony_civoid SkOpGlobalState::debugAddToCoinChangedDict() { 287cb93a386Sopenharmony_ci 288cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE 289cb93a386Sopenharmony_ci SkPathOpsDebug::CheckHealth(fContourHead); 290cb93a386Sopenharmony_ci#endif 291cb93a386Sopenharmony_ci // see if next coincident operation makes a change; if so, record it 292cb93a386Sopenharmony_ci SkPathOpsDebug::GlitchLog glitches; 293cb93a386Sopenharmony_ci const char* funcName = fCoinDictEntry.fFunctionName; 294cb93a386Sopenharmony_ci if (!strcmp("calc_angles", funcName)) { 295cb93a386Sopenharmony_ci ; 296cb93a386Sopenharmony_ci } else if (!strcmp("missing_coincidence", funcName)) { 297cb93a386Sopenharmony_ci missing_coincidence(&glitches, fContourHead); 298cb93a386Sopenharmony_ci } else if (!strcmp("move_multiples", funcName)) { 299cb93a386Sopenharmony_ci move_multiples(&glitches, fContourHead); 300cb93a386Sopenharmony_ci } else if (!strcmp("move_nearby", funcName)) { 301cb93a386Sopenharmony_ci move_nearby(&glitches, fContourHead); 302cb93a386Sopenharmony_ci } else if (!strcmp("addExpanded", funcName)) { 303cb93a386Sopenharmony_ci fCoincidence->debugAddExpanded(&glitches); 304cb93a386Sopenharmony_ci } else if (!strcmp("addMissing", funcName)) { 305cb93a386Sopenharmony_ci bool added; 306cb93a386Sopenharmony_ci fCoincidence->debugAddMissing(&glitches, &added); 307cb93a386Sopenharmony_ci } else if (!strcmp("addEndMovedSpans", funcName)) { 308cb93a386Sopenharmony_ci fCoincidence->debugAddEndMovedSpans(&glitches); 309cb93a386Sopenharmony_ci } else if (!strcmp("correctEnds", funcName)) { 310cb93a386Sopenharmony_ci fCoincidence->debugCorrectEnds(&glitches); 311cb93a386Sopenharmony_ci } else if (!strcmp("expand", funcName)) { 312cb93a386Sopenharmony_ci fCoincidence->debugExpand(&glitches); 313cb93a386Sopenharmony_ci } else if (!strcmp("findOverlaps", funcName)) { 314cb93a386Sopenharmony_ci ; 315cb93a386Sopenharmony_ci } else if (!strcmp("mark", funcName)) { 316cb93a386Sopenharmony_ci fCoincidence->debugMark(&glitches); 317cb93a386Sopenharmony_ci } else if (!strcmp("apply", funcName)) { 318cb93a386Sopenharmony_ci ; 319cb93a386Sopenharmony_ci } else { 320cb93a386Sopenharmony_ci SkASSERT(0); // add missing case 321cb93a386Sopenharmony_ci } 322cb93a386Sopenharmony_ci if (glitches.fGlitches.count()) { 323cb93a386Sopenharmony_ci fCoinDictEntry.fGlitchType = glitches.fGlitches[0].fType; 324cb93a386Sopenharmony_ci } 325cb93a386Sopenharmony_ci fCoinChangedDict.add(fCoinDictEntry); 326cb93a386Sopenharmony_ci} 327cb93a386Sopenharmony_ci#endif 328cb93a386Sopenharmony_ci 329cb93a386Sopenharmony_civoid SkPathOpsDebug::ShowActiveSpans(SkOpContourHead* contourList) { 330cb93a386Sopenharmony_ci#if DEBUG_ACTIVE_SPANS 331cb93a386Sopenharmony_ci SkString str; 332cb93a386Sopenharmony_ci SkOpContour* contour = contourList; 333cb93a386Sopenharmony_ci do { 334cb93a386Sopenharmony_ci contour->debugShowActiveSpans(&str); 335cb93a386Sopenharmony_ci } while ((contour = contour->next())); 336cb93a386Sopenharmony_ci if (!gActiveSpans.equals(str)) { 337cb93a386Sopenharmony_ci const char* s = str.c_str(); 338cb93a386Sopenharmony_ci const char* end; 339cb93a386Sopenharmony_ci while ((end = strchr(s, '\n'))) { 340cb93a386Sopenharmony_ci SkDebugf("%.*s", end - s + 1, s); 341cb93a386Sopenharmony_ci s = end + 1; 342cb93a386Sopenharmony_ci } 343cb93a386Sopenharmony_ci gActiveSpans.set(str); 344cb93a386Sopenharmony_ci } 345cb93a386Sopenharmony_ci#endif 346cb93a386Sopenharmony_ci} 347cb93a386Sopenharmony_ci 348cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE || DEBUG_COIN 349cb93a386Sopenharmony_civoid SkPathOpsDebug::CheckHealth(SkOpContourHead* contourList) { 350cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE 351cb93a386Sopenharmony_ci contourList->globalState()->debugSetCheckHealth(true); 352cb93a386Sopenharmony_ci#endif 353cb93a386Sopenharmony_ci#if DEBUG_COIN 354cb93a386Sopenharmony_ci GlitchLog glitches; 355cb93a386Sopenharmony_ci const SkOpContour* contour = contourList; 356cb93a386Sopenharmony_ci const SkOpCoincidence* coincidence = contour->globalState()->coincidence(); 357cb93a386Sopenharmony_ci coincidence->debugCheckValid(&glitches); // don't call validate; spans may be inconsistent 358cb93a386Sopenharmony_ci do { 359cb93a386Sopenharmony_ci contour->debugCheckHealth(&glitches); 360cb93a386Sopenharmony_ci contour->debugMissingCoincidence(&glitches); 361cb93a386Sopenharmony_ci } while ((contour = contour->next())); 362cb93a386Sopenharmony_ci bool added; 363cb93a386Sopenharmony_ci coincidence->debugAddMissing(&glitches, &added); 364cb93a386Sopenharmony_ci coincidence->debugExpand(&glitches); 365cb93a386Sopenharmony_ci coincidence->debugAddExpanded(&glitches); 366cb93a386Sopenharmony_ci coincidence->debugMark(&glitches); 367cb93a386Sopenharmony_ci unsigned mask = 0; 368cb93a386Sopenharmony_ci for (int index = 0; index < glitches.fGlitches.count(); ++index) { 369cb93a386Sopenharmony_ci const SpanGlitch& glitch = glitches.fGlitches[index]; 370cb93a386Sopenharmony_ci mask |= 1 << glitch.fType; 371cb93a386Sopenharmony_ci } 372cb93a386Sopenharmony_ci for (int index = 0; index < kGlitchType_Count; ++index) { 373cb93a386Sopenharmony_ci SkDebugf(mask & (1 << index) ? "x" : "-"); 374cb93a386Sopenharmony_ci } 375cb93a386Sopenharmony_ci SkDebugf(" %s\n", contourList->globalState()->debugCoinDictEntry().fFunctionName); 376cb93a386Sopenharmony_ci for (int index = 0; index < glitches.fGlitches.count(); ++index) { 377cb93a386Sopenharmony_ci const SpanGlitch& glitch = glitches.fGlitches[index]; 378cb93a386Sopenharmony_ci SkDebugf("%02d: ", index); 379cb93a386Sopenharmony_ci if (glitch.fBase) { 380cb93a386Sopenharmony_ci SkDebugf(" seg/base=%d/%d", glitch.fBase->segment()->debugID(), 381cb93a386Sopenharmony_ci glitch.fBase->debugID()); 382cb93a386Sopenharmony_ci } 383cb93a386Sopenharmony_ci if (glitch.fSuspect) { 384cb93a386Sopenharmony_ci SkDebugf(" seg/base=%d/%d", glitch.fSuspect->segment()->debugID(), 385cb93a386Sopenharmony_ci glitch.fSuspect->debugID()); 386cb93a386Sopenharmony_ci } 387cb93a386Sopenharmony_ci if (glitch.fSegment) { 388cb93a386Sopenharmony_ci SkDebugf(" segment=%d", glitch.fSegment->debugID()); 389cb93a386Sopenharmony_ci } 390cb93a386Sopenharmony_ci if (glitch.fCoinSpan) { 391cb93a386Sopenharmony_ci SkDebugf(" coinSeg/Span/PtT=%d/%d/%d", glitch.fCoinSpan->segment()->debugID(), 392cb93a386Sopenharmony_ci glitch.fCoinSpan->span()->debugID(), glitch.fCoinSpan->debugID()); 393cb93a386Sopenharmony_ci } 394cb93a386Sopenharmony_ci if (glitch.fEndSpan) { 395cb93a386Sopenharmony_ci SkDebugf(" endSpan=%d", glitch.fEndSpan->debugID()); 396cb93a386Sopenharmony_ci } 397cb93a386Sopenharmony_ci if (glitch.fOppSpan) { 398cb93a386Sopenharmony_ci SkDebugf(" oppSeg/Span/PtT=%d/%d/%d", glitch.fOppSpan->segment()->debugID(), 399cb93a386Sopenharmony_ci glitch.fOppSpan->span()->debugID(), glitch.fOppSpan->debugID()); 400cb93a386Sopenharmony_ci } 401cb93a386Sopenharmony_ci if (glitch.fOppEndSpan) { 402cb93a386Sopenharmony_ci SkDebugf(" oppEndSpan=%d", glitch.fOppEndSpan->debugID()); 403cb93a386Sopenharmony_ci } 404cb93a386Sopenharmony_ci if (!SkScalarIsNaN(glitch.fStartT)) { 405cb93a386Sopenharmony_ci SkDebugf(" startT=%g", glitch.fStartT); 406cb93a386Sopenharmony_ci } 407cb93a386Sopenharmony_ci if (!SkScalarIsNaN(glitch.fEndT)) { 408cb93a386Sopenharmony_ci SkDebugf(" endT=%g", glitch.fEndT); 409cb93a386Sopenharmony_ci } 410cb93a386Sopenharmony_ci if (glitch.fOppSegment) { 411cb93a386Sopenharmony_ci SkDebugf(" segment=%d", glitch.fOppSegment->debugID()); 412cb93a386Sopenharmony_ci } 413cb93a386Sopenharmony_ci if (!SkScalarIsNaN(glitch.fOppStartT)) { 414cb93a386Sopenharmony_ci SkDebugf(" oppStartT=%g", glitch.fOppStartT); 415cb93a386Sopenharmony_ci } 416cb93a386Sopenharmony_ci if (!SkScalarIsNaN(glitch.fOppEndT)) { 417cb93a386Sopenharmony_ci SkDebugf(" oppEndT=%g", glitch.fOppEndT); 418cb93a386Sopenharmony_ci } 419cb93a386Sopenharmony_ci if (!SkScalarIsNaN(glitch.fPt.fX) || !SkScalarIsNaN(glitch.fPt.fY)) { 420cb93a386Sopenharmony_ci SkDebugf(" pt=%g,%g", glitch.fPt.fX, glitch.fPt.fY); 421cb93a386Sopenharmony_ci } 422cb93a386Sopenharmony_ci DumpGlitchType(glitch.fType); 423cb93a386Sopenharmony_ci SkDebugf("\n"); 424cb93a386Sopenharmony_ci } 425cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE 426cb93a386Sopenharmony_ci contourList->globalState()->debugSetCheckHealth(false); 427cb93a386Sopenharmony_ci#endif 428cb93a386Sopenharmony_ci#if 01 && DEBUG_ACTIVE_SPANS 429cb93a386Sopenharmony_ci// SkDebugf("active after %s:\n", id); 430cb93a386Sopenharmony_ci ShowActiveSpans(contourList); 431cb93a386Sopenharmony_ci#endif 432cb93a386Sopenharmony_ci#endif 433cb93a386Sopenharmony_ci} 434cb93a386Sopenharmony_ci#endif 435cb93a386Sopenharmony_ci 436cb93a386Sopenharmony_ci#if DEBUG_COIN 437cb93a386Sopenharmony_civoid SkPathOpsDebug::DumpGlitchType(GlitchType glitchType) { 438cb93a386Sopenharmony_ci switch (glitchType) { 439cb93a386Sopenharmony_ci case kAddCorruptCoin_Glitch: SkDebugf(" AddCorruptCoin"); break; 440cb93a386Sopenharmony_ci case kAddExpandedCoin_Glitch: SkDebugf(" AddExpandedCoin"); break; 441cb93a386Sopenharmony_ci case kAddExpandedFail_Glitch: SkDebugf(" AddExpandedFail"); break; 442cb93a386Sopenharmony_ci case kAddIfCollapsed_Glitch: SkDebugf(" AddIfCollapsed"); break; 443cb93a386Sopenharmony_ci case kAddIfMissingCoin_Glitch: SkDebugf(" AddIfMissingCoin"); break; 444cb93a386Sopenharmony_ci case kAddMissingCoin_Glitch: SkDebugf(" AddMissingCoin"); break; 445cb93a386Sopenharmony_ci case kAddMissingExtend_Glitch: SkDebugf(" AddMissingExtend"); break; 446cb93a386Sopenharmony_ci case kAddOrOverlap_Glitch: SkDebugf(" AAddOrOverlap"); break; 447cb93a386Sopenharmony_ci case kCollapsedCoin_Glitch: SkDebugf(" CollapsedCoin"); break; 448cb93a386Sopenharmony_ci case kCollapsedDone_Glitch: SkDebugf(" CollapsedDone"); break; 449cb93a386Sopenharmony_ci case kCollapsedOppValue_Glitch: SkDebugf(" CollapsedOppValue"); break; 450cb93a386Sopenharmony_ci case kCollapsedSpan_Glitch: SkDebugf(" CollapsedSpan"); break; 451cb93a386Sopenharmony_ci case kCollapsedWindValue_Glitch: SkDebugf(" CollapsedWindValue"); break; 452cb93a386Sopenharmony_ci case kCorrectEnd_Glitch: SkDebugf(" CorrectEnd"); break; 453cb93a386Sopenharmony_ci case kDeletedCoin_Glitch: SkDebugf(" DeletedCoin"); break; 454cb93a386Sopenharmony_ci case kExpandCoin_Glitch: SkDebugf(" ExpandCoin"); break; 455cb93a386Sopenharmony_ci case kFail_Glitch: SkDebugf(" Fail"); break; 456cb93a386Sopenharmony_ci case kMarkCoinEnd_Glitch: SkDebugf(" MarkCoinEnd"); break; 457cb93a386Sopenharmony_ci case kMarkCoinInsert_Glitch: SkDebugf(" MarkCoinInsert"); break; 458cb93a386Sopenharmony_ci case kMarkCoinMissing_Glitch: SkDebugf(" MarkCoinMissing"); break; 459cb93a386Sopenharmony_ci case kMarkCoinStart_Glitch: SkDebugf(" MarkCoinStart"); break; 460cb93a386Sopenharmony_ci case kMergeMatches_Glitch: SkDebugf(" MergeMatches"); break; 461cb93a386Sopenharmony_ci case kMissingCoin_Glitch: SkDebugf(" MissingCoin"); break; 462cb93a386Sopenharmony_ci case kMissingDone_Glitch: SkDebugf(" MissingDone"); break; 463cb93a386Sopenharmony_ci case kMissingIntersection_Glitch: SkDebugf(" MissingIntersection"); break; 464cb93a386Sopenharmony_ci case kMoveMultiple_Glitch: SkDebugf(" MoveMultiple"); break; 465cb93a386Sopenharmony_ci case kMoveNearbyClearAll_Glitch: SkDebugf(" MoveNearbyClearAll"); break; 466cb93a386Sopenharmony_ci case kMoveNearbyClearAll2_Glitch: SkDebugf(" MoveNearbyClearAll2"); break; 467cb93a386Sopenharmony_ci case kMoveNearbyMerge_Glitch: SkDebugf(" MoveNearbyMerge"); break; 468cb93a386Sopenharmony_ci case kMoveNearbyMergeFinal_Glitch: SkDebugf(" MoveNearbyMergeFinal"); break; 469cb93a386Sopenharmony_ci case kMoveNearbyRelease_Glitch: SkDebugf(" MoveNearbyRelease"); break; 470cb93a386Sopenharmony_ci case kMoveNearbyReleaseFinal_Glitch: SkDebugf(" MoveNearbyReleaseFinal"); break; 471cb93a386Sopenharmony_ci case kReleasedSpan_Glitch: SkDebugf(" ReleasedSpan"); break; 472cb93a386Sopenharmony_ci case kReturnFalse_Glitch: SkDebugf(" ReturnFalse"); break; 473cb93a386Sopenharmony_ci case kUnaligned_Glitch: SkDebugf(" Unaligned"); break; 474cb93a386Sopenharmony_ci case kUnalignedHead_Glitch: SkDebugf(" UnalignedHead"); break; 475cb93a386Sopenharmony_ci case kUnalignedTail_Glitch: SkDebugf(" UnalignedTail"); break; 476cb93a386Sopenharmony_ci case kUninitialized_Glitch: break; 477cb93a386Sopenharmony_ci default: SkASSERT(0); 478cb93a386Sopenharmony_ci } 479cb93a386Sopenharmony_ci} 480cb93a386Sopenharmony_ci#endif 481cb93a386Sopenharmony_ci 482cb93a386Sopenharmony_ci#if defined SK_DEBUG || !FORCE_RELEASE 483cb93a386Sopenharmony_civoid SkPathOpsDebug::MathematicaIze(char* str, size_t bufferLen) { 484cb93a386Sopenharmony_ci size_t len = strlen(str); 485cb93a386Sopenharmony_ci bool num = false; 486cb93a386Sopenharmony_ci for (size_t idx = 0; idx < len; ++idx) { 487cb93a386Sopenharmony_ci if (num && str[idx] == 'e') { 488cb93a386Sopenharmony_ci if (len + 2 >= bufferLen) { 489cb93a386Sopenharmony_ci return; 490cb93a386Sopenharmony_ci } 491cb93a386Sopenharmony_ci memmove(&str[idx + 2], &str[idx + 1], len - idx); 492cb93a386Sopenharmony_ci str[idx] = '*'; 493cb93a386Sopenharmony_ci str[idx + 1] = '^'; 494cb93a386Sopenharmony_ci ++len; 495cb93a386Sopenharmony_ci } 496cb93a386Sopenharmony_ci num = str[idx] >= '0' && str[idx] <= '9'; 497cb93a386Sopenharmony_ci } 498cb93a386Sopenharmony_ci} 499cb93a386Sopenharmony_ci 500cb93a386Sopenharmony_cibool SkPathOpsDebug::ValidWind(int wind) { 501cb93a386Sopenharmony_ci return wind > SK_MinS32 + 0xFFFF && wind < SK_MaxS32 - 0xFFFF; 502cb93a386Sopenharmony_ci} 503cb93a386Sopenharmony_ci 504cb93a386Sopenharmony_civoid SkPathOpsDebug::WindingPrintf(int wind) { 505cb93a386Sopenharmony_ci if (wind == SK_MinS32) { 506cb93a386Sopenharmony_ci SkDebugf("?"); 507cb93a386Sopenharmony_ci } else { 508cb93a386Sopenharmony_ci SkDebugf("%d", wind); 509cb93a386Sopenharmony_ci } 510cb93a386Sopenharmony_ci} 511cb93a386Sopenharmony_ci#endif // defined SK_DEBUG || !FORCE_RELEASE 512cb93a386Sopenharmony_ci 513cb93a386Sopenharmony_ci 514cb93a386Sopenharmony_cistatic void show_function_header(const char* functionName) { 515cb93a386Sopenharmony_ci SkDebugf("\nstatic void %s(skiatest::Reporter* reporter, const char* filename) {\n", functionName); 516cb93a386Sopenharmony_ci if (strcmp("skphealth_com76", functionName) == 0) { 517cb93a386Sopenharmony_ci SkDebugf("found it\n"); 518cb93a386Sopenharmony_ci } 519cb93a386Sopenharmony_ci} 520cb93a386Sopenharmony_ci 521cb93a386Sopenharmony_cistatic const char* gOpStrs[] = { 522cb93a386Sopenharmony_ci "kDifference_SkPathOp", 523cb93a386Sopenharmony_ci "kIntersect_SkPathOp", 524cb93a386Sopenharmony_ci "kUnion_SkPathOp", 525cb93a386Sopenharmony_ci "kXOR_PathOp", 526cb93a386Sopenharmony_ci "kReverseDifference_SkPathOp", 527cb93a386Sopenharmony_ci}; 528cb93a386Sopenharmony_ci 529cb93a386Sopenharmony_ciconst char* SkPathOpsDebug::OpStr(SkPathOp op) { 530cb93a386Sopenharmony_ci return gOpStrs[op]; 531cb93a386Sopenharmony_ci} 532cb93a386Sopenharmony_ci 533cb93a386Sopenharmony_cistatic void show_op(SkPathOp op, const char* pathOne, const char* pathTwo) { 534cb93a386Sopenharmony_ci SkDebugf(" testPathOp(reporter, %s, %s, %s, filename);\n", pathOne, pathTwo, gOpStrs[op]); 535cb93a386Sopenharmony_ci SkDebugf("}\n"); 536cb93a386Sopenharmony_ci} 537cb93a386Sopenharmony_ci 538cb93a386Sopenharmony_civoid SkPathOpsDebug::ShowPath(const SkPath& a, const SkPath& b, SkPathOp shapeOp, 539cb93a386Sopenharmony_ci const char* testName) { 540cb93a386Sopenharmony_ci static SkMutex& mutex = *(new SkMutex); 541cb93a386Sopenharmony_ci 542cb93a386Sopenharmony_ci SkAutoMutexExclusive ac(mutex); 543cb93a386Sopenharmony_ci show_function_header(testName); 544cb93a386Sopenharmony_ci ShowOnePath(a, "path", true); 545cb93a386Sopenharmony_ci ShowOnePath(b, "pathB", true); 546cb93a386Sopenharmony_ci show_op(shapeOp, "path", "pathB"); 547cb93a386Sopenharmony_ci} 548cb93a386Sopenharmony_ci 549cb93a386Sopenharmony_ci#include "src/pathops/SkIntersectionHelper.h" 550cb93a386Sopenharmony_ci#include "src/pathops/SkIntersections.h" 551cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsTypes.h" 552cb93a386Sopenharmony_ci 553cb93a386Sopenharmony_ci#if DEBUG_COIN 554cb93a386Sopenharmony_ci 555cb93a386Sopenharmony_civoid SkOpGlobalState::debugAddToGlobalCoinDicts() { 556cb93a386Sopenharmony_ci static SkMutex& mutex = *(new SkMutex); 557cb93a386Sopenharmony_ci SkAutoMutexExclusive ac(mutex); 558cb93a386Sopenharmony_ci SkPathOpsDebug::gCoinSumChangedDict.add(fCoinChangedDict); 559cb93a386Sopenharmony_ci SkPathOpsDebug::gCoinSumVisitedDict.add(fCoinVisitedDict); 560cb93a386Sopenharmony_ci} 561cb93a386Sopenharmony_ci 562cb93a386Sopenharmony_ci#endif 563cb93a386Sopenharmony_ci 564cb93a386Sopenharmony_ci#if DEBUG_T_SECT_LOOP_COUNT 565cb93a386Sopenharmony_civoid SkOpGlobalState::debugAddLoopCount(SkIntersections* i, const SkIntersectionHelper& wt, 566cb93a386Sopenharmony_ci const SkIntersectionHelper& wn) { 567cb93a386Sopenharmony_ci for (int index = 0; index < (int) SK_ARRAY_COUNT(fDebugLoopCount); ++index) { 568cb93a386Sopenharmony_ci SkIntersections::DebugLoop looper = (SkIntersections::DebugLoop) index; 569cb93a386Sopenharmony_ci if (fDebugLoopCount[index] >= i->debugLoopCount(looper)) { 570cb93a386Sopenharmony_ci continue; 571cb93a386Sopenharmony_ci } 572cb93a386Sopenharmony_ci fDebugLoopCount[index] = i->debugLoopCount(looper); 573cb93a386Sopenharmony_ci fDebugWorstVerb[index * 2] = wt.segment()->verb(); 574cb93a386Sopenharmony_ci fDebugWorstVerb[index * 2 + 1] = wn.segment()->verb(); 575cb93a386Sopenharmony_ci sk_bzero(&fDebugWorstPts[index * 8], sizeof(SkPoint) * 8); 576cb93a386Sopenharmony_ci memcpy(&fDebugWorstPts[index * 2 * 4], wt.pts(), 577cb93a386Sopenharmony_ci (SkPathOpsVerbToPoints(wt.segment()->verb()) + 1) * sizeof(SkPoint)); 578cb93a386Sopenharmony_ci memcpy(&fDebugWorstPts[(index * 2 + 1) * 4], wn.pts(), 579cb93a386Sopenharmony_ci (SkPathOpsVerbToPoints(wn.segment()->verb()) + 1) * sizeof(SkPoint)); 580cb93a386Sopenharmony_ci fDebugWorstWeight[index * 2] = wt.weight(); 581cb93a386Sopenharmony_ci fDebugWorstWeight[index * 2 + 1] = wn.weight(); 582cb93a386Sopenharmony_ci } 583cb93a386Sopenharmony_ci i->debugResetLoopCount(); 584cb93a386Sopenharmony_ci} 585cb93a386Sopenharmony_ci 586cb93a386Sopenharmony_civoid SkOpGlobalState::debugDoYourWorst(SkOpGlobalState* local) { 587cb93a386Sopenharmony_ci for (int index = 0; index < (int) SK_ARRAY_COUNT(fDebugLoopCount); ++index) { 588cb93a386Sopenharmony_ci if (fDebugLoopCount[index] >= local->fDebugLoopCount[index]) { 589cb93a386Sopenharmony_ci continue; 590cb93a386Sopenharmony_ci } 591cb93a386Sopenharmony_ci fDebugLoopCount[index] = local->fDebugLoopCount[index]; 592cb93a386Sopenharmony_ci fDebugWorstVerb[index * 2] = local->fDebugWorstVerb[index * 2]; 593cb93a386Sopenharmony_ci fDebugWorstVerb[index * 2 + 1] = local->fDebugWorstVerb[index * 2 + 1]; 594cb93a386Sopenharmony_ci memcpy(&fDebugWorstPts[index * 2 * 4], &local->fDebugWorstPts[index * 2 * 4], 595cb93a386Sopenharmony_ci sizeof(SkPoint) * 8); 596cb93a386Sopenharmony_ci fDebugWorstWeight[index * 2] = local->fDebugWorstWeight[index * 2]; 597cb93a386Sopenharmony_ci fDebugWorstWeight[index * 2 + 1] = local->fDebugWorstWeight[index * 2 + 1]; 598cb93a386Sopenharmony_ci } 599cb93a386Sopenharmony_ci local->debugResetLoopCounts(); 600cb93a386Sopenharmony_ci} 601cb93a386Sopenharmony_ci 602cb93a386Sopenharmony_cistatic void dump_curve(SkPath::Verb verb, const SkPoint& pts, float weight) { 603cb93a386Sopenharmony_ci if (!verb) { 604cb93a386Sopenharmony_ci return; 605cb93a386Sopenharmony_ci } 606cb93a386Sopenharmony_ci const char* verbs[] = { "", "line", "quad", "conic", "cubic" }; 607cb93a386Sopenharmony_ci SkDebugf("%s: {{", verbs[verb]); 608cb93a386Sopenharmony_ci int ptCount = SkPathOpsVerbToPoints(verb); 609cb93a386Sopenharmony_ci for (int index = 0; index <= ptCount; ++index) { 610cb93a386Sopenharmony_ci SkDPoint::Dump((&pts)[index]); 611cb93a386Sopenharmony_ci if (index < ptCount - 1) { 612cb93a386Sopenharmony_ci SkDebugf(", "); 613cb93a386Sopenharmony_ci } 614cb93a386Sopenharmony_ci } 615cb93a386Sopenharmony_ci SkDebugf("}"); 616cb93a386Sopenharmony_ci if (weight != 1) { 617cb93a386Sopenharmony_ci SkDebugf(", "); 618cb93a386Sopenharmony_ci if (weight == floorf(weight)) { 619cb93a386Sopenharmony_ci SkDebugf("%.0f", weight); 620cb93a386Sopenharmony_ci } else { 621cb93a386Sopenharmony_ci SkDebugf("%1.9gf", weight); 622cb93a386Sopenharmony_ci } 623cb93a386Sopenharmony_ci } 624cb93a386Sopenharmony_ci SkDebugf("}\n"); 625cb93a386Sopenharmony_ci} 626cb93a386Sopenharmony_ci 627cb93a386Sopenharmony_civoid SkOpGlobalState::debugLoopReport() { 628cb93a386Sopenharmony_ci const char* loops[] = { "iterations", "coinChecks", "perpCalcs" }; 629cb93a386Sopenharmony_ci SkDebugf("\n"); 630cb93a386Sopenharmony_ci for (int index = 0; index < (int) SK_ARRAY_COUNT(fDebugLoopCount); ++index) { 631cb93a386Sopenharmony_ci SkDebugf("%s: %d\n", loops[index], fDebugLoopCount[index]); 632cb93a386Sopenharmony_ci dump_curve(fDebugWorstVerb[index * 2], fDebugWorstPts[index * 2 * 4], 633cb93a386Sopenharmony_ci fDebugWorstWeight[index * 2]); 634cb93a386Sopenharmony_ci dump_curve(fDebugWorstVerb[index * 2 + 1], fDebugWorstPts[(index * 2 + 1) * 4], 635cb93a386Sopenharmony_ci fDebugWorstWeight[index * 2 + 1]); 636cb93a386Sopenharmony_ci } 637cb93a386Sopenharmony_ci} 638cb93a386Sopenharmony_ci 639cb93a386Sopenharmony_civoid SkOpGlobalState::debugResetLoopCounts() { 640cb93a386Sopenharmony_ci sk_bzero(fDebugLoopCount, sizeof(fDebugLoopCount)); 641cb93a386Sopenharmony_ci sk_bzero(fDebugWorstVerb, sizeof(fDebugWorstVerb)); 642cb93a386Sopenharmony_ci sk_bzero(fDebugWorstPts, sizeof(fDebugWorstPts)); 643cb93a386Sopenharmony_ci sk_bzero(fDebugWorstWeight, sizeof(fDebugWorstWeight)); 644cb93a386Sopenharmony_ci} 645cb93a386Sopenharmony_ci#endif 646cb93a386Sopenharmony_ci 647cb93a386Sopenharmony_cibool SkOpGlobalState::DebugRunFail() { 648cb93a386Sopenharmony_ci return SkPathOpsDebug::gRunFail; 649cb93a386Sopenharmony_ci} 650cb93a386Sopenharmony_ci 651cb93a386Sopenharmony_ci// this is const so it can be called by const methods that overwise don't alter state 652cb93a386Sopenharmony_ci#if DEBUG_VALIDATE || DEBUG_COIN 653cb93a386Sopenharmony_civoid SkOpGlobalState::debugSetPhase(const char* funcName DEBUG_COIN_DECLARE_PARAMS()) const { 654cb93a386Sopenharmony_ci auto writable = const_cast<SkOpGlobalState*>(this); 655cb93a386Sopenharmony_ci#if DEBUG_VALIDATE 656cb93a386Sopenharmony_ci writable->setPhase(phase); 657cb93a386Sopenharmony_ci#endif 658cb93a386Sopenharmony_ci#if DEBUG_COIN 659cb93a386Sopenharmony_ci SkPathOpsDebug::CoinDictEntry* entry = &writable->fCoinDictEntry; 660cb93a386Sopenharmony_ci writable->fPreviousFuncName = entry->fFunctionName; 661cb93a386Sopenharmony_ci entry->fIteration = iteration; 662cb93a386Sopenharmony_ci entry->fLineNumber = lineNo; 663cb93a386Sopenharmony_ci entry->fGlitchType = SkPathOpsDebug::kUninitialized_Glitch; 664cb93a386Sopenharmony_ci entry->fFunctionName = funcName; 665cb93a386Sopenharmony_ci writable->fCoinVisitedDict.add(*entry); 666cb93a386Sopenharmony_ci writable->debugAddToCoinChangedDict(); 667cb93a386Sopenharmony_ci#endif 668cb93a386Sopenharmony_ci} 669cb93a386Sopenharmony_ci#endif 670cb93a386Sopenharmony_ci 671cb93a386Sopenharmony_ci#if DEBUG_T_SECT_LOOP_COUNT 672cb93a386Sopenharmony_civoid SkIntersections::debugBumpLoopCount(DebugLoop index) { 673cb93a386Sopenharmony_ci fDebugLoopCount[index]++; 674cb93a386Sopenharmony_ci} 675cb93a386Sopenharmony_ci 676cb93a386Sopenharmony_ciint SkIntersections::debugLoopCount(DebugLoop index) const { 677cb93a386Sopenharmony_ci return fDebugLoopCount[index]; 678cb93a386Sopenharmony_ci} 679cb93a386Sopenharmony_ci 680cb93a386Sopenharmony_civoid SkIntersections::debugResetLoopCount() { 681cb93a386Sopenharmony_ci sk_bzero(fDebugLoopCount, sizeof(fDebugLoopCount)); 682cb93a386Sopenharmony_ci} 683cb93a386Sopenharmony_ci#endif 684cb93a386Sopenharmony_ci 685cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsConic.h" 686cb93a386Sopenharmony_ci#include "src/pathops/SkPathOpsCubic.h" 687cb93a386Sopenharmony_ci 688cb93a386Sopenharmony_ciSkDCubic SkDQuad::debugToCubic() const { 689cb93a386Sopenharmony_ci SkDCubic cubic; 690cb93a386Sopenharmony_ci cubic[0] = fPts[0]; 691cb93a386Sopenharmony_ci cubic[2] = fPts[1]; 692cb93a386Sopenharmony_ci cubic[3] = fPts[2]; 693cb93a386Sopenharmony_ci cubic[1].fX = (cubic[0].fX + cubic[2].fX * 2) / 3; 694cb93a386Sopenharmony_ci cubic[1].fY = (cubic[0].fY + cubic[2].fY * 2) / 3; 695cb93a386Sopenharmony_ci cubic[2].fX = (cubic[3].fX + cubic[2].fX * 2) / 3; 696cb93a386Sopenharmony_ci cubic[2].fY = (cubic[3].fY + cubic[2].fY * 2) / 3; 697cb93a386Sopenharmony_ci return cubic; 698cb93a386Sopenharmony_ci} 699cb93a386Sopenharmony_ci 700cb93a386Sopenharmony_civoid SkDQuad::debugSet(const SkDPoint* pts) { 701cb93a386Sopenharmony_ci memcpy(fPts, pts, sizeof(fPts)); 702cb93a386Sopenharmony_ci SkDEBUGCODE(fDebugGlobalState = nullptr); 703cb93a386Sopenharmony_ci} 704cb93a386Sopenharmony_ci 705cb93a386Sopenharmony_civoid SkDCubic::debugSet(const SkDPoint* pts) { 706cb93a386Sopenharmony_ci memcpy(fPts, pts, sizeof(fPts)); 707cb93a386Sopenharmony_ci SkDEBUGCODE(fDebugGlobalState = nullptr); 708cb93a386Sopenharmony_ci} 709cb93a386Sopenharmony_ci 710cb93a386Sopenharmony_civoid SkDConic::debugSet(const SkDPoint* pts, SkScalar weight) { 711cb93a386Sopenharmony_ci fPts.debugSet(pts); 712cb93a386Sopenharmony_ci fWeight = weight; 713cb93a386Sopenharmony_ci} 714cb93a386Sopenharmony_ci 715cb93a386Sopenharmony_civoid SkDRect::debugInit() { 716cb93a386Sopenharmony_ci fLeft = fTop = fRight = fBottom = SK_ScalarNaN; 717cb93a386Sopenharmony_ci} 718cb93a386Sopenharmony_ci 719cb93a386Sopenharmony_ci#include "src/pathops/SkOpAngle.h" 720cb93a386Sopenharmony_ci#include "src/pathops/SkOpSegment.h" 721cb93a386Sopenharmony_ci 722cb93a386Sopenharmony_ci#if DEBUG_COIN 723cb93a386Sopenharmony_ci// commented-out lines keep this in sync with addT() 724cb93a386Sopenharmony_ci const SkOpPtT* SkOpSegment::debugAddT(double t, SkPathOpsDebug::GlitchLog* log) const { 725cb93a386Sopenharmony_ci debugValidate(); 726cb93a386Sopenharmony_ci SkPoint pt = this->ptAtT(t); 727cb93a386Sopenharmony_ci const SkOpSpanBase* span = &fHead; 728cb93a386Sopenharmony_ci do { 729cb93a386Sopenharmony_ci const SkOpPtT* result = span->ptT(); 730cb93a386Sopenharmony_ci if (t == result->fT || this->match(result, this, t, pt)) { 731cb93a386Sopenharmony_ci// span->bumpSpanAdds(); 732cb93a386Sopenharmony_ci return result; 733cb93a386Sopenharmony_ci } 734cb93a386Sopenharmony_ci if (t < result->fT) { 735cb93a386Sopenharmony_ci const SkOpSpan* prev = result->span()->prev(); 736cb93a386Sopenharmony_ci FAIL_WITH_NULL_IF(!prev, span); 737cb93a386Sopenharmony_ci // marks in global state that new op span has been allocated 738cb93a386Sopenharmony_ci this->globalState()->setAllocatedOpSpan(); 739cb93a386Sopenharmony_ci// span->init(this, prev, t, pt); 740cb93a386Sopenharmony_ci this->debugValidate(); 741cb93a386Sopenharmony_ci// #if DEBUG_ADD_T 742cb93a386Sopenharmony_ci// SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t, 743cb93a386Sopenharmony_ci// span->segment()->debugID(), span->debugID()); 744cb93a386Sopenharmony_ci// #endif 745cb93a386Sopenharmony_ci// span->bumpSpanAdds(); 746cb93a386Sopenharmony_ci return nullptr; 747cb93a386Sopenharmony_ci } 748cb93a386Sopenharmony_ci FAIL_WITH_NULL_IF(span != &fTail, span); 749cb93a386Sopenharmony_ci } while ((span = span->upCast()->next())); 750cb93a386Sopenharmony_ci SkASSERT(0); 751cb93a386Sopenharmony_ci return nullptr; // we never get here, but need this to satisfy compiler 752cb93a386Sopenharmony_ci} 753cb93a386Sopenharmony_ci#endif 754cb93a386Sopenharmony_ci 755cb93a386Sopenharmony_ci#if DEBUG_ANGLE 756cb93a386Sopenharmony_civoid SkOpSegment::debugCheckAngleCoin() const { 757cb93a386Sopenharmony_ci const SkOpSpanBase* base = &fHead; 758cb93a386Sopenharmony_ci const SkOpSpan* span; 759cb93a386Sopenharmony_ci do { 760cb93a386Sopenharmony_ci const SkOpAngle* angle = base->fromAngle(); 761cb93a386Sopenharmony_ci if (angle && angle->debugCheckCoincidence()) { 762cb93a386Sopenharmony_ci angle->debugCheckNearCoincidence(); 763cb93a386Sopenharmony_ci } 764cb93a386Sopenharmony_ci if (base->final()) { 765cb93a386Sopenharmony_ci break; 766cb93a386Sopenharmony_ci } 767cb93a386Sopenharmony_ci span = base->upCast(); 768cb93a386Sopenharmony_ci angle = span->toAngle(); 769cb93a386Sopenharmony_ci if (angle && angle->debugCheckCoincidence()) { 770cb93a386Sopenharmony_ci angle->debugCheckNearCoincidence(); 771cb93a386Sopenharmony_ci } 772cb93a386Sopenharmony_ci } while ((base = span->next())); 773cb93a386Sopenharmony_ci} 774cb93a386Sopenharmony_ci#endif 775cb93a386Sopenharmony_ci 776cb93a386Sopenharmony_ci#if DEBUG_COIN 777cb93a386Sopenharmony_ci// this mimics the order of the checks in handle coincidence 778cb93a386Sopenharmony_civoid SkOpSegment::debugCheckHealth(SkPathOpsDebug::GlitchLog* glitches) const { 779cb93a386Sopenharmony_ci debugMoveMultiples(glitches); 780cb93a386Sopenharmony_ci debugMoveNearby(glitches); 781cb93a386Sopenharmony_ci debugMissingCoincidence(glitches); 782cb93a386Sopenharmony_ci} 783cb93a386Sopenharmony_ci 784cb93a386Sopenharmony_ci// commented-out lines keep this in sync with clearAll() 785cb93a386Sopenharmony_civoid SkOpSegment::debugClearAll(SkPathOpsDebug::GlitchLog* glitches) const { 786cb93a386Sopenharmony_ci const SkOpSpan* span = &fHead; 787cb93a386Sopenharmony_ci do { 788cb93a386Sopenharmony_ci this->debugClearOne(span, glitches); 789cb93a386Sopenharmony_ci } while ((span = span->next()->upCastable())); 790cb93a386Sopenharmony_ci this->globalState()->coincidence()->debugRelease(glitches, this); 791cb93a386Sopenharmony_ci} 792cb93a386Sopenharmony_ci 793cb93a386Sopenharmony_ci// commented-out lines keep this in sync with clearOne() 794cb93a386Sopenharmony_civoid SkOpSegment::debugClearOne(const SkOpSpan* span, SkPathOpsDebug::GlitchLog* glitches) const { 795cb93a386Sopenharmony_ci if (span->windValue()) glitches->record(SkPathOpsDebug::kCollapsedWindValue_Glitch, span); 796cb93a386Sopenharmony_ci if (span->oppValue()) glitches->record(SkPathOpsDebug::kCollapsedOppValue_Glitch, span); 797cb93a386Sopenharmony_ci if (!span->done()) glitches->record(SkPathOpsDebug::kCollapsedDone_Glitch, span); 798cb93a386Sopenharmony_ci} 799cb93a386Sopenharmony_ci#endif 800cb93a386Sopenharmony_ci 801cb93a386Sopenharmony_ciSkOpAngle* SkOpSegment::debugLastAngle() { 802cb93a386Sopenharmony_ci SkOpAngle* result = nullptr; 803cb93a386Sopenharmony_ci SkOpSpan* span = this->head(); 804cb93a386Sopenharmony_ci do { 805cb93a386Sopenharmony_ci if (span->toAngle()) { 806cb93a386Sopenharmony_ci SkASSERT(!result); 807cb93a386Sopenharmony_ci result = span->toAngle(); 808cb93a386Sopenharmony_ci } 809cb93a386Sopenharmony_ci } while ((span = span->next()->upCastable())); 810cb93a386Sopenharmony_ci SkASSERT(result); 811cb93a386Sopenharmony_ci return result; 812cb93a386Sopenharmony_ci} 813cb93a386Sopenharmony_ci 814cb93a386Sopenharmony_ci#if DEBUG_COIN 815cb93a386Sopenharmony_ci// commented-out lines keep this in sync with ClearVisited 816cb93a386Sopenharmony_civoid SkOpSegment::DebugClearVisited(const SkOpSpanBase* span) { 817cb93a386Sopenharmony_ci // reset visited flag back to false 818cb93a386Sopenharmony_ci do { 819cb93a386Sopenharmony_ci const SkOpPtT* ptT = span->ptT(), * stopPtT = ptT; 820cb93a386Sopenharmony_ci while ((ptT = ptT->next()) != stopPtT) { 821cb93a386Sopenharmony_ci const SkOpSegment* opp = ptT->segment(); 822cb93a386Sopenharmony_ci opp->resetDebugVisited(); 823cb93a386Sopenharmony_ci } 824cb93a386Sopenharmony_ci } while (!span->final() && (span = span->upCast()->next())); 825cb93a386Sopenharmony_ci} 826cb93a386Sopenharmony_ci#endif 827cb93a386Sopenharmony_ci 828cb93a386Sopenharmony_ci#if DEBUG_COIN 829cb93a386Sopenharmony_ci// commented-out lines keep this in sync with missingCoincidence() 830cb93a386Sopenharmony_ci// look for pairs of undetected coincident curves 831cb93a386Sopenharmony_ci// assumes that segments going in have visited flag clear 832cb93a386Sopenharmony_ci// Even though pairs of curves correct detect coincident runs, a run may be missed 833cb93a386Sopenharmony_ci// if the coincidence is a product of multiple intersections. For instance, given 834cb93a386Sopenharmony_ci// curves A, B, and C: 835cb93a386Sopenharmony_ci// A-B intersect at a point 1; A-C and B-C intersect at point 2, so near 836cb93a386Sopenharmony_ci// the end of C that the intersection is replaced with the end of C. 837cb93a386Sopenharmony_ci// Even though A-B correctly do not detect an intersection at point 2, 838cb93a386Sopenharmony_ci// the resulting run from point 1 to point 2 is coincident on A and B. 839cb93a386Sopenharmony_civoid SkOpSegment::debugMissingCoincidence(SkPathOpsDebug::GlitchLog* log) const { 840cb93a386Sopenharmony_ci if (this->done()) { 841cb93a386Sopenharmony_ci return; 842cb93a386Sopenharmony_ci } 843cb93a386Sopenharmony_ci const SkOpSpan* prior = nullptr; 844cb93a386Sopenharmony_ci const SkOpSpanBase* spanBase = &fHead; 845cb93a386Sopenharmony_ci// bool result = false; 846cb93a386Sopenharmony_ci do { 847cb93a386Sopenharmony_ci const SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT; 848cb93a386Sopenharmony_ci SkASSERT(ptT->span() == spanBase); 849cb93a386Sopenharmony_ci while ((ptT = ptT->next()) != spanStopPtT) { 850cb93a386Sopenharmony_ci if (ptT->deleted()) { 851cb93a386Sopenharmony_ci continue; 852cb93a386Sopenharmony_ci } 853cb93a386Sopenharmony_ci const SkOpSegment* opp = ptT->span()->segment(); 854cb93a386Sopenharmony_ci if (opp->done()) { 855cb93a386Sopenharmony_ci continue; 856cb93a386Sopenharmony_ci } 857cb93a386Sopenharmony_ci // when opp is encounted the 1st time, continue; on 2nd encounter, look for coincidence 858cb93a386Sopenharmony_ci if (!opp->debugVisited()) { 859cb93a386Sopenharmony_ci continue; 860cb93a386Sopenharmony_ci } 861cb93a386Sopenharmony_ci if (spanBase == &fHead) { 862cb93a386Sopenharmony_ci continue; 863cb93a386Sopenharmony_ci } 864cb93a386Sopenharmony_ci if (ptT->segment() == this) { 865cb93a386Sopenharmony_ci continue; 866cb93a386Sopenharmony_ci } 867cb93a386Sopenharmony_ci const SkOpSpan* span = spanBase->upCastable(); 868cb93a386Sopenharmony_ci // FIXME?: this assumes that if the opposite segment is coincident then no more 869cb93a386Sopenharmony_ci // coincidence needs to be detected. This may not be true. 870cb93a386Sopenharmony_ci if (span && span->segment() != opp && span->containsCoincidence(opp)) { // debug has additional condition since it may be called before inner duplicate points have been deleted 871cb93a386Sopenharmony_ci continue; 872cb93a386Sopenharmony_ci } 873cb93a386Sopenharmony_ci if (spanBase->segment() != opp && spanBase->containsCoinEnd(opp)) { // debug has additional condition since it may be called before inner duplicate points have been deleted 874cb93a386Sopenharmony_ci continue; 875cb93a386Sopenharmony_ci } 876cb93a386Sopenharmony_ci const SkOpPtT* priorPtT = nullptr, * priorStopPtT; 877cb93a386Sopenharmony_ci // find prior span containing opp segment 878cb93a386Sopenharmony_ci const SkOpSegment* priorOpp = nullptr; 879cb93a386Sopenharmony_ci const SkOpSpan* priorTest = spanBase->prev(); 880cb93a386Sopenharmony_ci while (!priorOpp && priorTest) { 881cb93a386Sopenharmony_ci priorStopPtT = priorPtT = priorTest->ptT(); 882cb93a386Sopenharmony_ci while ((priorPtT = priorPtT->next()) != priorStopPtT) { 883cb93a386Sopenharmony_ci if (priorPtT->deleted()) { 884cb93a386Sopenharmony_ci continue; 885cb93a386Sopenharmony_ci } 886cb93a386Sopenharmony_ci const SkOpSegment* segment = priorPtT->span()->segment(); 887cb93a386Sopenharmony_ci if (segment == opp) { 888cb93a386Sopenharmony_ci prior = priorTest; 889cb93a386Sopenharmony_ci priorOpp = opp; 890cb93a386Sopenharmony_ci break; 891cb93a386Sopenharmony_ci } 892cb93a386Sopenharmony_ci } 893cb93a386Sopenharmony_ci priorTest = priorTest->prev(); 894cb93a386Sopenharmony_ci } 895cb93a386Sopenharmony_ci if (!priorOpp) { 896cb93a386Sopenharmony_ci continue; 897cb93a386Sopenharmony_ci } 898cb93a386Sopenharmony_ci if (priorPtT == ptT) { 899cb93a386Sopenharmony_ci continue; 900cb93a386Sopenharmony_ci } 901cb93a386Sopenharmony_ci const SkOpPtT* oppStart = prior->ptT(); 902cb93a386Sopenharmony_ci const SkOpPtT* oppEnd = spanBase->ptT(); 903cb93a386Sopenharmony_ci bool swapped = priorPtT->fT > ptT->fT; 904cb93a386Sopenharmony_ci if (swapped) { 905cb93a386Sopenharmony_ci using std::swap; 906cb93a386Sopenharmony_ci swap(priorPtT, ptT); 907cb93a386Sopenharmony_ci swap(oppStart, oppEnd); 908cb93a386Sopenharmony_ci } 909cb93a386Sopenharmony_ci const SkOpCoincidence* coincidence = this->globalState()->coincidence(); 910cb93a386Sopenharmony_ci const SkOpPtT* rootPriorPtT = priorPtT->span()->ptT(); 911cb93a386Sopenharmony_ci const SkOpPtT* rootPtT = ptT->span()->ptT(); 912cb93a386Sopenharmony_ci const SkOpPtT* rootOppStart = oppStart->span()->ptT(); 913cb93a386Sopenharmony_ci const SkOpPtT* rootOppEnd = oppEnd->span()->ptT(); 914cb93a386Sopenharmony_ci if (coincidence->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd)) { 915cb93a386Sopenharmony_ci goto swapBack; 916cb93a386Sopenharmony_ci } 917cb93a386Sopenharmony_ci if (testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) { 918cb93a386Sopenharmony_ci // mark coincidence 919cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE_VERBOSE 920cb93a386Sopenharmony_ci// SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\n", __FUNCTION__, 921cb93a386Sopenharmony_ci// rootPriorPtT->debugID(), rootPtT->debugID(), rootOppStart->debugID(), 922cb93a386Sopenharmony_ci// rootOppEnd->debugID()); 923cb93a386Sopenharmony_ci#endif 924cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kMissingCoin_Glitch, priorPtT, ptT, oppStart, oppEnd); 925cb93a386Sopenharmony_ci // coincidences->add(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd); 926cb93a386Sopenharmony_ci // } 927cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE 928cb93a386Sopenharmony_ci// SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOppStart, rootOppEnd); 929cb93a386Sopenharmony_ci#endif 930cb93a386Sopenharmony_ci // result = true; 931cb93a386Sopenharmony_ci } 932cb93a386Sopenharmony_ci swapBack: 933cb93a386Sopenharmony_ci if (swapped) { 934cb93a386Sopenharmony_ci using std::swap; 935cb93a386Sopenharmony_ci swap(priorPtT, ptT); 936cb93a386Sopenharmony_ci } 937cb93a386Sopenharmony_ci } 938cb93a386Sopenharmony_ci } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next())); 939cb93a386Sopenharmony_ci DebugClearVisited(&fHead); 940cb93a386Sopenharmony_ci return; 941cb93a386Sopenharmony_ci} 942cb93a386Sopenharmony_ci 943cb93a386Sopenharmony_ci// commented-out lines keep this in sync with moveMultiples() 944cb93a386Sopenharmony_ci// if a span has more than one intersection, merge the other segments' span as needed 945cb93a386Sopenharmony_civoid SkOpSegment::debugMoveMultiples(SkPathOpsDebug::GlitchLog* glitches) const { 946cb93a386Sopenharmony_ci debugValidate(); 947cb93a386Sopenharmony_ci const SkOpSpanBase* test = &fHead; 948cb93a386Sopenharmony_ci do { 949cb93a386Sopenharmony_ci int addCount = test->spanAddsCount(); 950cb93a386Sopenharmony_ci// SkASSERT(addCount >= 1); 951cb93a386Sopenharmony_ci if (addCount <= 1) { 952cb93a386Sopenharmony_ci continue; 953cb93a386Sopenharmony_ci } 954cb93a386Sopenharmony_ci const SkOpPtT* startPtT = test->ptT(); 955cb93a386Sopenharmony_ci const SkOpPtT* testPtT = startPtT; 956cb93a386Sopenharmony_ci do { // iterate through all spans associated with start 957cb93a386Sopenharmony_ci const SkOpSpanBase* oppSpan = testPtT->span(); 958cb93a386Sopenharmony_ci if (oppSpan->spanAddsCount() == addCount) { 959cb93a386Sopenharmony_ci continue; 960cb93a386Sopenharmony_ci } 961cb93a386Sopenharmony_ci if (oppSpan->deleted()) { 962cb93a386Sopenharmony_ci continue; 963cb93a386Sopenharmony_ci } 964cb93a386Sopenharmony_ci const SkOpSegment* oppSegment = oppSpan->segment(); 965cb93a386Sopenharmony_ci if (oppSegment == this) { 966cb93a386Sopenharmony_ci continue; 967cb93a386Sopenharmony_ci } 968cb93a386Sopenharmony_ci // find range of spans to consider merging 969cb93a386Sopenharmony_ci const SkOpSpanBase* oppPrev = oppSpan; 970cb93a386Sopenharmony_ci const SkOpSpanBase* oppFirst = oppSpan; 971cb93a386Sopenharmony_ci while ((oppPrev = oppPrev->prev())) { 972cb93a386Sopenharmony_ci if (!roughly_equal(oppPrev->t(), oppSpan->t())) { 973cb93a386Sopenharmony_ci break; 974cb93a386Sopenharmony_ci } 975cb93a386Sopenharmony_ci if (oppPrev->spanAddsCount() == addCount) { 976cb93a386Sopenharmony_ci continue; 977cb93a386Sopenharmony_ci } 978cb93a386Sopenharmony_ci if (oppPrev->deleted()) { 979cb93a386Sopenharmony_ci continue; 980cb93a386Sopenharmony_ci } 981cb93a386Sopenharmony_ci oppFirst = oppPrev; 982cb93a386Sopenharmony_ci } 983cb93a386Sopenharmony_ci const SkOpSpanBase* oppNext = oppSpan; 984cb93a386Sopenharmony_ci const SkOpSpanBase* oppLast = oppSpan; 985cb93a386Sopenharmony_ci while ((oppNext = oppNext->final() ? nullptr : oppNext->upCast()->next())) { 986cb93a386Sopenharmony_ci if (!roughly_equal(oppNext->t(), oppSpan->t())) { 987cb93a386Sopenharmony_ci break; 988cb93a386Sopenharmony_ci } 989cb93a386Sopenharmony_ci if (oppNext->spanAddsCount() == addCount) { 990cb93a386Sopenharmony_ci continue; 991cb93a386Sopenharmony_ci } 992cb93a386Sopenharmony_ci if (oppNext->deleted()) { 993cb93a386Sopenharmony_ci continue; 994cb93a386Sopenharmony_ci } 995cb93a386Sopenharmony_ci oppLast = oppNext; 996cb93a386Sopenharmony_ci } 997cb93a386Sopenharmony_ci if (oppFirst == oppLast) { 998cb93a386Sopenharmony_ci continue; 999cb93a386Sopenharmony_ci } 1000cb93a386Sopenharmony_ci const SkOpSpanBase* oppTest = oppFirst; 1001cb93a386Sopenharmony_ci do { 1002cb93a386Sopenharmony_ci if (oppTest == oppSpan) { 1003cb93a386Sopenharmony_ci continue; 1004cb93a386Sopenharmony_ci } 1005cb93a386Sopenharmony_ci // check to see if the candidate meets specific criteria: 1006cb93a386Sopenharmony_ci // it contains spans of segments in test's loop but not including 'this' 1007cb93a386Sopenharmony_ci const SkOpPtT* oppStartPtT = oppTest->ptT(); 1008cb93a386Sopenharmony_ci const SkOpPtT* oppPtT = oppStartPtT; 1009cb93a386Sopenharmony_ci while ((oppPtT = oppPtT->next()) != oppStartPtT) { 1010cb93a386Sopenharmony_ci const SkOpSegment* oppPtTSegment = oppPtT->segment(); 1011cb93a386Sopenharmony_ci if (oppPtTSegment == this) { 1012cb93a386Sopenharmony_ci goto tryNextSpan; 1013cb93a386Sopenharmony_ci } 1014cb93a386Sopenharmony_ci const SkOpPtT* matchPtT = startPtT; 1015cb93a386Sopenharmony_ci do { 1016cb93a386Sopenharmony_ci if (matchPtT->segment() == oppPtTSegment) { 1017cb93a386Sopenharmony_ci goto foundMatch; 1018cb93a386Sopenharmony_ci } 1019cb93a386Sopenharmony_ci } while ((matchPtT = matchPtT->next()) != startPtT); 1020cb93a386Sopenharmony_ci goto tryNextSpan; 1021cb93a386Sopenharmony_ci foundMatch: // merge oppTest and oppSpan 1022cb93a386Sopenharmony_ci oppSegment->debugValidate(); 1023cb93a386Sopenharmony_ci oppTest->debugMergeMatches(glitches, oppSpan); 1024cb93a386Sopenharmony_ci oppTest->debugAddOpp(glitches, oppSpan); 1025cb93a386Sopenharmony_ci oppSegment->debugValidate(); 1026cb93a386Sopenharmony_ci goto checkNextSpan; 1027cb93a386Sopenharmony_ci } 1028cb93a386Sopenharmony_ci tryNextSpan: 1029cb93a386Sopenharmony_ci ; 1030cb93a386Sopenharmony_ci } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next())); 1031cb93a386Sopenharmony_ci } while ((testPtT = testPtT->next()) != startPtT); 1032cb93a386Sopenharmony_cicheckNextSpan: 1033cb93a386Sopenharmony_ci ; 1034cb93a386Sopenharmony_ci } while ((test = test->final() ? nullptr : test->upCast()->next())); 1035cb93a386Sopenharmony_ci debugValidate(); 1036cb93a386Sopenharmony_ci return; 1037cb93a386Sopenharmony_ci} 1038cb93a386Sopenharmony_ci 1039cb93a386Sopenharmony_ci// commented-out lines keep this in sync with moveNearby() 1040cb93a386Sopenharmony_ci// Move nearby t values and pts so they all hang off the same span. Alignment happens later. 1041cb93a386Sopenharmony_civoid SkOpSegment::debugMoveNearby(SkPathOpsDebug::GlitchLog* glitches) const { 1042cb93a386Sopenharmony_ci debugValidate(); 1043cb93a386Sopenharmony_ci // release undeleted spans pointing to this seg that are linked to the primary span 1044cb93a386Sopenharmony_ci const SkOpSpanBase* spanBase = &fHead; 1045cb93a386Sopenharmony_ci do { 1046cb93a386Sopenharmony_ci const SkOpPtT* ptT = spanBase->ptT(); 1047cb93a386Sopenharmony_ci const SkOpPtT* headPtT = ptT; 1048cb93a386Sopenharmony_ci while ((ptT = ptT->next()) != headPtT) { 1049cb93a386Sopenharmony_ci const SkOpSpanBase* test = ptT->span(); 1050cb93a386Sopenharmony_ci if (ptT->segment() == this && !ptT->deleted() && test != spanBase 1051cb93a386Sopenharmony_ci && test->ptT() == ptT) { 1052cb93a386Sopenharmony_ci if (test->final()) { 1053cb93a386Sopenharmony_ci if (spanBase == &fHead) { 1054cb93a386Sopenharmony_ci glitches->record(SkPathOpsDebug::kMoveNearbyClearAll_Glitch, this); 1055cb93a386Sopenharmony_ci// return; 1056cb93a386Sopenharmony_ci } 1057cb93a386Sopenharmony_ci glitches->record(SkPathOpsDebug::kMoveNearbyReleaseFinal_Glitch, spanBase, ptT); 1058cb93a386Sopenharmony_ci } else if (test->prev()) { 1059cb93a386Sopenharmony_ci glitches->record(SkPathOpsDebug::kMoveNearbyRelease_Glitch, test, headPtT); 1060cb93a386Sopenharmony_ci } 1061cb93a386Sopenharmony_ci// break; 1062cb93a386Sopenharmony_ci } 1063cb93a386Sopenharmony_ci } 1064cb93a386Sopenharmony_ci spanBase = spanBase->upCast()->next(); 1065cb93a386Sopenharmony_ci } while (!spanBase->final()); 1066cb93a386Sopenharmony_ci 1067cb93a386Sopenharmony_ci // This loop looks for adjacent spans which are near by 1068cb93a386Sopenharmony_ci spanBase = &fHead; 1069cb93a386Sopenharmony_ci do { // iterate through all spans associated with start 1070cb93a386Sopenharmony_ci const SkOpSpanBase* test = spanBase->upCast()->next(); 1071cb93a386Sopenharmony_ci bool found; 1072cb93a386Sopenharmony_ci if (!this->spansNearby(spanBase, test, &found)) { 1073cb93a386Sopenharmony_ci glitches->record(SkPathOpsDebug::kMoveNearbyMergeFinal_Glitch, test); 1074cb93a386Sopenharmony_ci } 1075cb93a386Sopenharmony_ci if (found) { 1076cb93a386Sopenharmony_ci if (test->final()) { 1077cb93a386Sopenharmony_ci if (spanBase->prev()) { 1078cb93a386Sopenharmony_ci glitches->record(SkPathOpsDebug::kMoveNearbyMergeFinal_Glitch, test); 1079cb93a386Sopenharmony_ci } else { 1080cb93a386Sopenharmony_ci glitches->record(SkPathOpsDebug::kMoveNearbyClearAll2_Glitch, this); 1081cb93a386Sopenharmony_ci // return 1082cb93a386Sopenharmony_ci } 1083cb93a386Sopenharmony_ci } else { 1084cb93a386Sopenharmony_ci glitches->record(SkPathOpsDebug::kMoveNearbyMerge_Glitch, spanBase); 1085cb93a386Sopenharmony_ci } 1086cb93a386Sopenharmony_ci } 1087cb93a386Sopenharmony_ci spanBase = test; 1088cb93a386Sopenharmony_ci } while (!spanBase->final()); 1089cb93a386Sopenharmony_ci debugValidate(); 1090cb93a386Sopenharmony_ci} 1091cb93a386Sopenharmony_ci#endif 1092cb93a386Sopenharmony_ci 1093cb93a386Sopenharmony_civoid SkOpSegment::debugReset() { 1094cb93a386Sopenharmony_ci this->init(this->fPts, this->fWeight, this->contour(), this->verb()); 1095cb93a386Sopenharmony_ci} 1096cb93a386Sopenharmony_ci 1097cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE_ORDER 1098cb93a386Sopenharmony_civoid SkOpSegment::debugSetCoinT(int index, SkScalar t) const { 1099cb93a386Sopenharmony_ci if (fDebugBaseMax < 0 || fDebugBaseIndex == index) { 1100cb93a386Sopenharmony_ci fDebugBaseIndex = index; 1101cb93a386Sopenharmony_ci fDebugBaseMin = std::min(t, fDebugBaseMin); 1102cb93a386Sopenharmony_ci fDebugBaseMax = std::max(t, fDebugBaseMax); 1103cb93a386Sopenharmony_ci return; 1104cb93a386Sopenharmony_ci } 1105cb93a386Sopenharmony_ci SkASSERT(fDebugBaseMin >= t || t >= fDebugBaseMax); 1106cb93a386Sopenharmony_ci if (fDebugLastMax < 0 || fDebugLastIndex == index) { 1107cb93a386Sopenharmony_ci fDebugLastIndex = index; 1108cb93a386Sopenharmony_ci fDebugLastMin = std::min(t, fDebugLastMin); 1109cb93a386Sopenharmony_ci fDebugLastMax = std::max(t, fDebugLastMax); 1110cb93a386Sopenharmony_ci return; 1111cb93a386Sopenharmony_ci } 1112cb93a386Sopenharmony_ci SkASSERT(fDebugLastMin >= t || t >= fDebugLastMax); 1113cb93a386Sopenharmony_ci SkASSERT((t - fDebugBaseMin > 0) == (fDebugLastMin - fDebugBaseMin > 0)); 1114cb93a386Sopenharmony_ci} 1115cb93a386Sopenharmony_ci#endif 1116cb93a386Sopenharmony_ci 1117cb93a386Sopenharmony_ci#if DEBUG_ACTIVE_SPANS 1118cb93a386Sopenharmony_civoid SkOpSegment::debugShowActiveSpans(SkString* str) const { 1119cb93a386Sopenharmony_ci debugValidate(); 1120cb93a386Sopenharmony_ci if (done()) { 1121cb93a386Sopenharmony_ci return; 1122cb93a386Sopenharmony_ci } 1123cb93a386Sopenharmony_ci int lastId = -1; 1124cb93a386Sopenharmony_ci double lastT = -1; 1125cb93a386Sopenharmony_ci const SkOpSpan* span = &fHead; 1126cb93a386Sopenharmony_ci do { 1127cb93a386Sopenharmony_ci if (span->done()) { 1128cb93a386Sopenharmony_ci continue; 1129cb93a386Sopenharmony_ci } 1130cb93a386Sopenharmony_ci if (lastId == this->debugID() && lastT == span->t()) { 1131cb93a386Sopenharmony_ci continue; 1132cb93a386Sopenharmony_ci } 1133cb93a386Sopenharmony_ci lastId = this->debugID(); 1134cb93a386Sopenharmony_ci lastT = span->t(); 1135cb93a386Sopenharmony_ci str->appendf("%s id=%d", __FUNCTION__, this->debugID()); 1136cb93a386Sopenharmony_ci // since endpoints may have be adjusted, show actual computed curves 1137cb93a386Sopenharmony_ci SkDCurve curvePart; 1138cb93a386Sopenharmony_ci this->subDivide(span, span->next(), &curvePart); 1139cb93a386Sopenharmony_ci const SkDPoint* pts = curvePart.fCubic.fPts; 1140cb93a386Sopenharmony_ci str->appendf(" (%1.9g,%1.9g", pts[0].fX, pts[0].fY); 1141cb93a386Sopenharmony_ci for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { 1142cb93a386Sopenharmony_ci str->appendf(" %1.9g,%1.9g", pts[vIndex].fX, pts[vIndex].fY); 1143cb93a386Sopenharmony_ci } 1144cb93a386Sopenharmony_ci if (SkPath::kConic_Verb == fVerb) { 1145cb93a386Sopenharmony_ci str->appendf(" %1.9gf", curvePart.fConic.fWeight); 1146cb93a386Sopenharmony_ci } 1147cb93a386Sopenharmony_ci str->appendf(") t=%1.9g tEnd=%1.9g", span->t(), span->next()->t()); 1148cb93a386Sopenharmony_ci if (span->windSum() == SK_MinS32) { 1149cb93a386Sopenharmony_ci str->appendf(" windSum=?"); 1150cb93a386Sopenharmony_ci } else { 1151cb93a386Sopenharmony_ci str->appendf(" windSum=%d", span->windSum()); 1152cb93a386Sopenharmony_ci } 1153cb93a386Sopenharmony_ci if (span->oppValue() && span->oppSum() == SK_MinS32) { 1154cb93a386Sopenharmony_ci str->appendf(" oppSum=?"); 1155cb93a386Sopenharmony_ci } else if (span->oppValue() || span->oppSum() != SK_MinS32) { 1156cb93a386Sopenharmony_ci str->appendf(" oppSum=%d", span->oppSum()); 1157cb93a386Sopenharmony_ci } 1158cb93a386Sopenharmony_ci str->appendf(" windValue=%d", span->windValue()); 1159cb93a386Sopenharmony_ci if (span->oppValue() || span->oppSum() != SK_MinS32) { 1160cb93a386Sopenharmony_ci str->appendf(" oppValue=%d", span->oppValue()); 1161cb93a386Sopenharmony_ci } 1162cb93a386Sopenharmony_ci str->appendf("\n"); 1163cb93a386Sopenharmony_ci } while ((span = span->next()->upCastable())); 1164cb93a386Sopenharmony_ci} 1165cb93a386Sopenharmony_ci#endif 1166cb93a386Sopenharmony_ci 1167cb93a386Sopenharmony_ci#if DEBUG_MARK_DONE 1168cb93a386Sopenharmony_civoid SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int winding) { 1169cb93a386Sopenharmony_ci const SkPoint& pt = span->ptT()->fPt; 1170cb93a386Sopenharmony_ci SkDebugf("%s id=%d", fun, this->debugID()); 1171cb93a386Sopenharmony_ci SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); 1172cb93a386Sopenharmony_ci for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { 1173cb93a386Sopenharmony_ci SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); 1174cb93a386Sopenharmony_ci } 1175cb93a386Sopenharmony_ci SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=", 1176cb93a386Sopenharmony_ci span->t(), span->debugID(), pt.fX, pt.fY, span->next()->t()); 1177cb93a386Sopenharmony_ci if (winding == SK_MinS32) { 1178cb93a386Sopenharmony_ci SkDebugf("?"); 1179cb93a386Sopenharmony_ci } else { 1180cb93a386Sopenharmony_ci SkDebugf("%d", winding); 1181cb93a386Sopenharmony_ci } 1182cb93a386Sopenharmony_ci SkDebugf(" windSum="); 1183cb93a386Sopenharmony_ci if (span->windSum() == SK_MinS32) { 1184cb93a386Sopenharmony_ci SkDebugf("?"); 1185cb93a386Sopenharmony_ci } else { 1186cb93a386Sopenharmony_ci SkDebugf("%d", span->windSum()); 1187cb93a386Sopenharmony_ci } 1188cb93a386Sopenharmony_ci SkDebugf(" windValue=%d\n", span->windValue()); 1189cb93a386Sopenharmony_ci} 1190cb93a386Sopenharmony_ci 1191cb93a386Sopenharmony_civoid SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int winding, 1192cb93a386Sopenharmony_ci int oppWinding) { 1193cb93a386Sopenharmony_ci const SkPoint& pt = span->ptT()->fPt; 1194cb93a386Sopenharmony_ci SkDebugf("%s id=%d", fun, this->debugID()); 1195cb93a386Sopenharmony_ci SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); 1196cb93a386Sopenharmony_ci for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { 1197cb93a386Sopenharmony_ci SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); 1198cb93a386Sopenharmony_ci } 1199cb93a386Sopenharmony_ci SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=", 1200cb93a386Sopenharmony_ci span->t(), span->debugID(), pt.fX, pt.fY, span->next()->t(), winding, oppWinding); 1201cb93a386Sopenharmony_ci if (winding == SK_MinS32) { 1202cb93a386Sopenharmony_ci SkDebugf("?"); 1203cb93a386Sopenharmony_ci } else { 1204cb93a386Sopenharmony_ci SkDebugf("%d", winding); 1205cb93a386Sopenharmony_ci } 1206cb93a386Sopenharmony_ci SkDebugf(" newOppSum="); 1207cb93a386Sopenharmony_ci if (oppWinding == SK_MinS32) { 1208cb93a386Sopenharmony_ci SkDebugf("?"); 1209cb93a386Sopenharmony_ci } else { 1210cb93a386Sopenharmony_ci SkDebugf("%d", oppWinding); 1211cb93a386Sopenharmony_ci } 1212cb93a386Sopenharmony_ci SkDebugf(" oppSum="); 1213cb93a386Sopenharmony_ci if (span->oppSum() == SK_MinS32) { 1214cb93a386Sopenharmony_ci SkDebugf("?"); 1215cb93a386Sopenharmony_ci } else { 1216cb93a386Sopenharmony_ci SkDebugf("%d", span->oppSum()); 1217cb93a386Sopenharmony_ci } 1218cb93a386Sopenharmony_ci SkDebugf(" windSum="); 1219cb93a386Sopenharmony_ci if (span->windSum() == SK_MinS32) { 1220cb93a386Sopenharmony_ci SkDebugf("?"); 1221cb93a386Sopenharmony_ci } else { 1222cb93a386Sopenharmony_ci SkDebugf("%d", span->windSum()); 1223cb93a386Sopenharmony_ci } 1224cb93a386Sopenharmony_ci SkDebugf(" windValue=%d oppValue=%d\n", span->windValue(), span->oppValue()); 1225cb93a386Sopenharmony_ci} 1226cb93a386Sopenharmony_ci 1227cb93a386Sopenharmony_ci#endif 1228cb93a386Sopenharmony_ci 1229cb93a386Sopenharmony_ci// loop looking for a pair of angle parts that are too close to be sorted 1230cb93a386Sopenharmony_ci/* This is called after other more simple intersection and angle sorting tests have been exhausted. 1231cb93a386Sopenharmony_ci This should be rarely called -- the test below is thorough and time consuming. 1232cb93a386Sopenharmony_ci This checks the distance between start points; the distance between 1233cb93a386Sopenharmony_ci*/ 1234cb93a386Sopenharmony_ci#if DEBUG_ANGLE 1235cb93a386Sopenharmony_civoid SkOpAngle::debugCheckNearCoincidence() const { 1236cb93a386Sopenharmony_ci const SkOpAngle* test = this; 1237cb93a386Sopenharmony_ci do { 1238cb93a386Sopenharmony_ci const SkOpSegment* testSegment = test->segment(); 1239cb93a386Sopenharmony_ci double testStartT = test->start()->t(); 1240cb93a386Sopenharmony_ci SkDPoint testStartPt = testSegment->dPtAtT(testStartT); 1241cb93a386Sopenharmony_ci double testEndT = test->end()->t(); 1242cb93a386Sopenharmony_ci SkDPoint testEndPt = testSegment->dPtAtT(testEndT); 1243cb93a386Sopenharmony_ci double testLenSq = testStartPt.distanceSquared(testEndPt); 1244cb93a386Sopenharmony_ci SkDebugf("%s testLenSq=%1.9g id=%d\n", __FUNCTION__, testLenSq, testSegment->debugID()); 1245cb93a386Sopenharmony_ci double testMidT = (testStartT + testEndT) / 2; 1246cb93a386Sopenharmony_ci const SkOpAngle* next = test; 1247cb93a386Sopenharmony_ci while ((next = next->fNext) != this) { 1248cb93a386Sopenharmony_ci SkOpSegment* nextSegment = next->segment(); 1249cb93a386Sopenharmony_ci double testMidDistSq = testSegment->distSq(testMidT, next); 1250cb93a386Sopenharmony_ci double testEndDistSq = testSegment->distSq(testEndT, next); 1251cb93a386Sopenharmony_ci double nextStartT = next->start()->t(); 1252cb93a386Sopenharmony_ci SkDPoint nextStartPt = nextSegment->dPtAtT(nextStartT); 1253cb93a386Sopenharmony_ci double distSq = testStartPt.distanceSquared(nextStartPt); 1254cb93a386Sopenharmony_ci double nextEndT = next->end()->t(); 1255cb93a386Sopenharmony_ci double nextMidT = (nextStartT + nextEndT) / 2; 1256cb93a386Sopenharmony_ci double nextMidDistSq = nextSegment->distSq(nextMidT, test); 1257cb93a386Sopenharmony_ci double nextEndDistSq = nextSegment->distSq(nextEndT, test); 1258cb93a386Sopenharmony_ci SkDebugf("%s distSq=%1.9g testId=%d nextId=%d\n", __FUNCTION__, distSq, 1259cb93a386Sopenharmony_ci testSegment->debugID(), nextSegment->debugID()); 1260cb93a386Sopenharmony_ci SkDebugf("%s testMidDistSq=%1.9g\n", __FUNCTION__, testMidDistSq); 1261cb93a386Sopenharmony_ci SkDebugf("%s testEndDistSq=%1.9g\n", __FUNCTION__, testEndDistSq); 1262cb93a386Sopenharmony_ci SkDebugf("%s nextMidDistSq=%1.9g\n", __FUNCTION__, nextMidDistSq); 1263cb93a386Sopenharmony_ci SkDebugf("%s nextEndDistSq=%1.9g\n", __FUNCTION__, nextEndDistSq); 1264cb93a386Sopenharmony_ci SkDPoint nextEndPt = nextSegment->dPtAtT(nextEndT); 1265cb93a386Sopenharmony_ci double nextLenSq = nextStartPt.distanceSquared(nextEndPt); 1266cb93a386Sopenharmony_ci SkDebugf("%s nextLenSq=%1.9g\n", __FUNCTION__, nextLenSq); 1267cb93a386Sopenharmony_ci SkDebugf("\n"); 1268cb93a386Sopenharmony_ci } 1269cb93a386Sopenharmony_ci test = test->fNext; 1270cb93a386Sopenharmony_ci } while (test->fNext != this); 1271cb93a386Sopenharmony_ci} 1272cb93a386Sopenharmony_ci#endif 1273cb93a386Sopenharmony_ci 1274cb93a386Sopenharmony_ci#if DEBUG_ANGLE 1275cb93a386Sopenharmony_ciSkString SkOpAngle::debugPart() const { 1276cb93a386Sopenharmony_ci SkString result; 1277cb93a386Sopenharmony_ci switch (this->segment()->verb()) { 1278cb93a386Sopenharmony_ci case SkPath::kLine_Verb: 1279cb93a386Sopenharmony_ci result.printf(LINE_DEBUG_STR " id=%d", LINE_DEBUG_DATA(fPart.fCurve), 1280cb93a386Sopenharmony_ci this->segment()->debugID()); 1281cb93a386Sopenharmony_ci break; 1282cb93a386Sopenharmony_ci case SkPath::kQuad_Verb: 1283cb93a386Sopenharmony_ci result.printf(QUAD_DEBUG_STR " id=%d", QUAD_DEBUG_DATA(fPart.fCurve), 1284cb93a386Sopenharmony_ci this->segment()->debugID()); 1285cb93a386Sopenharmony_ci break; 1286cb93a386Sopenharmony_ci case SkPath::kConic_Verb: 1287cb93a386Sopenharmony_ci result.printf(CONIC_DEBUG_STR " id=%d", 1288cb93a386Sopenharmony_ci CONIC_DEBUG_DATA(fPart.fCurve, fPart.fCurve.fConic.fWeight), 1289cb93a386Sopenharmony_ci this->segment()->debugID()); 1290cb93a386Sopenharmony_ci break; 1291cb93a386Sopenharmony_ci case SkPath::kCubic_Verb: 1292cb93a386Sopenharmony_ci result.printf(CUBIC_DEBUG_STR " id=%d", CUBIC_DEBUG_DATA(fPart.fCurve), 1293cb93a386Sopenharmony_ci this->segment()->debugID()); 1294cb93a386Sopenharmony_ci break; 1295cb93a386Sopenharmony_ci default: 1296cb93a386Sopenharmony_ci SkASSERT(0); 1297cb93a386Sopenharmony_ci } 1298cb93a386Sopenharmony_ci return result; 1299cb93a386Sopenharmony_ci} 1300cb93a386Sopenharmony_ci#endif 1301cb93a386Sopenharmony_ci 1302cb93a386Sopenharmony_ci#if DEBUG_SORT 1303cb93a386Sopenharmony_civoid SkOpAngle::debugLoop() const { 1304cb93a386Sopenharmony_ci const SkOpAngle* first = this; 1305cb93a386Sopenharmony_ci const SkOpAngle* next = this; 1306cb93a386Sopenharmony_ci do { 1307cb93a386Sopenharmony_ci next->dumpOne(true); 1308cb93a386Sopenharmony_ci SkDebugf("\n"); 1309cb93a386Sopenharmony_ci next = next->fNext; 1310cb93a386Sopenharmony_ci } while (next && next != first); 1311cb93a386Sopenharmony_ci next = first; 1312cb93a386Sopenharmony_ci do { 1313cb93a386Sopenharmony_ci next->debugValidate(); 1314cb93a386Sopenharmony_ci next = next->fNext; 1315cb93a386Sopenharmony_ci } while (next && next != first); 1316cb93a386Sopenharmony_ci} 1317cb93a386Sopenharmony_ci#endif 1318cb93a386Sopenharmony_ci 1319cb93a386Sopenharmony_civoid SkOpAngle::debugValidate() const { 1320cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE 1321cb93a386Sopenharmony_ci if (this->globalState()->debugCheckHealth()) { 1322cb93a386Sopenharmony_ci return; 1323cb93a386Sopenharmony_ci } 1324cb93a386Sopenharmony_ci#endif 1325cb93a386Sopenharmony_ci#if DEBUG_VALIDATE 1326cb93a386Sopenharmony_ci const SkOpAngle* first = this; 1327cb93a386Sopenharmony_ci const SkOpAngle* next = this; 1328cb93a386Sopenharmony_ci int wind = 0; 1329cb93a386Sopenharmony_ci int opp = 0; 1330cb93a386Sopenharmony_ci int lastXor = -1; 1331cb93a386Sopenharmony_ci int lastOppXor = -1; 1332cb93a386Sopenharmony_ci do { 1333cb93a386Sopenharmony_ci if (next->unorderable()) { 1334cb93a386Sopenharmony_ci return; 1335cb93a386Sopenharmony_ci } 1336cb93a386Sopenharmony_ci const SkOpSpan* minSpan = next->start()->starter(next->end()); 1337cb93a386Sopenharmony_ci if (minSpan->windValue() == SK_MinS32) { 1338cb93a386Sopenharmony_ci return; 1339cb93a386Sopenharmony_ci } 1340cb93a386Sopenharmony_ci bool op = next->segment()->operand(); 1341cb93a386Sopenharmony_ci bool isXor = next->segment()->isXor(); 1342cb93a386Sopenharmony_ci bool oppXor = next->segment()->oppXor(); 1343cb93a386Sopenharmony_ci SkASSERT(!DEBUG_LIMIT_WIND_SUM || between(0, minSpan->windValue(), DEBUG_LIMIT_WIND_SUM)); 1344cb93a386Sopenharmony_ci SkASSERT(!DEBUG_LIMIT_WIND_SUM 1345cb93a386Sopenharmony_ci || between(-DEBUG_LIMIT_WIND_SUM, minSpan->oppValue(), DEBUG_LIMIT_WIND_SUM)); 1346cb93a386Sopenharmony_ci bool useXor = op ? oppXor : isXor; 1347cb93a386Sopenharmony_ci SkASSERT(lastXor == -1 || lastXor == (int) useXor); 1348cb93a386Sopenharmony_ci lastXor = (int) useXor; 1349cb93a386Sopenharmony_ci wind += next->debugSign() * (op ? minSpan->oppValue() : minSpan->windValue()); 1350cb93a386Sopenharmony_ci if (useXor) { 1351cb93a386Sopenharmony_ci wind &= 1; 1352cb93a386Sopenharmony_ci } 1353cb93a386Sopenharmony_ci useXor = op ? isXor : oppXor; 1354cb93a386Sopenharmony_ci SkASSERT(lastOppXor == -1 || lastOppXor == (int) useXor); 1355cb93a386Sopenharmony_ci lastOppXor = (int) useXor; 1356cb93a386Sopenharmony_ci opp += next->debugSign() * (op ? minSpan->windValue() : minSpan->oppValue()); 1357cb93a386Sopenharmony_ci if (useXor) { 1358cb93a386Sopenharmony_ci opp &= 1; 1359cb93a386Sopenharmony_ci } 1360cb93a386Sopenharmony_ci next = next->fNext; 1361cb93a386Sopenharmony_ci } while (next && next != first); 1362cb93a386Sopenharmony_ci SkASSERT(wind == 0 || !SkPathOpsDebug::gRunFail); 1363cb93a386Sopenharmony_ci SkASSERT(opp == 0 || !SkPathOpsDebug::gRunFail); 1364cb93a386Sopenharmony_ci#endif 1365cb93a386Sopenharmony_ci} 1366cb93a386Sopenharmony_ci 1367cb93a386Sopenharmony_civoid SkOpAngle::debugValidateNext() const { 1368cb93a386Sopenharmony_ci#if !FORCE_RELEASE 1369cb93a386Sopenharmony_ci const SkOpAngle* first = this; 1370cb93a386Sopenharmony_ci const SkOpAngle* next = first; 1371cb93a386Sopenharmony_ci SkTDArray<const SkOpAngle*>(angles); 1372cb93a386Sopenharmony_ci do { 1373cb93a386Sopenharmony_ci// SkASSERT_RELEASE(next->fSegment->debugContains(next)); 1374cb93a386Sopenharmony_ci angles.push_back(next); 1375cb93a386Sopenharmony_ci next = next->next(); 1376cb93a386Sopenharmony_ci if (next == first) { 1377cb93a386Sopenharmony_ci break; 1378cb93a386Sopenharmony_ci } 1379cb93a386Sopenharmony_ci SkASSERT_RELEASE(!angles.contains(next)); 1380cb93a386Sopenharmony_ci if (!next) { 1381cb93a386Sopenharmony_ci return; 1382cb93a386Sopenharmony_ci } 1383cb93a386Sopenharmony_ci } while (true); 1384cb93a386Sopenharmony_ci#endif 1385cb93a386Sopenharmony_ci} 1386cb93a386Sopenharmony_ci 1387cb93a386Sopenharmony_ci#ifdef SK_DEBUG 1388cb93a386Sopenharmony_civoid SkCoincidentSpans::debugStartCheck(const SkOpSpanBase* outer, const SkOpSpanBase* over, 1389cb93a386Sopenharmony_ci const SkOpGlobalState* debugState) const { 1390cb93a386Sopenharmony_ci SkASSERT(coinPtTEnd()->span() == over || !SkOpGlobalState::DebugRunFail()); 1391cb93a386Sopenharmony_ci SkASSERT(oppPtTEnd()->span() == outer || !SkOpGlobalState::DebugRunFail()); 1392cb93a386Sopenharmony_ci} 1393cb93a386Sopenharmony_ci#endif 1394cb93a386Sopenharmony_ci 1395cb93a386Sopenharmony_ci#if DEBUG_COIN 1396cb93a386Sopenharmony_ci// sets the span's end to the ptT referenced by the previous-next 1397cb93a386Sopenharmony_civoid SkCoincidentSpans::debugCorrectOneEnd(SkPathOpsDebug::GlitchLog* log, 1398cb93a386Sopenharmony_ci const SkOpPtT* (SkCoincidentSpans::* getEnd)() const, 1399cb93a386Sopenharmony_ci void (SkCoincidentSpans::*setEnd)(const SkOpPtT* ptT) const ) const { 1400cb93a386Sopenharmony_ci const SkOpPtT* origPtT = (this->*getEnd)(); 1401cb93a386Sopenharmony_ci const SkOpSpanBase* origSpan = origPtT->span(); 1402cb93a386Sopenharmony_ci const SkOpSpan* prev = origSpan->prev(); 1403cb93a386Sopenharmony_ci const SkOpPtT* testPtT = prev ? prev->next()->ptT() 1404cb93a386Sopenharmony_ci : origSpan->upCast()->next()->prev()->ptT(); 1405cb93a386Sopenharmony_ci if (origPtT != testPtT) { 1406cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kCorrectEnd_Glitch, this, origPtT, testPtT); 1407cb93a386Sopenharmony_ci } 1408cb93a386Sopenharmony_ci} 1409cb93a386Sopenharmony_ci 1410cb93a386Sopenharmony_ci 1411cb93a386Sopenharmony_ci/* Commented-out lines keep this in sync with correctEnds */ 1412cb93a386Sopenharmony_ci// FIXME: member pointers have fallen out of favor and can be replaced with 1413cb93a386Sopenharmony_ci// an alternative approach. 1414cb93a386Sopenharmony_ci// makes all span ends agree with the segment's spans that define them 1415cb93a386Sopenharmony_civoid SkCoincidentSpans::debugCorrectEnds(SkPathOpsDebug::GlitchLog* log) const { 1416cb93a386Sopenharmony_ci this->debugCorrectOneEnd(log, &SkCoincidentSpans::coinPtTStart, nullptr); 1417cb93a386Sopenharmony_ci this->debugCorrectOneEnd(log, &SkCoincidentSpans::coinPtTEnd, nullptr); 1418cb93a386Sopenharmony_ci this->debugCorrectOneEnd(log, &SkCoincidentSpans::oppPtTStart, nullptr); 1419cb93a386Sopenharmony_ci this->debugCorrectOneEnd(log, &SkCoincidentSpans::oppPtTEnd, nullptr); 1420cb93a386Sopenharmony_ci} 1421cb93a386Sopenharmony_ci 1422cb93a386Sopenharmony_ci/* Commented-out lines keep this in sync with expand */ 1423cb93a386Sopenharmony_ci// expand the range by checking adjacent spans for coincidence 1424cb93a386Sopenharmony_cibool SkCoincidentSpans::debugExpand(SkPathOpsDebug::GlitchLog* log) const { 1425cb93a386Sopenharmony_ci bool expanded = false; 1426cb93a386Sopenharmony_ci const SkOpSegment* segment = coinPtTStart()->segment(); 1427cb93a386Sopenharmony_ci const SkOpSegment* oppSegment = oppPtTStart()->segment(); 1428cb93a386Sopenharmony_ci do { 1429cb93a386Sopenharmony_ci const SkOpSpan* start = coinPtTStart()->span()->upCast(); 1430cb93a386Sopenharmony_ci const SkOpSpan* prev = start->prev(); 1431cb93a386Sopenharmony_ci const SkOpPtT* oppPtT; 1432cb93a386Sopenharmony_ci if (!prev || !(oppPtT = prev->contains(oppSegment))) { 1433cb93a386Sopenharmony_ci break; 1434cb93a386Sopenharmony_ci } 1435cb93a386Sopenharmony_ci double midT = (prev->t() + start->t()) / 2; 1436cb93a386Sopenharmony_ci if (!segment->isClose(midT, oppSegment)) { 1437cb93a386Sopenharmony_ci break; 1438cb93a386Sopenharmony_ci } 1439cb93a386Sopenharmony_ci if (log) log->record(SkPathOpsDebug::kExpandCoin_Glitch, this, prev->ptT(), oppPtT); 1440cb93a386Sopenharmony_ci expanded = true; 1441cb93a386Sopenharmony_ci } while (false); // actual continues while expansion is possible 1442cb93a386Sopenharmony_ci do { 1443cb93a386Sopenharmony_ci const SkOpSpanBase* end = coinPtTEnd()->span(); 1444cb93a386Sopenharmony_ci SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next(); 1445cb93a386Sopenharmony_ci if (next && next->deleted()) { 1446cb93a386Sopenharmony_ci break; 1447cb93a386Sopenharmony_ci } 1448cb93a386Sopenharmony_ci const SkOpPtT* oppPtT; 1449cb93a386Sopenharmony_ci if (!next || !(oppPtT = next->contains(oppSegment))) { 1450cb93a386Sopenharmony_ci break; 1451cb93a386Sopenharmony_ci } 1452cb93a386Sopenharmony_ci double midT = (end->t() + next->t()) / 2; 1453cb93a386Sopenharmony_ci if (!segment->isClose(midT, oppSegment)) { 1454cb93a386Sopenharmony_ci break; 1455cb93a386Sopenharmony_ci } 1456cb93a386Sopenharmony_ci if (log) log->record(SkPathOpsDebug::kExpandCoin_Glitch, this, next->ptT(), oppPtT); 1457cb93a386Sopenharmony_ci expanded = true; 1458cb93a386Sopenharmony_ci } while (false); // actual continues while expansion is possible 1459cb93a386Sopenharmony_ci return expanded; 1460cb93a386Sopenharmony_ci} 1461cb93a386Sopenharmony_ci 1462cb93a386Sopenharmony_ci// description below 1463cb93a386Sopenharmony_civoid SkOpCoincidence::debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* log, const SkOpSpan* base, const SkOpSpanBase* testSpan) const { 1464cb93a386Sopenharmony_ci const SkOpPtT* testPtT = testSpan->ptT(); 1465cb93a386Sopenharmony_ci const SkOpPtT* stopPtT = testPtT; 1466cb93a386Sopenharmony_ci const SkOpSegment* baseSeg = base->segment(); 1467cb93a386Sopenharmony_ci while ((testPtT = testPtT->next()) != stopPtT) { 1468cb93a386Sopenharmony_ci const SkOpSegment* testSeg = testPtT->segment(); 1469cb93a386Sopenharmony_ci if (testPtT->deleted()) { 1470cb93a386Sopenharmony_ci continue; 1471cb93a386Sopenharmony_ci } 1472cb93a386Sopenharmony_ci if (testSeg == baseSeg) { 1473cb93a386Sopenharmony_ci continue; 1474cb93a386Sopenharmony_ci } 1475cb93a386Sopenharmony_ci if (testPtT->span()->ptT() != testPtT) { 1476cb93a386Sopenharmony_ci continue; 1477cb93a386Sopenharmony_ci } 1478cb93a386Sopenharmony_ci if (this->contains(baseSeg, testSeg, testPtT->fT)) { 1479cb93a386Sopenharmony_ci continue; 1480cb93a386Sopenharmony_ci } 1481cb93a386Sopenharmony_ci // intersect perp with base->ptT() with testPtT->segment() 1482cb93a386Sopenharmony_ci SkDVector dxdy = baseSeg->dSlopeAtT(base->t()); 1483cb93a386Sopenharmony_ci const SkPoint& pt = base->pt(); 1484cb93a386Sopenharmony_ci SkDLine ray = {{{pt.fX, pt.fY}, {pt.fX + dxdy.fY, pt.fY - dxdy.fX}}}; 1485cb93a386Sopenharmony_ci SkIntersections i; 1486cb93a386Sopenharmony_ci (*CurveIntersectRay[testSeg->verb()])(testSeg->pts(), testSeg->weight(), ray, &i); 1487cb93a386Sopenharmony_ci for (int index = 0; index < i.used(); ++index) { 1488cb93a386Sopenharmony_ci double t = i[0][index]; 1489cb93a386Sopenharmony_ci if (!between(0, t, 1)) { 1490cb93a386Sopenharmony_ci continue; 1491cb93a386Sopenharmony_ci } 1492cb93a386Sopenharmony_ci SkDPoint oppPt = i.pt(index); 1493cb93a386Sopenharmony_ci if (!oppPt.approximatelyEqual(pt)) { 1494cb93a386Sopenharmony_ci continue; 1495cb93a386Sopenharmony_ci } 1496cb93a386Sopenharmony_ci SkOpSegment* writableSeg = const_cast<SkOpSegment*>(testSeg); 1497cb93a386Sopenharmony_ci SkOpPtT* oppStart = writableSeg->addT(t); 1498cb93a386Sopenharmony_ci if (oppStart == testPtT) { 1499cb93a386Sopenharmony_ci continue; 1500cb93a386Sopenharmony_ci } 1501cb93a386Sopenharmony_ci SkOpSpan* writableBase = const_cast<SkOpSpan*>(base); 1502cb93a386Sopenharmony_ci oppStart->span()->addOpp(writableBase); 1503cb93a386Sopenharmony_ci if (oppStart->deleted()) { 1504cb93a386Sopenharmony_ci continue; 1505cb93a386Sopenharmony_ci } 1506cb93a386Sopenharmony_ci SkOpSegment* coinSeg = base->segment(); 1507cb93a386Sopenharmony_ci SkOpSegment* oppSeg = oppStart->segment(); 1508cb93a386Sopenharmony_ci double coinTs, coinTe, oppTs, oppTe; 1509cb93a386Sopenharmony_ci if (Ordered(coinSeg, oppSeg)) { 1510cb93a386Sopenharmony_ci coinTs = base->t(); 1511cb93a386Sopenharmony_ci coinTe = testSpan->t(); 1512cb93a386Sopenharmony_ci oppTs = oppStart->fT; 1513cb93a386Sopenharmony_ci oppTe = testPtT->fT; 1514cb93a386Sopenharmony_ci } else { 1515cb93a386Sopenharmony_ci using std::swap; 1516cb93a386Sopenharmony_ci swap(coinSeg, oppSeg); 1517cb93a386Sopenharmony_ci coinTs = oppStart->fT; 1518cb93a386Sopenharmony_ci coinTe = testPtT->fT; 1519cb93a386Sopenharmony_ci oppTs = base->t(); 1520cb93a386Sopenharmony_ci oppTe = testSpan->t(); 1521cb93a386Sopenharmony_ci } 1522cb93a386Sopenharmony_ci if (coinTs > coinTe) { 1523cb93a386Sopenharmony_ci using std::swap; 1524cb93a386Sopenharmony_ci swap(coinTs, coinTe); 1525cb93a386Sopenharmony_ci swap(oppTs, oppTe); 1526cb93a386Sopenharmony_ci } 1527cb93a386Sopenharmony_ci bool added; 1528cb93a386Sopenharmony_ci if (this->debugAddOrOverlap(log, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, &added), false) { 1529cb93a386Sopenharmony_ci return; 1530cb93a386Sopenharmony_ci } 1531cb93a386Sopenharmony_ci } 1532cb93a386Sopenharmony_ci } 1533cb93a386Sopenharmony_ci return; 1534cb93a386Sopenharmony_ci} 1535cb93a386Sopenharmony_ci 1536cb93a386Sopenharmony_ci// description below 1537cb93a386Sopenharmony_civoid SkOpCoincidence::debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* log, const SkOpPtT* ptT) const { 1538cb93a386Sopenharmony_ci FAIL_IF(!ptT->span()->upCastable(), ptT->span()); 1539cb93a386Sopenharmony_ci const SkOpSpan* base = ptT->span()->upCast(); 1540cb93a386Sopenharmony_ci const SkOpSpan* prev = base->prev(); 1541cb93a386Sopenharmony_ci FAIL_IF(!prev, ptT->span()); 1542cb93a386Sopenharmony_ci if (!prev->isCanceled()) { 1543cb93a386Sopenharmony_ci if (this->debugAddEndMovedSpans(log, base, base->prev()), false) { 1544cb93a386Sopenharmony_ci return; 1545cb93a386Sopenharmony_ci } 1546cb93a386Sopenharmony_ci } 1547cb93a386Sopenharmony_ci if (!base->isCanceled()) { 1548cb93a386Sopenharmony_ci if (this->debugAddEndMovedSpans(log, base, base->next()), false) { 1549cb93a386Sopenharmony_ci return; 1550cb93a386Sopenharmony_ci } 1551cb93a386Sopenharmony_ci } 1552cb93a386Sopenharmony_ci return; 1553cb93a386Sopenharmony_ci} 1554cb93a386Sopenharmony_ci 1555cb93a386Sopenharmony_ci/* If A is coincident with B and B includes an endpoint, and A's matching point 1556cb93a386Sopenharmony_ci is not the endpoint (i.e., there's an implied line connecting B-end and A) 1557cb93a386Sopenharmony_ci then assume that the same implied line may intersect another curve close to B. 1558cb93a386Sopenharmony_ci Since we only care about coincidence that was undetected, look at the 1559cb93a386Sopenharmony_ci ptT list on B-segment adjacent to the B-end/A ptT loop (not in the loop, but 1560cb93a386Sopenharmony_ci next door) and see if the A matching point is close enough to form another 1561cb93a386Sopenharmony_ci coincident pair. If so, check for a new coincident span between B-end/A ptT loop 1562cb93a386Sopenharmony_ci and the adjacent ptT loop. 1563cb93a386Sopenharmony_ci*/ 1564cb93a386Sopenharmony_civoid SkOpCoincidence::debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* log) const { 1565cb93a386Sopenharmony_ci const SkCoincidentSpans* span = fHead; 1566cb93a386Sopenharmony_ci if (!span) { 1567cb93a386Sopenharmony_ci return; 1568cb93a386Sopenharmony_ci } 1569cb93a386Sopenharmony_ci// fTop = span; 1570cb93a386Sopenharmony_ci// fHead = nullptr; 1571cb93a386Sopenharmony_ci do { 1572cb93a386Sopenharmony_ci if (span->coinPtTStart()->fPt != span->oppPtTStart()->fPt) { 1573cb93a386Sopenharmony_ci FAIL_IF(1 == span->coinPtTStart()->fT, span); 1574cb93a386Sopenharmony_ci bool onEnd = span->coinPtTStart()->fT == 0; 1575cb93a386Sopenharmony_ci bool oOnEnd = zero_or_one(span->oppPtTStart()->fT); 1576cb93a386Sopenharmony_ci if (onEnd) { 1577cb93a386Sopenharmony_ci if (!oOnEnd) { // if both are on end, any nearby intersect was already found 1578cb93a386Sopenharmony_ci if (this->debugAddEndMovedSpans(log, span->oppPtTStart()), false) { 1579cb93a386Sopenharmony_ci return; 1580cb93a386Sopenharmony_ci } 1581cb93a386Sopenharmony_ci } 1582cb93a386Sopenharmony_ci } else if (oOnEnd) { 1583cb93a386Sopenharmony_ci if (this->debugAddEndMovedSpans(log, span->coinPtTStart()), false) { 1584cb93a386Sopenharmony_ci return; 1585cb93a386Sopenharmony_ci } 1586cb93a386Sopenharmony_ci } 1587cb93a386Sopenharmony_ci } 1588cb93a386Sopenharmony_ci if (span->coinPtTEnd()->fPt != span->oppPtTEnd()->fPt) { 1589cb93a386Sopenharmony_ci bool onEnd = span->coinPtTEnd()->fT == 1; 1590cb93a386Sopenharmony_ci bool oOnEnd = zero_or_one(span->oppPtTEnd()->fT); 1591cb93a386Sopenharmony_ci if (onEnd) { 1592cb93a386Sopenharmony_ci if (!oOnEnd) { 1593cb93a386Sopenharmony_ci if (this->debugAddEndMovedSpans(log, span->oppPtTEnd()), false) { 1594cb93a386Sopenharmony_ci return; 1595cb93a386Sopenharmony_ci } 1596cb93a386Sopenharmony_ci } 1597cb93a386Sopenharmony_ci } else if (oOnEnd) { 1598cb93a386Sopenharmony_ci if (this->debugAddEndMovedSpans(log, span->coinPtTEnd()), false) { 1599cb93a386Sopenharmony_ci return; 1600cb93a386Sopenharmony_ci } 1601cb93a386Sopenharmony_ci } 1602cb93a386Sopenharmony_ci } 1603cb93a386Sopenharmony_ci } while ((span = span->next())); 1604cb93a386Sopenharmony_ci// this->restoreHead(); 1605cb93a386Sopenharmony_ci return; 1606cb93a386Sopenharmony_ci} 1607cb93a386Sopenharmony_ci 1608cb93a386Sopenharmony_ci/* Commented-out lines keep this in sync with addExpanded */ 1609cb93a386Sopenharmony_ci// for each coincident pair, match the spans 1610cb93a386Sopenharmony_ci// if the spans don't match, add the mssing pt to the segment and loop it in the opposite span 1611cb93a386Sopenharmony_civoid SkOpCoincidence::debugAddExpanded(SkPathOpsDebug::GlitchLog* log) const { 1612cb93a386Sopenharmony_ci// DEBUG_SET_PHASE(); 1613cb93a386Sopenharmony_ci const SkCoincidentSpans* coin = this->fHead; 1614cb93a386Sopenharmony_ci if (!coin) { 1615cb93a386Sopenharmony_ci return; 1616cb93a386Sopenharmony_ci } 1617cb93a386Sopenharmony_ci do { 1618cb93a386Sopenharmony_ci const SkOpPtT* startPtT = coin->coinPtTStart(); 1619cb93a386Sopenharmony_ci const SkOpPtT* oStartPtT = coin->oppPtTStart(); 1620cb93a386Sopenharmony_ci double priorT = startPtT->fT; 1621cb93a386Sopenharmony_ci double oPriorT = oStartPtT->fT; 1622cb93a386Sopenharmony_ci FAIL_IF(!startPtT->contains(oStartPtT), coin); 1623cb93a386Sopenharmony_ci SkOPASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd())); 1624cb93a386Sopenharmony_ci const SkOpSpanBase* start = startPtT->span(); 1625cb93a386Sopenharmony_ci const SkOpSpanBase* oStart = oStartPtT->span(); 1626cb93a386Sopenharmony_ci const SkOpSpanBase* end = coin->coinPtTEnd()->span(); 1627cb93a386Sopenharmony_ci const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span(); 1628cb93a386Sopenharmony_ci FAIL_IF(oEnd->deleted(), coin); 1629cb93a386Sopenharmony_ci FAIL_IF(!start->upCastable(), coin); 1630cb93a386Sopenharmony_ci const SkOpSpanBase* test = start->upCast()->next(); 1631cb93a386Sopenharmony_ci FAIL_IF(!coin->flipped() && !oStart->upCastable(), coin); 1632cb93a386Sopenharmony_ci const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->upCast()->next(); 1633cb93a386Sopenharmony_ci FAIL_IF(!oTest, coin); 1634cb93a386Sopenharmony_ci const SkOpSegment* seg = start->segment(); 1635cb93a386Sopenharmony_ci const SkOpSegment* oSeg = oStart->segment(); 1636cb93a386Sopenharmony_ci while (test != end || oTest != oEnd) { 1637cb93a386Sopenharmony_ci const SkOpPtT* containedOpp = test->ptT()->contains(oSeg); 1638cb93a386Sopenharmony_ci const SkOpPtT* containedThis = oTest->ptT()->contains(seg); 1639cb93a386Sopenharmony_ci if (!containedOpp || !containedThis) { 1640cb93a386Sopenharmony_ci // choose the ends, or the first common pt-t list shared by both 1641cb93a386Sopenharmony_ci double nextT, oNextT; 1642cb93a386Sopenharmony_ci if (containedOpp) { 1643cb93a386Sopenharmony_ci nextT = test->t(); 1644cb93a386Sopenharmony_ci oNextT = containedOpp->fT; 1645cb93a386Sopenharmony_ci } else if (containedThis) { 1646cb93a386Sopenharmony_ci nextT = containedThis->fT; 1647cb93a386Sopenharmony_ci oNextT = oTest->t(); 1648cb93a386Sopenharmony_ci } else { 1649cb93a386Sopenharmony_ci // iterate through until a pt-t list found that contains the other 1650cb93a386Sopenharmony_ci const SkOpSpanBase* walk = test; 1651cb93a386Sopenharmony_ci const SkOpPtT* walkOpp; 1652cb93a386Sopenharmony_ci do { 1653cb93a386Sopenharmony_ci FAIL_IF(!walk->upCastable(), coin); 1654cb93a386Sopenharmony_ci walk = walk->upCast()->next(); 1655cb93a386Sopenharmony_ci } while (!(walkOpp = walk->ptT()->contains(oSeg)) 1656cb93a386Sopenharmony_ci && walk != coin->coinPtTEnd()->span()); 1657cb93a386Sopenharmony_ci FAIL_IF(!walkOpp, coin); 1658cb93a386Sopenharmony_ci nextT = walk->t(); 1659cb93a386Sopenharmony_ci oNextT = walkOpp->fT; 1660cb93a386Sopenharmony_ci } 1661cb93a386Sopenharmony_ci // use t ranges to guess which one is missing 1662cb93a386Sopenharmony_ci double startRange = nextT - priorT; 1663cb93a386Sopenharmony_ci FAIL_IF(!startRange, coin); 1664cb93a386Sopenharmony_ci double startPart = (test->t() - priorT) / startRange; 1665cb93a386Sopenharmony_ci double oStartRange = oNextT - oPriorT; 1666cb93a386Sopenharmony_ci FAIL_IF(!oStartRange, coin); 1667cb93a386Sopenharmony_ci double oStartPart = (oTest->t() - oStartPtT->fT) / oStartRange; 1668cb93a386Sopenharmony_ci FAIL_IF(startPart == oStartPart, coin); 1669cb93a386Sopenharmony_ci bool addToOpp = !containedOpp && !containedThis ? startPart < oStartPart 1670cb93a386Sopenharmony_ci : !!containedThis; 1671cb93a386Sopenharmony_ci bool startOver = false; 1672cb93a386Sopenharmony_ci addToOpp ? log->record(SkPathOpsDebug::kAddExpandedCoin_Glitch, 1673cb93a386Sopenharmony_ci oPriorT + oStartRange * startPart, test) 1674cb93a386Sopenharmony_ci : log->record(SkPathOpsDebug::kAddExpandedCoin_Glitch, 1675cb93a386Sopenharmony_ci priorT + startRange * oStartPart, oTest); 1676cb93a386Sopenharmony_ci // FAIL_IF(!success, coin); 1677cb93a386Sopenharmony_ci if (startOver) { 1678cb93a386Sopenharmony_ci test = start; 1679cb93a386Sopenharmony_ci oTest = oStart; 1680cb93a386Sopenharmony_ci } 1681cb93a386Sopenharmony_ci end = coin->coinPtTEnd()->span(); 1682cb93a386Sopenharmony_ci oEnd = coin->oppPtTEnd()->span(); 1683cb93a386Sopenharmony_ci } 1684cb93a386Sopenharmony_ci if (test != end) { 1685cb93a386Sopenharmony_ci FAIL_IF(!test->upCastable(), coin); 1686cb93a386Sopenharmony_ci priorT = test->t(); 1687cb93a386Sopenharmony_ci test = test->upCast()->next(); 1688cb93a386Sopenharmony_ci } 1689cb93a386Sopenharmony_ci if (oTest != oEnd) { 1690cb93a386Sopenharmony_ci oPriorT = oTest->t(); 1691cb93a386Sopenharmony_ci oTest = coin->flipped() ? oTest->prev() : oTest->upCast()->next(); 1692cb93a386Sopenharmony_ci FAIL_IF(!oTest, coin); 1693cb93a386Sopenharmony_ci } 1694cb93a386Sopenharmony_ci } 1695cb93a386Sopenharmony_ci } while ((coin = coin->next())); 1696cb93a386Sopenharmony_ci return; 1697cb93a386Sopenharmony_ci} 1698cb93a386Sopenharmony_ci 1699cb93a386Sopenharmony_ci/* Commented-out lines keep this in sync addIfMissing() */ 1700cb93a386Sopenharmony_ci// note that over1s, over1e, over2s, over2e are ordered 1701cb93a386Sopenharmony_civoid SkOpCoincidence::debugAddIfMissing(SkPathOpsDebug::GlitchLog* log, const SkOpPtT* over1s, const SkOpPtT* over2s, 1702cb93a386Sopenharmony_ci double tStart, double tEnd, const SkOpSegment* coinSeg, const SkOpSegment* oppSeg, bool* added, 1703cb93a386Sopenharmony_ci const SkOpPtT* over1e, const SkOpPtT* over2e) const { 1704cb93a386Sopenharmony_ci SkASSERT(tStart < tEnd); 1705cb93a386Sopenharmony_ci SkASSERT(over1s->fT < over1e->fT); 1706cb93a386Sopenharmony_ci SkASSERT(between(over1s->fT, tStart, over1e->fT)); 1707cb93a386Sopenharmony_ci SkASSERT(between(over1s->fT, tEnd, over1e->fT)); 1708cb93a386Sopenharmony_ci SkASSERT(over2s->fT < over2e->fT); 1709cb93a386Sopenharmony_ci SkASSERT(between(over2s->fT, tStart, over2e->fT)); 1710cb93a386Sopenharmony_ci SkASSERT(between(over2s->fT, tEnd, over2e->fT)); 1711cb93a386Sopenharmony_ci SkASSERT(over1s->segment() == over1e->segment()); 1712cb93a386Sopenharmony_ci SkASSERT(over2s->segment() == over2e->segment()); 1713cb93a386Sopenharmony_ci SkASSERT(over1s->segment() == over2s->segment()); 1714cb93a386Sopenharmony_ci SkASSERT(over1s->segment() != coinSeg); 1715cb93a386Sopenharmony_ci SkASSERT(over1s->segment() != oppSeg); 1716cb93a386Sopenharmony_ci SkASSERT(coinSeg != oppSeg); 1717cb93a386Sopenharmony_ci double coinTs, coinTe, oppTs, oppTe; 1718cb93a386Sopenharmony_ci coinTs = TRange(over1s, tStart, coinSeg SkDEBUGPARAMS(over1e)); 1719cb93a386Sopenharmony_ci coinTe = TRange(over1s, tEnd, coinSeg SkDEBUGPARAMS(over1e)); 1720cb93a386Sopenharmony_ci SkOpSpanBase::Collapsed result = coinSeg->collapsed(coinTs, coinTe); 1721cb93a386Sopenharmony_ci if (SkOpSpanBase::Collapsed::kNo != result) { 1722cb93a386Sopenharmony_ci return log->record(SkPathOpsDebug::kAddIfCollapsed_Glitch, coinSeg); 1723cb93a386Sopenharmony_ci } 1724cb93a386Sopenharmony_ci oppTs = TRange(over2s, tStart, oppSeg SkDEBUGPARAMS(over2e)); 1725cb93a386Sopenharmony_ci oppTe = TRange(over2s, tEnd, oppSeg SkDEBUGPARAMS(over2e)); 1726cb93a386Sopenharmony_ci result = oppSeg->collapsed(oppTs, oppTe); 1727cb93a386Sopenharmony_ci if (SkOpSpanBase::Collapsed::kNo != result) { 1728cb93a386Sopenharmony_ci return log->record(SkPathOpsDebug::kAddIfCollapsed_Glitch, oppSeg); 1729cb93a386Sopenharmony_ci } 1730cb93a386Sopenharmony_ci if (coinTs > coinTe) { 1731cb93a386Sopenharmony_ci using std::swap; 1732cb93a386Sopenharmony_ci swap(coinTs, coinTe); 1733cb93a386Sopenharmony_ci swap(oppTs, oppTe); 1734cb93a386Sopenharmony_ci } 1735cb93a386Sopenharmony_ci this->debugAddOrOverlap(log, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, added); 1736cb93a386Sopenharmony_ci return; 1737cb93a386Sopenharmony_ci} 1738cb93a386Sopenharmony_ci 1739cb93a386Sopenharmony_ci/* Commented-out lines keep this in sync addOrOverlap() */ 1740cb93a386Sopenharmony_ci// If this is called by addEndMovedSpans(), a returned false propogates out to an abort. 1741cb93a386Sopenharmony_ci// If this is called by AddIfMissing(), a returned false indicates there was nothing to add 1742cb93a386Sopenharmony_civoid SkOpCoincidence::debugAddOrOverlap(SkPathOpsDebug::GlitchLog* log, 1743cb93a386Sopenharmony_ci const SkOpSegment* coinSeg, const SkOpSegment* oppSeg, 1744cb93a386Sopenharmony_ci double coinTs, double coinTe, double oppTs, double oppTe, bool* added) const { 1745cb93a386Sopenharmony_ci SkTDArray<SkCoincidentSpans*> overlaps; 1746cb93a386Sopenharmony_ci SkOPASSERT(!fTop); // this is (correctly) reversed in addifMissing() 1747cb93a386Sopenharmony_ci if (fTop && !this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe, 1748cb93a386Sopenharmony_ci &overlaps)) { 1749cb93a386Sopenharmony_ci return; 1750cb93a386Sopenharmony_ci } 1751cb93a386Sopenharmony_ci if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs, 1752cb93a386Sopenharmony_ci coinTe, oppTs, oppTe, &overlaps)) { 1753cb93a386Sopenharmony_ci return; 1754cb93a386Sopenharmony_ci } 1755cb93a386Sopenharmony_ci const SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr; 1756cb93a386Sopenharmony_ci for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing 1757cb93a386Sopenharmony_ci const SkCoincidentSpans* test = overlaps[index]; 1758cb93a386Sopenharmony_ci if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) { 1759cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap, test->coinPtTStart()); 1760cb93a386Sopenharmony_ci } 1761cb93a386Sopenharmony_ci if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) { 1762cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap, test->coinPtTEnd()); 1763cb93a386Sopenharmony_ci } 1764cb93a386Sopenharmony_ci if (overlap->flipped() 1765cb93a386Sopenharmony_ci ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT 1766cb93a386Sopenharmony_ci : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) { 1767cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap, test->oppPtTStart()); 1768cb93a386Sopenharmony_ci } 1769cb93a386Sopenharmony_ci if (overlap->flipped() 1770cb93a386Sopenharmony_ci ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT 1771cb93a386Sopenharmony_ci : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) { 1772cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kAddOrOverlap_Glitch, overlap, test->oppPtTEnd()); 1773cb93a386Sopenharmony_ci } 1774cb93a386Sopenharmony_ci if (!fHead) { this->debugRelease(log, fHead, test); 1775cb93a386Sopenharmony_ci this->debugRelease(log, fTop, test); 1776cb93a386Sopenharmony_ci } 1777cb93a386Sopenharmony_ci } 1778cb93a386Sopenharmony_ci const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg); 1779cb93a386Sopenharmony_ci const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg); 1780cb93a386Sopenharmony_ci RETURN_FALSE_IF(overlap && cs && ce && overlap->contains(cs, ce), coinSeg); 1781cb93a386Sopenharmony_ci RETURN_FALSE_IF(cs != ce || !cs, coinSeg); 1782cb93a386Sopenharmony_ci const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg); 1783cb93a386Sopenharmony_ci const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg); 1784cb93a386Sopenharmony_ci RETURN_FALSE_IF(overlap && os && oe && overlap->contains(os, oe), oppSeg); 1785cb93a386Sopenharmony_ci SkASSERT(true || !cs || !cs->deleted()); 1786cb93a386Sopenharmony_ci SkASSERT(true || !os || !os->deleted()); 1787cb93a386Sopenharmony_ci SkASSERT(true || !ce || !ce->deleted()); 1788cb93a386Sopenharmony_ci SkASSERT(true || !oe || !oe->deleted()); 1789cb93a386Sopenharmony_ci const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullptr; 1790cb93a386Sopenharmony_ci const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullptr; 1791cb93a386Sopenharmony_ci RETURN_FALSE_IF(csExisting && csExisting == ceExisting, coinSeg); 1792cb93a386Sopenharmony_ci RETURN_FALSE_IF(csExisting && (csExisting == ce || 1793cb93a386Sopenharmony_ci csExisting->contains(ceExisting ? ceExisting : ce)), coinSeg); 1794cb93a386Sopenharmony_ci RETURN_FALSE_IF(ceExisting && (ceExisting == cs || 1795cb93a386Sopenharmony_ci ceExisting->contains(csExisting ? csExisting : cs)), coinSeg); 1796cb93a386Sopenharmony_ci const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr; 1797cb93a386Sopenharmony_ci const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr; 1798cb93a386Sopenharmony_ci RETURN_FALSE_IF(osExisting && osExisting == oeExisting, oppSeg); 1799cb93a386Sopenharmony_ci RETURN_FALSE_IF(osExisting && (osExisting == oe || 1800cb93a386Sopenharmony_ci osExisting->contains(oeExisting ? oeExisting : oe)), oppSeg); 1801cb93a386Sopenharmony_ci RETURN_FALSE_IF(oeExisting && (oeExisting == os || 1802cb93a386Sopenharmony_ci oeExisting->contains(osExisting ? osExisting : os)), oppSeg); 1803cb93a386Sopenharmony_ci bool csDeleted = false, osDeleted = false, ceDeleted = false, oeDeleted = false; 1804cb93a386Sopenharmony_ci this->debugValidate(); 1805cb93a386Sopenharmony_ci if (!cs || !os) { 1806cb93a386Sopenharmony_ci if (!cs) 1807cb93a386Sopenharmony_ci cs = coinSeg->debugAddT(coinTs, log); 1808cb93a386Sopenharmony_ci if (!os) 1809cb93a386Sopenharmony_ci os = oppSeg->debugAddT(oppTs, log); 1810cb93a386Sopenharmony_ci// RETURN_FALSE_IF(callerAborts, !csWritable || !osWritable); 1811cb93a386Sopenharmony_ci if (cs && os) cs->span()->debugAddOpp(log, os->span()); 1812cb93a386Sopenharmony_ci// cs = csWritable; 1813cb93a386Sopenharmony_ci// os = osWritable->active(); 1814cb93a386Sopenharmony_ci RETURN_FALSE_IF((ce && ce->deleted()) || (oe && oe->deleted()), coinSeg); 1815cb93a386Sopenharmony_ci } 1816cb93a386Sopenharmony_ci if (!ce || !oe) { 1817cb93a386Sopenharmony_ci if (!ce) 1818cb93a386Sopenharmony_ci ce = coinSeg->debugAddT(coinTe, log); 1819cb93a386Sopenharmony_ci if (!oe) 1820cb93a386Sopenharmony_ci oe = oppSeg->debugAddT(oppTe, log); 1821cb93a386Sopenharmony_ci if (ce && oe) ce->span()->debugAddOpp(log, oe->span()); 1822cb93a386Sopenharmony_ci// ce = ceWritable; 1823cb93a386Sopenharmony_ci// oe = oeWritable; 1824cb93a386Sopenharmony_ci } 1825cb93a386Sopenharmony_ci this->debugValidate(); 1826cb93a386Sopenharmony_ci RETURN_FALSE_IF(csDeleted, coinSeg); 1827cb93a386Sopenharmony_ci RETURN_FALSE_IF(osDeleted, oppSeg); 1828cb93a386Sopenharmony_ci RETURN_FALSE_IF(ceDeleted, coinSeg); 1829cb93a386Sopenharmony_ci RETURN_FALSE_IF(oeDeleted, oppSeg); 1830cb93a386Sopenharmony_ci RETURN_FALSE_IF(!cs || !ce || cs == ce || cs->contains(ce) || !os || !oe || os == oe || os->contains(oe), coinSeg); 1831cb93a386Sopenharmony_ci bool result = true; 1832cb93a386Sopenharmony_ci if (overlap) { 1833cb93a386Sopenharmony_ci if (overlap->coinPtTStart()->segment() == coinSeg) { 1834cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kAddMissingExtend_Glitch, coinSeg, coinTs, coinTe, oppSeg, oppTs, oppTe); 1835cb93a386Sopenharmony_ci } else { 1836cb93a386Sopenharmony_ci if (oppTs > oppTe) { 1837cb93a386Sopenharmony_ci using std::swap; 1838cb93a386Sopenharmony_ci swap(coinTs, coinTe); 1839cb93a386Sopenharmony_ci swap(oppTs, oppTe); 1840cb93a386Sopenharmony_ci } 1841cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kAddMissingExtend_Glitch, oppSeg, oppTs, oppTe, coinSeg, coinTs, coinTe); 1842cb93a386Sopenharmony_ci } 1843cb93a386Sopenharmony_ci#if 0 && DEBUG_COINCIDENCE_VERBOSE 1844cb93a386Sopenharmony_ci if (result) { 1845cb93a386Sopenharmony_ci overlap->debugShow(); 1846cb93a386Sopenharmony_ci } 1847cb93a386Sopenharmony_ci#endif 1848cb93a386Sopenharmony_ci } else { 1849cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kAddMissingCoin_Glitch, coinSeg, coinTs, coinTe, oppSeg, oppTs, oppTe); 1850cb93a386Sopenharmony_ci#if 0 && DEBUG_COINCIDENCE_VERBOSE 1851cb93a386Sopenharmony_ci fHead->debugShow(); 1852cb93a386Sopenharmony_ci#endif 1853cb93a386Sopenharmony_ci } 1854cb93a386Sopenharmony_ci this->debugValidate(); 1855cb93a386Sopenharmony_ci return (void) result; 1856cb93a386Sopenharmony_ci} 1857cb93a386Sopenharmony_ci 1858cb93a386Sopenharmony_ci// Extra commented-out lines keep this in sync with addMissing() 1859cb93a386Sopenharmony_ci/* detects overlaps of different coincident runs on same segment */ 1860cb93a386Sopenharmony_ci/* does not detect overlaps for pairs without any segments in common */ 1861cb93a386Sopenharmony_ci// returns true if caller should loop again 1862cb93a386Sopenharmony_civoid SkOpCoincidence::debugAddMissing(SkPathOpsDebug::GlitchLog* log, bool* added) const { 1863cb93a386Sopenharmony_ci const SkCoincidentSpans* outer = fHead; 1864cb93a386Sopenharmony_ci *added = false; 1865cb93a386Sopenharmony_ci if (!outer) { 1866cb93a386Sopenharmony_ci return; 1867cb93a386Sopenharmony_ci } 1868cb93a386Sopenharmony_ci // fTop = outer; 1869cb93a386Sopenharmony_ci // fHead = nullptr; 1870cb93a386Sopenharmony_ci do { 1871cb93a386Sopenharmony_ci // addifmissing can modify the list that this is walking 1872cb93a386Sopenharmony_ci // save head so that walker can iterate over old data unperturbed 1873cb93a386Sopenharmony_ci // addifmissing adds to head freely then add saved head in the end 1874cb93a386Sopenharmony_ci const SkOpPtT* ocs = outer->coinPtTStart(); 1875cb93a386Sopenharmony_ci SkASSERT(!ocs->deleted()); 1876cb93a386Sopenharmony_ci const SkOpSegment* outerCoin = ocs->segment(); 1877cb93a386Sopenharmony_ci SkASSERT(!outerCoin->done()); // if it's done, should have already been removed from list 1878cb93a386Sopenharmony_ci const SkOpPtT* oos = outer->oppPtTStart(); 1879cb93a386Sopenharmony_ci if (oos->deleted()) { 1880cb93a386Sopenharmony_ci return; 1881cb93a386Sopenharmony_ci } 1882cb93a386Sopenharmony_ci const SkOpSegment* outerOpp = oos->segment(); 1883cb93a386Sopenharmony_ci SkASSERT(!outerOpp->done()); 1884cb93a386Sopenharmony_ci// SkOpSegment* outerCoinWritable = const_cast<SkOpSegment*>(outerCoin); 1885cb93a386Sopenharmony_ci// SkOpSegment* outerOppWritable = const_cast<SkOpSegment*>(outerOpp); 1886cb93a386Sopenharmony_ci const SkCoincidentSpans* inner = outer; 1887cb93a386Sopenharmony_ci while ((inner = inner->next())) { 1888cb93a386Sopenharmony_ci this->debugValidate(); 1889cb93a386Sopenharmony_ci double overS, overE; 1890cb93a386Sopenharmony_ci const SkOpPtT* ics = inner->coinPtTStart(); 1891cb93a386Sopenharmony_ci SkASSERT(!ics->deleted()); 1892cb93a386Sopenharmony_ci const SkOpSegment* innerCoin = ics->segment(); 1893cb93a386Sopenharmony_ci SkASSERT(!innerCoin->done()); 1894cb93a386Sopenharmony_ci const SkOpPtT* ios = inner->oppPtTStart(); 1895cb93a386Sopenharmony_ci SkASSERT(!ios->deleted()); 1896cb93a386Sopenharmony_ci const SkOpSegment* innerOpp = ios->segment(); 1897cb93a386Sopenharmony_ci SkASSERT(!innerOpp->done()); 1898cb93a386Sopenharmony_ci// SkOpSegment* innerCoinWritable = const_cast<SkOpSegment*>(innerCoin); 1899cb93a386Sopenharmony_ci// SkOpSegment* innerOppWritable = const_cast<SkOpSegment*>(innerOpp); 1900cb93a386Sopenharmony_ci if (outerCoin == innerCoin) { 1901cb93a386Sopenharmony_ci const SkOpPtT* oce = outer->coinPtTEnd(); 1902cb93a386Sopenharmony_ci if (oce->deleted()) { 1903cb93a386Sopenharmony_ci return; 1904cb93a386Sopenharmony_ci } 1905cb93a386Sopenharmony_ci const SkOpPtT* ice = inner->coinPtTEnd(); 1906cb93a386Sopenharmony_ci SkASSERT(!ice->deleted()); 1907cb93a386Sopenharmony_ci if (outerOpp != innerOpp && this->overlap(ocs, oce, ics, ice, &overS, &overE)) { 1908cb93a386Sopenharmony_ci this->debugAddIfMissing(log, ocs->starter(oce), ics->starter(ice), 1909cb93a386Sopenharmony_ci overS, overE, outerOpp, innerOpp, added, 1910cb93a386Sopenharmony_ci ocs->debugEnder(oce), 1911cb93a386Sopenharmony_ci ics->debugEnder(ice)); 1912cb93a386Sopenharmony_ci } 1913cb93a386Sopenharmony_ci } else if (outerCoin == innerOpp) { 1914cb93a386Sopenharmony_ci const SkOpPtT* oce = outer->coinPtTEnd(); 1915cb93a386Sopenharmony_ci SkASSERT(!oce->deleted()); 1916cb93a386Sopenharmony_ci const SkOpPtT* ioe = inner->oppPtTEnd(); 1917cb93a386Sopenharmony_ci SkASSERT(!ioe->deleted()); 1918cb93a386Sopenharmony_ci if (outerOpp != innerCoin && this->overlap(ocs, oce, ios, ioe, &overS, &overE)) { 1919cb93a386Sopenharmony_ci this->debugAddIfMissing(log, ocs->starter(oce), ios->starter(ioe), 1920cb93a386Sopenharmony_ci overS, overE, outerOpp, innerCoin, added, 1921cb93a386Sopenharmony_ci ocs->debugEnder(oce), 1922cb93a386Sopenharmony_ci ios->debugEnder(ioe)); 1923cb93a386Sopenharmony_ci } 1924cb93a386Sopenharmony_ci } else if (outerOpp == innerCoin) { 1925cb93a386Sopenharmony_ci const SkOpPtT* ooe = outer->oppPtTEnd(); 1926cb93a386Sopenharmony_ci SkASSERT(!ooe->deleted()); 1927cb93a386Sopenharmony_ci const SkOpPtT* ice = inner->coinPtTEnd(); 1928cb93a386Sopenharmony_ci SkASSERT(!ice->deleted()); 1929cb93a386Sopenharmony_ci SkASSERT(outerCoin != innerOpp); 1930cb93a386Sopenharmony_ci if (this->overlap(oos, ooe, ics, ice, &overS, &overE)) { 1931cb93a386Sopenharmony_ci this->debugAddIfMissing(log, oos->starter(ooe), ics->starter(ice), 1932cb93a386Sopenharmony_ci overS, overE, outerCoin, innerOpp, added, 1933cb93a386Sopenharmony_ci oos->debugEnder(ooe), 1934cb93a386Sopenharmony_ci ics->debugEnder(ice)); 1935cb93a386Sopenharmony_ci } 1936cb93a386Sopenharmony_ci } else if (outerOpp == innerOpp) { 1937cb93a386Sopenharmony_ci const SkOpPtT* ooe = outer->oppPtTEnd(); 1938cb93a386Sopenharmony_ci SkASSERT(!ooe->deleted()); 1939cb93a386Sopenharmony_ci const SkOpPtT* ioe = inner->oppPtTEnd(); 1940cb93a386Sopenharmony_ci if (ioe->deleted()) { 1941cb93a386Sopenharmony_ci return; 1942cb93a386Sopenharmony_ci } 1943cb93a386Sopenharmony_ci SkASSERT(outerCoin != innerCoin); 1944cb93a386Sopenharmony_ci if (this->overlap(oos, ooe, ios, ioe, &overS, &overE)) { 1945cb93a386Sopenharmony_ci this->debugAddIfMissing(log, oos->starter(ooe), ios->starter(ioe), 1946cb93a386Sopenharmony_ci overS, overE, outerCoin, innerCoin, added, 1947cb93a386Sopenharmony_ci oos->debugEnder(ooe), 1948cb93a386Sopenharmony_ci ios->debugEnder(ioe)); 1949cb93a386Sopenharmony_ci } 1950cb93a386Sopenharmony_ci } 1951cb93a386Sopenharmony_ci this->debugValidate(); 1952cb93a386Sopenharmony_ci } 1953cb93a386Sopenharmony_ci } while ((outer = outer->next())); 1954cb93a386Sopenharmony_ci // this->restoreHead(); 1955cb93a386Sopenharmony_ci return; 1956cb93a386Sopenharmony_ci} 1957cb93a386Sopenharmony_ci 1958cb93a386Sopenharmony_ci// Commented-out lines keep this in sync with release() 1959cb93a386Sopenharmony_civoid SkOpCoincidence::debugRelease(SkPathOpsDebug::GlitchLog* log, const SkCoincidentSpans* coin, const SkCoincidentSpans* remove) const { 1960cb93a386Sopenharmony_ci const SkCoincidentSpans* head = coin; 1961cb93a386Sopenharmony_ci const SkCoincidentSpans* prev = nullptr; 1962cb93a386Sopenharmony_ci const SkCoincidentSpans* next; 1963cb93a386Sopenharmony_ci do { 1964cb93a386Sopenharmony_ci next = coin->next(); 1965cb93a386Sopenharmony_ci if (coin == remove) { 1966cb93a386Sopenharmony_ci if (prev) { 1967cb93a386Sopenharmony_ci// prev->setNext(next); 1968cb93a386Sopenharmony_ci } else if (head == fHead) { 1969cb93a386Sopenharmony_ci// fHead = next; 1970cb93a386Sopenharmony_ci } else { 1971cb93a386Sopenharmony_ci// fTop = next; 1972cb93a386Sopenharmony_ci } 1973cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kReleasedSpan_Glitch, coin); 1974cb93a386Sopenharmony_ci } 1975cb93a386Sopenharmony_ci prev = coin; 1976cb93a386Sopenharmony_ci } while ((coin = next)); 1977cb93a386Sopenharmony_ci return; 1978cb93a386Sopenharmony_ci} 1979cb93a386Sopenharmony_ci 1980cb93a386Sopenharmony_civoid SkOpCoincidence::debugRelease(SkPathOpsDebug::GlitchLog* log, const SkOpSegment* deleted) const { 1981cb93a386Sopenharmony_ci const SkCoincidentSpans* coin = fHead; 1982cb93a386Sopenharmony_ci if (!coin) { 1983cb93a386Sopenharmony_ci return; 1984cb93a386Sopenharmony_ci } 1985cb93a386Sopenharmony_ci do { 1986cb93a386Sopenharmony_ci if (coin->coinPtTStart()->segment() == deleted 1987cb93a386Sopenharmony_ci || coin->coinPtTEnd()->segment() == deleted 1988cb93a386Sopenharmony_ci || coin->oppPtTStart()->segment() == deleted 1989cb93a386Sopenharmony_ci || coin->oppPtTEnd()->segment() == deleted) { 1990cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kReleasedSpan_Glitch, coin); 1991cb93a386Sopenharmony_ci } 1992cb93a386Sopenharmony_ci } while ((coin = coin->next())); 1993cb93a386Sopenharmony_ci} 1994cb93a386Sopenharmony_ci 1995cb93a386Sopenharmony_ci// Commented-out lines keep this in sync with expand() 1996cb93a386Sopenharmony_ci// expand the range by checking adjacent spans for coincidence 1997cb93a386Sopenharmony_cibool SkOpCoincidence::debugExpand(SkPathOpsDebug::GlitchLog* log) const { 1998cb93a386Sopenharmony_ci const SkCoincidentSpans* coin = fHead; 1999cb93a386Sopenharmony_ci if (!coin) { 2000cb93a386Sopenharmony_ci return false; 2001cb93a386Sopenharmony_ci } 2002cb93a386Sopenharmony_ci bool expanded = false; 2003cb93a386Sopenharmony_ci do { 2004cb93a386Sopenharmony_ci if (coin->debugExpand(log)) { 2005cb93a386Sopenharmony_ci // check to see if multiple spans expanded so they are now identical 2006cb93a386Sopenharmony_ci const SkCoincidentSpans* test = fHead; 2007cb93a386Sopenharmony_ci do { 2008cb93a386Sopenharmony_ci if (coin == test) { 2009cb93a386Sopenharmony_ci continue; 2010cb93a386Sopenharmony_ci } 2011cb93a386Sopenharmony_ci if (coin->coinPtTStart() == test->coinPtTStart() 2012cb93a386Sopenharmony_ci && coin->oppPtTStart() == test->oppPtTStart()) { 2013cb93a386Sopenharmony_ci if (log) log->record(SkPathOpsDebug::kExpandCoin_Glitch, fHead, test->coinPtTStart()); 2014cb93a386Sopenharmony_ci break; 2015cb93a386Sopenharmony_ci } 2016cb93a386Sopenharmony_ci } while ((test = test->next())); 2017cb93a386Sopenharmony_ci expanded = true; 2018cb93a386Sopenharmony_ci } 2019cb93a386Sopenharmony_ci } while ((coin = coin->next())); 2020cb93a386Sopenharmony_ci return expanded; 2021cb93a386Sopenharmony_ci} 2022cb93a386Sopenharmony_ci 2023cb93a386Sopenharmony_ci// Commented-out lines keep this in sync with mark() 2024cb93a386Sopenharmony_ci/* this sets up the coincidence links in the segments when the coincidence crosses multiple spans */ 2025cb93a386Sopenharmony_civoid SkOpCoincidence::debugMark(SkPathOpsDebug::GlitchLog* log) const { 2026cb93a386Sopenharmony_ci const SkCoincidentSpans* coin = fHead; 2027cb93a386Sopenharmony_ci if (!coin) { 2028cb93a386Sopenharmony_ci return; 2029cb93a386Sopenharmony_ci } 2030cb93a386Sopenharmony_ci do { 2031cb93a386Sopenharmony_ci FAIL_IF(!coin->coinPtTStartWritable()->span()->upCastable(), coin); 2032cb93a386Sopenharmony_ci const SkOpSpan* start = coin->coinPtTStartWritable()->span()->upCast(); 2033cb93a386Sopenharmony_ci// SkASSERT(start->deleted()); 2034cb93a386Sopenharmony_ci const SkOpSpanBase* end = coin->coinPtTEndWritable()->span(); 2035cb93a386Sopenharmony_ci// SkASSERT(end->deleted()); 2036cb93a386Sopenharmony_ci const SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span(); 2037cb93a386Sopenharmony_ci// SkASSERT(oStart->deleted()); 2038cb93a386Sopenharmony_ci const SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span(); 2039cb93a386Sopenharmony_ci// SkASSERT(oEnd->deleted()); 2040cb93a386Sopenharmony_ci bool flipped = coin->flipped(); 2041cb93a386Sopenharmony_ci if (flipped) { 2042cb93a386Sopenharmony_ci using std::swap; 2043cb93a386Sopenharmony_ci swap(oStart, oEnd); 2044cb93a386Sopenharmony_ci } 2045cb93a386Sopenharmony_ci /* coin and opp spans may not match up. Mark the ends, and then let the interior 2046cb93a386Sopenharmony_ci get marked as many times as the spans allow */ 2047cb93a386Sopenharmony_ci start->debugInsertCoincidence(log, oStart->upCast()); 2048cb93a386Sopenharmony_ci end->debugInsertCoinEnd(log, oEnd); 2049cb93a386Sopenharmony_ci const SkOpSegment* segment = start->segment(); 2050cb93a386Sopenharmony_ci const SkOpSegment* oSegment = oStart->segment(); 2051cb93a386Sopenharmony_ci const SkOpSpanBase* next = start; 2052cb93a386Sopenharmony_ci const SkOpSpanBase* oNext = oStart; 2053cb93a386Sopenharmony_ci bool ordered; 2054cb93a386Sopenharmony_ci FAIL_IF(!coin->ordered(&ordered), coin); 2055cb93a386Sopenharmony_ci while ((next = next->upCast()->next()) != end) { 2056cb93a386Sopenharmony_ci FAIL_IF(!next->upCastable(), coin); 2057cb93a386Sopenharmony_ci if (next->upCast()->debugInsertCoincidence(log, oSegment, flipped, ordered), false) { 2058cb93a386Sopenharmony_ci return; 2059cb93a386Sopenharmony_ci } 2060cb93a386Sopenharmony_ci } 2061cb93a386Sopenharmony_ci while ((oNext = oNext->upCast()->next()) != oEnd) { 2062cb93a386Sopenharmony_ci FAIL_IF(!oNext->upCastable(), coin); 2063cb93a386Sopenharmony_ci if (oNext->upCast()->debugInsertCoincidence(log, segment, flipped, ordered), false) { 2064cb93a386Sopenharmony_ci return; 2065cb93a386Sopenharmony_ci } 2066cb93a386Sopenharmony_ci } 2067cb93a386Sopenharmony_ci } while ((coin = coin->next())); 2068cb93a386Sopenharmony_ci return; 2069cb93a386Sopenharmony_ci} 2070cb93a386Sopenharmony_ci#endif 2071cb93a386Sopenharmony_ci 2072cb93a386Sopenharmony_ci#if DEBUG_COIN 2073cb93a386Sopenharmony_ci// Commented-out lines keep this in sync with markCollapsed() 2074cb93a386Sopenharmony_civoid SkOpCoincidence::debugMarkCollapsed(SkPathOpsDebug::GlitchLog* log, const SkCoincidentSpans* coin, const SkOpPtT* test) const { 2075cb93a386Sopenharmony_ci const SkCoincidentSpans* head = coin; 2076cb93a386Sopenharmony_ci while (coin) { 2077cb93a386Sopenharmony_ci if (coin->collapsed(test)) { 2078cb93a386Sopenharmony_ci if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinPtTEnd()->fT)) { 2079cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kCollapsedCoin_Glitch, coin); 2080cb93a386Sopenharmony_ci } 2081cb93a386Sopenharmony_ci if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtTEnd()->fT)) { 2082cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kCollapsedCoin_Glitch, coin); 2083cb93a386Sopenharmony_ci } 2084cb93a386Sopenharmony_ci this->debugRelease(log, head, coin); 2085cb93a386Sopenharmony_ci } 2086cb93a386Sopenharmony_ci coin = coin->next(); 2087cb93a386Sopenharmony_ci } 2088cb93a386Sopenharmony_ci} 2089cb93a386Sopenharmony_ci 2090cb93a386Sopenharmony_ci// Commented-out lines keep this in sync with markCollapsed() 2091cb93a386Sopenharmony_civoid SkOpCoincidence::debugMarkCollapsed(SkPathOpsDebug::GlitchLog* log, const SkOpPtT* test) const { 2092cb93a386Sopenharmony_ci this->debugMarkCollapsed(log, fHead, test); 2093cb93a386Sopenharmony_ci this->debugMarkCollapsed(log, fTop, test); 2094cb93a386Sopenharmony_ci} 2095cb93a386Sopenharmony_ci#endif 2096cb93a386Sopenharmony_ci 2097cb93a386Sopenharmony_civoid SkCoincidentSpans::debugShow() const { 2098cb93a386Sopenharmony_ci SkDebugf("coinSpan - id=%d t=%1.9g tEnd=%1.9g\n", coinPtTStart()->segment()->debugID(), 2099cb93a386Sopenharmony_ci coinPtTStart()->fT, coinPtTEnd()->fT); 2100cb93a386Sopenharmony_ci SkDebugf("coinSpan + id=%d t=%1.9g tEnd=%1.9g\n", oppPtTStart()->segment()->debugID(), 2101cb93a386Sopenharmony_ci oppPtTStart()->fT, oppPtTEnd()->fT); 2102cb93a386Sopenharmony_ci} 2103cb93a386Sopenharmony_ci 2104cb93a386Sopenharmony_civoid SkOpCoincidence::debugShowCoincidence() const { 2105cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE 2106cb93a386Sopenharmony_ci const SkCoincidentSpans* span = fHead; 2107cb93a386Sopenharmony_ci while (span) { 2108cb93a386Sopenharmony_ci span->debugShow(); 2109cb93a386Sopenharmony_ci span = span->next(); 2110cb93a386Sopenharmony_ci } 2111cb93a386Sopenharmony_ci#endif 2112cb93a386Sopenharmony_ci} 2113cb93a386Sopenharmony_ci 2114cb93a386Sopenharmony_ci#if DEBUG_COIN 2115cb93a386Sopenharmony_cistatic void DebugCheckBetween(const SkOpSpanBase* next, const SkOpSpanBase* end, 2116cb93a386Sopenharmony_ci double oStart, double oEnd, const SkOpSegment* oSegment, 2117cb93a386Sopenharmony_ci SkPathOpsDebug::GlitchLog* log) { 2118cb93a386Sopenharmony_ci SkASSERT(next != end); 2119cb93a386Sopenharmony_ci SkASSERT(!next->contains(end) || log); 2120cb93a386Sopenharmony_ci if (next->t() > end->t()) { 2121cb93a386Sopenharmony_ci using std::swap; 2122cb93a386Sopenharmony_ci swap(next, end); 2123cb93a386Sopenharmony_ci } 2124cb93a386Sopenharmony_ci do { 2125cb93a386Sopenharmony_ci const SkOpPtT* ptT = next->ptT(); 2126cb93a386Sopenharmony_ci int index = 0; 2127cb93a386Sopenharmony_ci bool somethingBetween = false; 2128cb93a386Sopenharmony_ci do { 2129cb93a386Sopenharmony_ci ++index; 2130cb93a386Sopenharmony_ci ptT = ptT->next(); 2131cb93a386Sopenharmony_ci const SkOpPtT* checkPtT = next->ptT(); 2132cb93a386Sopenharmony_ci if (ptT == checkPtT) { 2133cb93a386Sopenharmony_ci break; 2134cb93a386Sopenharmony_ci } 2135cb93a386Sopenharmony_ci bool looped = false; 2136cb93a386Sopenharmony_ci for (int check = 0; check < index; ++check) { 2137cb93a386Sopenharmony_ci if ((looped = checkPtT == ptT)) { 2138cb93a386Sopenharmony_ci break; 2139cb93a386Sopenharmony_ci } 2140cb93a386Sopenharmony_ci checkPtT = checkPtT->next(); 2141cb93a386Sopenharmony_ci } 2142cb93a386Sopenharmony_ci if (looped) { 2143cb93a386Sopenharmony_ci SkASSERT(0); 2144cb93a386Sopenharmony_ci break; 2145cb93a386Sopenharmony_ci } 2146cb93a386Sopenharmony_ci if (ptT->deleted()) { 2147cb93a386Sopenharmony_ci continue; 2148cb93a386Sopenharmony_ci } 2149cb93a386Sopenharmony_ci if (ptT->segment() != oSegment) { 2150cb93a386Sopenharmony_ci continue; 2151cb93a386Sopenharmony_ci } 2152cb93a386Sopenharmony_ci somethingBetween |= between(oStart, ptT->fT, oEnd); 2153cb93a386Sopenharmony_ci } while (true); 2154cb93a386Sopenharmony_ci SkASSERT(somethingBetween); 2155cb93a386Sopenharmony_ci } while (next != end && (next = next->upCast()->next())); 2156cb93a386Sopenharmony_ci} 2157cb93a386Sopenharmony_ci 2158cb93a386Sopenharmony_cistatic void DebugCheckOverlap(const SkCoincidentSpans* test, const SkCoincidentSpans* list, 2159cb93a386Sopenharmony_ci SkPathOpsDebug::GlitchLog* log) { 2160cb93a386Sopenharmony_ci if (!list) { 2161cb93a386Sopenharmony_ci return; 2162cb93a386Sopenharmony_ci } 2163cb93a386Sopenharmony_ci const SkOpSegment* coinSeg = test->coinPtTStart()->segment(); 2164cb93a386Sopenharmony_ci SkASSERT(coinSeg == test->coinPtTEnd()->segment()); 2165cb93a386Sopenharmony_ci const SkOpSegment* oppSeg = test->oppPtTStart()->segment(); 2166cb93a386Sopenharmony_ci SkASSERT(oppSeg == test->oppPtTEnd()->segment()); 2167cb93a386Sopenharmony_ci SkASSERT(coinSeg != test->oppPtTStart()->segment()); 2168cb93a386Sopenharmony_ci SkDEBUGCODE(double tcs = test->coinPtTStart()->fT); 2169cb93a386Sopenharmony_ci SkASSERT(between(0, tcs, 1)); 2170cb93a386Sopenharmony_ci SkDEBUGCODE(double tce = test->coinPtTEnd()->fT); 2171cb93a386Sopenharmony_ci SkASSERT(between(0, tce, 1)); 2172cb93a386Sopenharmony_ci SkASSERT(tcs < tce); 2173cb93a386Sopenharmony_ci double tos = test->oppPtTStart()->fT; 2174cb93a386Sopenharmony_ci SkASSERT(between(0, tos, 1)); 2175cb93a386Sopenharmony_ci double toe = test->oppPtTEnd()->fT; 2176cb93a386Sopenharmony_ci SkASSERT(between(0, toe, 1)); 2177cb93a386Sopenharmony_ci SkASSERT(tos != toe); 2178cb93a386Sopenharmony_ci if (tos > toe) { 2179cb93a386Sopenharmony_ci using std::swap; 2180cb93a386Sopenharmony_ci swap(tos, toe); 2181cb93a386Sopenharmony_ci } 2182cb93a386Sopenharmony_ci do { 2183cb93a386Sopenharmony_ci double lcs, lce, los, loe; 2184cb93a386Sopenharmony_ci if (coinSeg == list->coinPtTStart()->segment()) { 2185cb93a386Sopenharmony_ci if (oppSeg != list->oppPtTStart()->segment()) { 2186cb93a386Sopenharmony_ci continue; 2187cb93a386Sopenharmony_ci } 2188cb93a386Sopenharmony_ci lcs = list->coinPtTStart()->fT; 2189cb93a386Sopenharmony_ci lce = list->coinPtTEnd()->fT; 2190cb93a386Sopenharmony_ci los = list->oppPtTStart()->fT; 2191cb93a386Sopenharmony_ci loe = list->oppPtTEnd()->fT; 2192cb93a386Sopenharmony_ci if (los > loe) { 2193cb93a386Sopenharmony_ci using std::swap; 2194cb93a386Sopenharmony_ci swap(los, loe); 2195cb93a386Sopenharmony_ci } 2196cb93a386Sopenharmony_ci } else if (coinSeg == list->oppPtTStart()->segment()) { 2197cb93a386Sopenharmony_ci if (oppSeg != list->coinPtTStart()->segment()) { 2198cb93a386Sopenharmony_ci continue; 2199cb93a386Sopenharmony_ci } 2200cb93a386Sopenharmony_ci lcs = list->oppPtTStart()->fT; 2201cb93a386Sopenharmony_ci lce = list->oppPtTEnd()->fT; 2202cb93a386Sopenharmony_ci if (lcs > lce) { 2203cb93a386Sopenharmony_ci using std::swap; 2204cb93a386Sopenharmony_ci swap(lcs, lce); 2205cb93a386Sopenharmony_ci } 2206cb93a386Sopenharmony_ci los = list->coinPtTStart()->fT; 2207cb93a386Sopenharmony_ci loe = list->coinPtTEnd()->fT; 2208cb93a386Sopenharmony_ci } else { 2209cb93a386Sopenharmony_ci continue; 2210cb93a386Sopenharmony_ci } 2211cb93a386Sopenharmony_ci SkASSERT(tce < lcs || lce < tcs); 2212cb93a386Sopenharmony_ci SkASSERT(toe < los || loe < tos); 2213cb93a386Sopenharmony_ci } while ((list = list->next())); 2214cb93a386Sopenharmony_ci} 2215cb93a386Sopenharmony_ci 2216cb93a386Sopenharmony_ci 2217cb93a386Sopenharmony_cistatic void DebugCheckOverlapTop(const SkCoincidentSpans* head, const SkCoincidentSpans* opt, 2218cb93a386Sopenharmony_ci SkPathOpsDebug::GlitchLog* log) { 2219cb93a386Sopenharmony_ci // check for overlapping coincident spans 2220cb93a386Sopenharmony_ci const SkCoincidentSpans* test = head; 2221cb93a386Sopenharmony_ci while (test) { 2222cb93a386Sopenharmony_ci const SkCoincidentSpans* next = test->next(); 2223cb93a386Sopenharmony_ci DebugCheckOverlap(test, next, log); 2224cb93a386Sopenharmony_ci DebugCheckOverlap(test, opt, log); 2225cb93a386Sopenharmony_ci test = next; 2226cb93a386Sopenharmony_ci } 2227cb93a386Sopenharmony_ci} 2228cb93a386Sopenharmony_ci 2229cb93a386Sopenharmony_cistatic void DebugValidate(const SkCoincidentSpans* head, const SkCoincidentSpans* opt, 2230cb93a386Sopenharmony_ci SkPathOpsDebug::GlitchLog* log) { 2231cb93a386Sopenharmony_ci // look for pts inside coincident spans that are not inside the opposite spans 2232cb93a386Sopenharmony_ci const SkCoincidentSpans* coin = head; 2233cb93a386Sopenharmony_ci while (coin) { 2234cb93a386Sopenharmony_ci SkASSERT(SkOpCoincidence::Ordered(coin->coinPtTStart()->segment(), 2235cb93a386Sopenharmony_ci coin->oppPtTStart()->segment())); 2236cb93a386Sopenharmony_ci SkASSERT(coin->coinPtTStart()->span()->ptT() == coin->coinPtTStart()); 2237cb93a386Sopenharmony_ci SkASSERT(coin->coinPtTEnd()->span()->ptT() == coin->coinPtTEnd()); 2238cb93a386Sopenharmony_ci SkASSERT(coin->oppPtTStart()->span()->ptT() == coin->oppPtTStart()); 2239cb93a386Sopenharmony_ci SkASSERT(coin->oppPtTEnd()->span()->ptT() == coin->oppPtTEnd()); 2240cb93a386Sopenharmony_ci coin = coin->next(); 2241cb93a386Sopenharmony_ci } 2242cb93a386Sopenharmony_ci DebugCheckOverlapTop(head, opt, log); 2243cb93a386Sopenharmony_ci} 2244cb93a386Sopenharmony_ci#endif 2245cb93a386Sopenharmony_ci 2246cb93a386Sopenharmony_civoid SkOpCoincidence::debugValidate() const { 2247cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE 2248cb93a386Sopenharmony_ci DebugValidate(fHead, fTop, nullptr); 2249cb93a386Sopenharmony_ci DebugValidate(fTop, nullptr, nullptr); 2250cb93a386Sopenharmony_ci#endif 2251cb93a386Sopenharmony_ci} 2252cb93a386Sopenharmony_ci 2253cb93a386Sopenharmony_ci#if DEBUG_COIN 2254cb93a386Sopenharmony_cistatic void DebugCheckBetween(const SkCoincidentSpans* head, const SkCoincidentSpans* opt, 2255cb93a386Sopenharmony_ci SkPathOpsDebug::GlitchLog* log) { 2256cb93a386Sopenharmony_ci // look for pts inside coincident spans that are not inside the opposite spans 2257cb93a386Sopenharmony_ci const SkCoincidentSpans* coin = head; 2258cb93a386Sopenharmony_ci while (coin) { 2259cb93a386Sopenharmony_ci DebugCheckBetween(coin->coinPtTStart()->span(), coin->coinPtTEnd()->span(), 2260cb93a386Sopenharmony_ci coin->oppPtTStart()->fT, coin->oppPtTEnd()->fT, coin->oppPtTStart()->segment(), 2261cb93a386Sopenharmony_ci log); 2262cb93a386Sopenharmony_ci DebugCheckBetween(coin->oppPtTStart()->span(), coin->oppPtTEnd()->span(), 2263cb93a386Sopenharmony_ci coin->coinPtTStart()->fT, coin->coinPtTEnd()->fT, coin->coinPtTStart()->segment(), 2264cb93a386Sopenharmony_ci log); 2265cb93a386Sopenharmony_ci coin = coin->next(); 2266cb93a386Sopenharmony_ci } 2267cb93a386Sopenharmony_ci DebugCheckOverlapTop(head, opt, log); 2268cb93a386Sopenharmony_ci} 2269cb93a386Sopenharmony_ci#endif 2270cb93a386Sopenharmony_ci 2271cb93a386Sopenharmony_civoid SkOpCoincidence::debugCheckBetween() const { 2272cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE 2273cb93a386Sopenharmony_ci if (fGlobalState->debugCheckHealth()) { 2274cb93a386Sopenharmony_ci return; 2275cb93a386Sopenharmony_ci } 2276cb93a386Sopenharmony_ci DebugCheckBetween(fHead, fTop, nullptr); 2277cb93a386Sopenharmony_ci DebugCheckBetween(fTop, nullptr, nullptr); 2278cb93a386Sopenharmony_ci#endif 2279cb93a386Sopenharmony_ci} 2280cb93a386Sopenharmony_ci 2281cb93a386Sopenharmony_ci#if DEBUG_COIN 2282cb93a386Sopenharmony_civoid SkOpContour::debugCheckHealth(SkPathOpsDebug::GlitchLog* log) const { 2283cb93a386Sopenharmony_ci const SkOpSegment* segment = &fHead; 2284cb93a386Sopenharmony_ci do { 2285cb93a386Sopenharmony_ci segment->debugCheckHealth(log); 2286cb93a386Sopenharmony_ci } while ((segment = segment->next())); 2287cb93a386Sopenharmony_ci} 2288cb93a386Sopenharmony_ci 2289cb93a386Sopenharmony_civoid SkOpCoincidence::debugCheckValid(SkPathOpsDebug::GlitchLog* log) const { 2290cb93a386Sopenharmony_ci#if DEBUG_VALIDATE 2291cb93a386Sopenharmony_ci DebugValidate(fHead, fTop, log); 2292cb93a386Sopenharmony_ci DebugValidate(fTop, nullptr, log); 2293cb93a386Sopenharmony_ci#endif 2294cb93a386Sopenharmony_ci} 2295cb93a386Sopenharmony_ci 2296cb93a386Sopenharmony_civoid SkOpCoincidence::debugCorrectEnds(SkPathOpsDebug::GlitchLog* log) const { 2297cb93a386Sopenharmony_ci const SkCoincidentSpans* coin = fHead; 2298cb93a386Sopenharmony_ci if (!coin) { 2299cb93a386Sopenharmony_ci return; 2300cb93a386Sopenharmony_ci } 2301cb93a386Sopenharmony_ci do { 2302cb93a386Sopenharmony_ci coin->debugCorrectEnds(log); 2303cb93a386Sopenharmony_ci } while ((coin = coin->next())); 2304cb93a386Sopenharmony_ci} 2305cb93a386Sopenharmony_ci 2306cb93a386Sopenharmony_ci// commmented-out lines keep this aligned with missingCoincidence() 2307cb93a386Sopenharmony_civoid SkOpContour::debugMissingCoincidence(SkPathOpsDebug::GlitchLog* log) const { 2308cb93a386Sopenharmony_ci// SkASSERT(fCount > 0); 2309cb93a386Sopenharmony_ci const SkOpSegment* segment = &fHead; 2310cb93a386Sopenharmony_ci// bool result = false; 2311cb93a386Sopenharmony_ci do { 2312cb93a386Sopenharmony_ci if (segment->debugMissingCoincidence(log), false) { 2313cb93a386Sopenharmony_ci// result = true; 2314cb93a386Sopenharmony_ci } 2315cb93a386Sopenharmony_ci segment = segment->next(); 2316cb93a386Sopenharmony_ci } while (segment); 2317cb93a386Sopenharmony_ci return; 2318cb93a386Sopenharmony_ci} 2319cb93a386Sopenharmony_ci 2320cb93a386Sopenharmony_civoid SkOpContour::debugMoveMultiples(SkPathOpsDebug::GlitchLog* log) const { 2321cb93a386Sopenharmony_ci SkASSERT(fCount > 0); 2322cb93a386Sopenharmony_ci const SkOpSegment* segment = &fHead; 2323cb93a386Sopenharmony_ci do { 2324cb93a386Sopenharmony_ci if (segment->debugMoveMultiples(log), false) { 2325cb93a386Sopenharmony_ci return; 2326cb93a386Sopenharmony_ci } 2327cb93a386Sopenharmony_ci } while ((segment = segment->next())); 2328cb93a386Sopenharmony_ci return; 2329cb93a386Sopenharmony_ci} 2330cb93a386Sopenharmony_ci 2331cb93a386Sopenharmony_civoid SkOpContour::debugMoveNearby(SkPathOpsDebug::GlitchLog* log) const { 2332cb93a386Sopenharmony_ci SkASSERT(fCount > 0); 2333cb93a386Sopenharmony_ci const SkOpSegment* segment = &fHead; 2334cb93a386Sopenharmony_ci do { 2335cb93a386Sopenharmony_ci segment->debugMoveNearby(log); 2336cb93a386Sopenharmony_ci } while ((segment = segment->next())); 2337cb93a386Sopenharmony_ci} 2338cb93a386Sopenharmony_ci#endif 2339cb93a386Sopenharmony_ci 2340cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE_ORDER 2341cb93a386Sopenharmony_civoid SkOpSegment::debugResetCoinT() const { 2342cb93a386Sopenharmony_ci fDebugBaseIndex = -1; 2343cb93a386Sopenharmony_ci fDebugBaseMin = 1; 2344cb93a386Sopenharmony_ci fDebugBaseMax = -1; 2345cb93a386Sopenharmony_ci fDebugLastIndex = -1; 2346cb93a386Sopenharmony_ci fDebugLastMin = 1; 2347cb93a386Sopenharmony_ci fDebugLastMax = -1; 2348cb93a386Sopenharmony_ci} 2349cb93a386Sopenharmony_ci#endif 2350cb93a386Sopenharmony_ci 2351cb93a386Sopenharmony_civoid SkOpSegment::debugValidate() const { 2352cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE_ORDER 2353cb93a386Sopenharmony_ci { 2354cb93a386Sopenharmony_ci const SkOpSpanBase* span = &fHead; 2355cb93a386Sopenharmony_ci do { 2356cb93a386Sopenharmony_ci span->debugResetCoinT(); 2357cb93a386Sopenharmony_ci } while (!span->final() && (span = span->upCast()->next())); 2358cb93a386Sopenharmony_ci span = &fHead; 2359cb93a386Sopenharmony_ci int index = 0; 2360cb93a386Sopenharmony_ci do { 2361cb93a386Sopenharmony_ci span->debugSetCoinT(index++); 2362cb93a386Sopenharmony_ci } while (!span->final() && (span = span->upCast()->next())); 2363cb93a386Sopenharmony_ci } 2364cb93a386Sopenharmony_ci#endif 2365cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE 2366cb93a386Sopenharmony_ci if (this->globalState()->debugCheckHealth()) { 2367cb93a386Sopenharmony_ci return; 2368cb93a386Sopenharmony_ci } 2369cb93a386Sopenharmony_ci#endif 2370cb93a386Sopenharmony_ci#if DEBUG_VALIDATE 2371cb93a386Sopenharmony_ci const SkOpSpanBase* span = &fHead; 2372cb93a386Sopenharmony_ci double lastT = -1; 2373cb93a386Sopenharmony_ci const SkOpSpanBase* prev = nullptr; 2374cb93a386Sopenharmony_ci int count = 0; 2375cb93a386Sopenharmony_ci int done = 0; 2376cb93a386Sopenharmony_ci do { 2377cb93a386Sopenharmony_ci if (!span->final()) { 2378cb93a386Sopenharmony_ci ++count; 2379cb93a386Sopenharmony_ci done += span->upCast()->done() ? 1 : 0; 2380cb93a386Sopenharmony_ci } 2381cb93a386Sopenharmony_ci SkASSERT(span->segment() == this); 2382cb93a386Sopenharmony_ci SkASSERT(!prev || prev->upCast()->next() == span); 2383cb93a386Sopenharmony_ci SkASSERT(!prev || prev == span->prev()); 2384cb93a386Sopenharmony_ci prev = span; 2385cb93a386Sopenharmony_ci double t = span->ptT()->fT; 2386cb93a386Sopenharmony_ci SkASSERT(lastT < t); 2387cb93a386Sopenharmony_ci lastT = t; 2388cb93a386Sopenharmony_ci span->debugValidate(); 2389cb93a386Sopenharmony_ci } while (!span->final() && (span = span->upCast()->next())); 2390cb93a386Sopenharmony_ci SkASSERT(count == fCount); 2391cb93a386Sopenharmony_ci SkASSERT(done == fDoneCount); 2392cb93a386Sopenharmony_ci SkASSERT(count >= fDoneCount); 2393cb93a386Sopenharmony_ci SkASSERT(span->final()); 2394cb93a386Sopenharmony_ci span->debugValidate(); 2395cb93a386Sopenharmony_ci#endif 2396cb93a386Sopenharmony_ci} 2397cb93a386Sopenharmony_ci 2398cb93a386Sopenharmony_ci#if DEBUG_COIN 2399cb93a386Sopenharmony_ci 2400cb93a386Sopenharmony_ci// Commented-out lines keep this in sync with addOpp() 2401cb93a386Sopenharmony_civoid SkOpSpanBase::debugAddOpp(SkPathOpsDebug::GlitchLog* log, const SkOpSpanBase* opp) const { 2402cb93a386Sopenharmony_ci const SkOpPtT* oppPrev = this->ptT()->oppPrev(opp->ptT()); 2403cb93a386Sopenharmony_ci if (!oppPrev) { 2404cb93a386Sopenharmony_ci return; 2405cb93a386Sopenharmony_ci } 2406cb93a386Sopenharmony_ci this->debugMergeMatches(log, opp); 2407cb93a386Sopenharmony_ci this->ptT()->debugAddOpp(opp->ptT(), oppPrev); 2408cb93a386Sopenharmony_ci this->debugCheckForCollapsedCoincidence(log); 2409cb93a386Sopenharmony_ci} 2410cb93a386Sopenharmony_ci 2411cb93a386Sopenharmony_ci// Commented-out lines keep this in sync with checkForCollapsedCoincidence() 2412cb93a386Sopenharmony_civoid SkOpSpanBase::debugCheckForCollapsedCoincidence(SkPathOpsDebug::GlitchLog* log) const { 2413cb93a386Sopenharmony_ci const SkOpCoincidence* coins = this->globalState()->coincidence(); 2414cb93a386Sopenharmony_ci if (coins->isEmpty()) { 2415cb93a386Sopenharmony_ci return; 2416cb93a386Sopenharmony_ci } 2417cb93a386Sopenharmony_ci// the insert above may have put both ends of a coincident run in the same span 2418cb93a386Sopenharmony_ci// for each coincident ptT in loop; see if its opposite in is also in the loop 2419cb93a386Sopenharmony_ci// this implementation is the motivation for marking that a ptT is referenced by a coincident span 2420cb93a386Sopenharmony_ci const SkOpPtT* head = this->ptT(); 2421cb93a386Sopenharmony_ci const SkOpPtT* test = head; 2422cb93a386Sopenharmony_ci do { 2423cb93a386Sopenharmony_ci if (!test->coincident()) { 2424cb93a386Sopenharmony_ci continue; 2425cb93a386Sopenharmony_ci } 2426cb93a386Sopenharmony_ci coins->debugMarkCollapsed(log, test); 2427cb93a386Sopenharmony_ci } while ((test = test->next()) != head); 2428cb93a386Sopenharmony_ci} 2429cb93a386Sopenharmony_ci#endif 2430cb93a386Sopenharmony_ci 2431cb93a386Sopenharmony_cibool SkOpSpanBase::debugCoinEndLoopCheck() const { 2432cb93a386Sopenharmony_ci int loop = 0; 2433cb93a386Sopenharmony_ci const SkOpSpanBase* next = this; 2434cb93a386Sopenharmony_ci SkOpSpanBase* nextCoin; 2435cb93a386Sopenharmony_ci do { 2436cb93a386Sopenharmony_ci nextCoin = next->fCoinEnd; 2437cb93a386Sopenharmony_ci SkASSERT(nextCoin == this || nextCoin->fCoinEnd != nextCoin); 2438cb93a386Sopenharmony_ci for (int check = 1; check < loop - 1; ++check) { 2439cb93a386Sopenharmony_ci const SkOpSpanBase* checkCoin = this->fCoinEnd; 2440cb93a386Sopenharmony_ci const SkOpSpanBase* innerCoin = checkCoin; 2441cb93a386Sopenharmony_ci for (int inner = check + 1; inner < loop; ++inner) { 2442cb93a386Sopenharmony_ci innerCoin = innerCoin->fCoinEnd; 2443cb93a386Sopenharmony_ci if (checkCoin == innerCoin) { 2444cb93a386Sopenharmony_ci SkDebugf("*** bad coincident end loop ***\n"); 2445cb93a386Sopenharmony_ci return false; 2446cb93a386Sopenharmony_ci } 2447cb93a386Sopenharmony_ci } 2448cb93a386Sopenharmony_ci } 2449cb93a386Sopenharmony_ci ++loop; 2450cb93a386Sopenharmony_ci } while ((next = nextCoin) && next != this); 2451cb93a386Sopenharmony_ci return true; 2452cb93a386Sopenharmony_ci} 2453cb93a386Sopenharmony_ci 2454cb93a386Sopenharmony_ci#if DEBUG_COIN 2455cb93a386Sopenharmony_ci// Commented-out lines keep this in sync with insertCoinEnd() 2456cb93a386Sopenharmony_civoid SkOpSpanBase::debugInsertCoinEnd(SkPathOpsDebug::GlitchLog* log, const SkOpSpanBase* coin) const { 2457cb93a386Sopenharmony_ci if (containsCoinEnd(coin)) { 2458cb93a386Sopenharmony_ci// SkASSERT(coin->containsCoinEnd(this)); 2459cb93a386Sopenharmony_ci return; 2460cb93a386Sopenharmony_ci } 2461cb93a386Sopenharmony_ci debugValidate(); 2462cb93a386Sopenharmony_ci// SkASSERT(this != coin); 2463cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kMarkCoinEnd_Glitch, this, coin); 2464cb93a386Sopenharmony_ci// coin->fCoinEnd = this->fCoinEnd; 2465cb93a386Sopenharmony_ci// this->fCoinEnd = coinNext; 2466cb93a386Sopenharmony_ci debugValidate(); 2467cb93a386Sopenharmony_ci} 2468cb93a386Sopenharmony_ci 2469cb93a386Sopenharmony_ci// Commented-out lines keep this in sync with mergeMatches() 2470cb93a386Sopenharmony_ci// Look to see if pt-t linked list contains same segment more than once 2471cb93a386Sopenharmony_ci// if so, and if each pt-t is directly pointed to by spans in that segment, 2472cb93a386Sopenharmony_ci// merge them 2473cb93a386Sopenharmony_ci// keep the points, but remove spans so that the segment doesn't have 2 or more 2474cb93a386Sopenharmony_ci// spans pointing to the same pt-t loop at different loop elements 2475cb93a386Sopenharmony_civoid SkOpSpanBase::debugMergeMatches(SkPathOpsDebug::GlitchLog* log, const SkOpSpanBase* opp) const { 2476cb93a386Sopenharmony_ci const SkOpPtT* test = &fPtT; 2477cb93a386Sopenharmony_ci const SkOpPtT* testNext; 2478cb93a386Sopenharmony_ci const SkOpPtT* stop = test; 2479cb93a386Sopenharmony_ci do { 2480cb93a386Sopenharmony_ci testNext = test->next(); 2481cb93a386Sopenharmony_ci if (test->deleted()) { 2482cb93a386Sopenharmony_ci continue; 2483cb93a386Sopenharmony_ci } 2484cb93a386Sopenharmony_ci const SkOpSpanBase* testBase = test->span(); 2485cb93a386Sopenharmony_ci SkASSERT(testBase->ptT() == test); 2486cb93a386Sopenharmony_ci const SkOpSegment* segment = test->segment(); 2487cb93a386Sopenharmony_ci if (segment->done()) { 2488cb93a386Sopenharmony_ci continue; 2489cb93a386Sopenharmony_ci } 2490cb93a386Sopenharmony_ci const SkOpPtT* inner = opp->ptT(); 2491cb93a386Sopenharmony_ci const SkOpPtT* innerStop = inner; 2492cb93a386Sopenharmony_ci do { 2493cb93a386Sopenharmony_ci if (inner->segment() != segment) { 2494cb93a386Sopenharmony_ci continue; 2495cb93a386Sopenharmony_ci } 2496cb93a386Sopenharmony_ci if (inner->deleted()) { 2497cb93a386Sopenharmony_ci continue; 2498cb93a386Sopenharmony_ci } 2499cb93a386Sopenharmony_ci const SkOpSpanBase* innerBase = inner->span(); 2500cb93a386Sopenharmony_ci SkASSERT(innerBase->ptT() == inner); 2501cb93a386Sopenharmony_ci // when the intersection is first detected, the span base is marked if there are 2502cb93a386Sopenharmony_ci // more than one point in the intersection. 2503cb93a386Sopenharmony_ci// if (!innerBase->hasMultipleHint() && !testBase->hasMultipleHint()) { 2504cb93a386Sopenharmony_ci if (!zero_or_one(inner->fT)) { 2505cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kMergeMatches_Glitch, innerBase, test); 2506cb93a386Sopenharmony_ci } else { 2507cb93a386Sopenharmony_ci SkASSERT(inner->fT != test->fT); 2508cb93a386Sopenharmony_ci if (!zero_or_one(test->fT)) { 2509cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kMergeMatches_Glitch, testBase, inner); 2510cb93a386Sopenharmony_ci } else { 2511cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kMergeMatches_Glitch, segment); 2512cb93a386Sopenharmony_ci// SkDEBUGCODE(testBase->debugSetDeleted()); 2513cb93a386Sopenharmony_ci// test->setDeleted(); 2514cb93a386Sopenharmony_ci// SkDEBUGCODE(innerBase->debugSetDeleted()); 2515cb93a386Sopenharmony_ci// inner->setDeleted(); 2516cb93a386Sopenharmony_ci } 2517cb93a386Sopenharmony_ci } 2518cb93a386Sopenharmony_ci#ifdef SK_DEBUG // assert if another undeleted entry points to segment 2519cb93a386Sopenharmony_ci const SkOpPtT* debugInner = inner; 2520cb93a386Sopenharmony_ci while ((debugInner = debugInner->next()) != innerStop) { 2521cb93a386Sopenharmony_ci if (debugInner->segment() != segment) { 2522cb93a386Sopenharmony_ci continue; 2523cb93a386Sopenharmony_ci } 2524cb93a386Sopenharmony_ci if (debugInner->deleted()) { 2525cb93a386Sopenharmony_ci continue; 2526cb93a386Sopenharmony_ci } 2527cb93a386Sopenharmony_ci SkOPASSERT(0); 2528cb93a386Sopenharmony_ci } 2529cb93a386Sopenharmony_ci#endif 2530cb93a386Sopenharmony_ci break; 2531cb93a386Sopenharmony_ci// } 2532cb93a386Sopenharmony_ci break; 2533cb93a386Sopenharmony_ci } while ((inner = inner->next()) != innerStop); 2534cb93a386Sopenharmony_ci } while ((test = testNext) != stop); 2535cb93a386Sopenharmony_ci this->debugCheckForCollapsedCoincidence(log); 2536cb93a386Sopenharmony_ci} 2537cb93a386Sopenharmony_ci 2538cb93a386Sopenharmony_ci#endif 2539cb93a386Sopenharmony_ci 2540cb93a386Sopenharmony_civoid SkOpSpanBase::debugResetCoinT() const { 2541cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE_ORDER 2542cb93a386Sopenharmony_ci const SkOpPtT* ptT = &fPtT; 2543cb93a386Sopenharmony_ci do { 2544cb93a386Sopenharmony_ci ptT->debugResetCoinT(); 2545cb93a386Sopenharmony_ci ptT = ptT->next(); 2546cb93a386Sopenharmony_ci } while (ptT != &fPtT); 2547cb93a386Sopenharmony_ci#endif 2548cb93a386Sopenharmony_ci} 2549cb93a386Sopenharmony_ci 2550cb93a386Sopenharmony_civoid SkOpSpanBase::debugSetCoinT(int index) const { 2551cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE_ORDER 2552cb93a386Sopenharmony_ci const SkOpPtT* ptT = &fPtT; 2553cb93a386Sopenharmony_ci do { 2554cb93a386Sopenharmony_ci if (!ptT->deleted()) { 2555cb93a386Sopenharmony_ci ptT->debugSetCoinT(index); 2556cb93a386Sopenharmony_ci } 2557cb93a386Sopenharmony_ci ptT = ptT->next(); 2558cb93a386Sopenharmony_ci } while (ptT != &fPtT); 2559cb93a386Sopenharmony_ci#endif 2560cb93a386Sopenharmony_ci} 2561cb93a386Sopenharmony_ci 2562cb93a386Sopenharmony_ciconst SkOpSpan* SkOpSpanBase::debugStarter(SkOpSpanBase const** endPtr) const { 2563cb93a386Sopenharmony_ci const SkOpSpanBase* end = *endPtr; 2564cb93a386Sopenharmony_ci SkASSERT(this->segment() == end->segment()); 2565cb93a386Sopenharmony_ci const SkOpSpanBase* result; 2566cb93a386Sopenharmony_ci if (t() < end->t()) { 2567cb93a386Sopenharmony_ci result = this; 2568cb93a386Sopenharmony_ci } else { 2569cb93a386Sopenharmony_ci result = end; 2570cb93a386Sopenharmony_ci *endPtr = this; 2571cb93a386Sopenharmony_ci } 2572cb93a386Sopenharmony_ci return result->upCast(); 2573cb93a386Sopenharmony_ci} 2574cb93a386Sopenharmony_ci 2575cb93a386Sopenharmony_civoid SkOpSpanBase::debugValidate() const { 2576cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE 2577cb93a386Sopenharmony_ci if (this->globalState()->debugCheckHealth()) { 2578cb93a386Sopenharmony_ci return; 2579cb93a386Sopenharmony_ci } 2580cb93a386Sopenharmony_ci#endif 2581cb93a386Sopenharmony_ci#if DEBUG_VALIDATE 2582cb93a386Sopenharmony_ci const SkOpPtT* ptT = &fPtT; 2583cb93a386Sopenharmony_ci SkASSERT(ptT->span() == this); 2584cb93a386Sopenharmony_ci do { 2585cb93a386Sopenharmony_ci// SkASSERT(SkDPoint::RoughlyEqual(fPtT.fPt, ptT->fPt)); 2586cb93a386Sopenharmony_ci ptT->debugValidate(); 2587cb93a386Sopenharmony_ci ptT = ptT->next(); 2588cb93a386Sopenharmony_ci } while (ptT != &fPtT); 2589cb93a386Sopenharmony_ci SkASSERT(this->debugCoinEndLoopCheck()); 2590cb93a386Sopenharmony_ci if (!this->final()) { 2591cb93a386Sopenharmony_ci SkASSERT(this->upCast()->debugCoinLoopCheck()); 2592cb93a386Sopenharmony_ci } 2593cb93a386Sopenharmony_ci if (fFromAngle) { 2594cb93a386Sopenharmony_ci fFromAngle->debugValidate(); 2595cb93a386Sopenharmony_ci } 2596cb93a386Sopenharmony_ci if (!this->final() && this->upCast()->toAngle()) { 2597cb93a386Sopenharmony_ci this->upCast()->toAngle()->debugValidate(); 2598cb93a386Sopenharmony_ci } 2599cb93a386Sopenharmony_ci#endif 2600cb93a386Sopenharmony_ci} 2601cb93a386Sopenharmony_ci 2602cb93a386Sopenharmony_cibool SkOpSpan::debugCoinLoopCheck() const { 2603cb93a386Sopenharmony_ci int loop = 0; 2604cb93a386Sopenharmony_ci const SkOpSpan* next = this; 2605cb93a386Sopenharmony_ci SkOpSpan* nextCoin; 2606cb93a386Sopenharmony_ci do { 2607cb93a386Sopenharmony_ci nextCoin = next->fCoincident; 2608cb93a386Sopenharmony_ci SkASSERT(nextCoin == this || nextCoin->fCoincident != nextCoin); 2609cb93a386Sopenharmony_ci for (int check = 1; check < loop - 1; ++check) { 2610cb93a386Sopenharmony_ci const SkOpSpan* checkCoin = this->fCoincident; 2611cb93a386Sopenharmony_ci const SkOpSpan* innerCoin = checkCoin; 2612cb93a386Sopenharmony_ci for (int inner = check + 1; inner < loop; ++inner) { 2613cb93a386Sopenharmony_ci innerCoin = innerCoin->fCoincident; 2614cb93a386Sopenharmony_ci if (checkCoin == innerCoin) { 2615cb93a386Sopenharmony_ci SkDebugf("*** bad coincident loop ***\n"); 2616cb93a386Sopenharmony_ci return false; 2617cb93a386Sopenharmony_ci } 2618cb93a386Sopenharmony_ci } 2619cb93a386Sopenharmony_ci } 2620cb93a386Sopenharmony_ci ++loop; 2621cb93a386Sopenharmony_ci } while ((next = nextCoin) && next != this); 2622cb93a386Sopenharmony_ci return true; 2623cb93a386Sopenharmony_ci} 2624cb93a386Sopenharmony_ci 2625cb93a386Sopenharmony_ci#if DEBUG_COIN 2626cb93a386Sopenharmony_ci// Commented-out lines keep this in sync with insertCoincidence() in header 2627cb93a386Sopenharmony_civoid SkOpSpan::debugInsertCoincidence(SkPathOpsDebug::GlitchLog* log, const SkOpSpan* coin) const { 2628cb93a386Sopenharmony_ci if (containsCoincidence(coin)) { 2629cb93a386Sopenharmony_ci// SkASSERT(coin->containsCoincidence(this)); 2630cb93a386Sopenharmony_ci return; 2631cb93a386Sopenharmony_ci } 2632cb93a386Sopenharmony_ci debugValidate(); 2633cb93a386Sopenharmony_ci// SkASSERT(this != coin); 2634cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kMarkCoinStart_Glitch, this, coin); 2635cb93a386Sopenharmony_ci// coin->fCoincident = this->fCoincident; 2636cb93a386Sopenharmony_ci// this->fCoincident = coinNext; 2637cb93a386Sopenharmony_ci debugValidate(); 2638cb93a386Sopenharmony_ci} 2639cb93a386Sopenharmony_ci 2640cb93a386Sopenharmony_ci// Commented-out lines keep this in sync with insertCoincidence() 2641cb93a386Sopenharmony_civoid SkOpSpan::debugInsertCoincidence(SkPathOpsDebug::GlitchLog* log, const SkOpSegment* segment, bool flipped, bool ordered) const { 2642cb93a386Sopenharmony_ci if (this->containsCoincidence(segment)) { 2643cb93a386Sopenharmony_ci return; 2644cb93a386Sopenharmony_ci } 2645cb93a386Sopenharmony_ci const SkOpPtT* next = &fPtT; 2646cb93a386Sopenharmony_ci while ((next = next->next()) != &fPtT) { 2647cb93a386Sopenharmony_ci if (next->segment() == segment) { 2648cb93a386Sopenharmony_ci const SkOpSpan* span; 2649cb93a386Sopenharmony_ci const SkOpSpanBase* base = next->span(); 2650cb93a386Sopenharmony_ci if (!ordered) { 2651cb93a386Sopenharmony_ci const SkOpSpanBase* spanEnd = fNext->contains(segment)->span(); 2652cb93a386Sopenharmony_ci const SkOpPtT* start = base->ptT()->starter(spanEnd->ptT()); 2653cb93a386Sopenharmony_ci FAIL_IF(!start->span()->upCastable(), this); 2654cb93a386Sopenharmony_ci span = const_cast<SkOpSpan*>(start->span()->upCast()); 2655cb93a386Sopenharmony_ci } 2656cb93a386Sopenharmony_ci else if (flipped) { 2657cb93a386Sopenharmony_ci span = base->prev(); 2658cb93a386Sopenharmony_ci FAIL_IF(!span, this); 2659cb93a386Sopenharmony_ci } 2660cb93a386Sopenharmony_ci else { 2661cb93a386Sopenharmony_ci FAIL_IF(!base->upCastable(), this); 2662cb93a386Sopenharmony_ci span = base->upCast(); 2663cb93a386Sopenharmony_ci } 2664cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kMarkCoinInsert_Glitch, span); 2665cb93a386Sopenharmony_ci return; 2666cb93a386Sopenharmony_ci } 2667cb93a386Sopenharmony_ci } 2668cb93a386Sopenharmony_ci#if DEBUG_COIN 2669cb93a386Sopenharmony_ci log->record(SkPathOpsDebug::kMarkCoinMissing_Glitch, segment, this); 2670cb93a386Sopenharmony_ci#endif 2671cb93a386Sopenharmony_ci return; 2672cb93a386Sopenharmony_ci} 2673cb93a386Sopenharmony_ci#endif 2674cb93a386Sopenharmony_ci 2675cb93a386Sopenharmony_ci// called only by test code 2676cb93a386Sopenharmony_ciint SkIntersections::debugCoincidentUsed() const { 2677cb93a386Sopenharmony_ci if (!fIsCoincident[0]) { 2678cb93a386Sopenharmony_ci SkASSERT(!fIsCoincident[1]); 2679cb93a386Sopenharmony_ci return 0; 2680cb93a386Sopenharmony_ci } 2681cb93a386Sopenharmony_ci int count = 0; 2682cb93a386Sopenharmony_ci SkDEBUGCODE(int count2 = 0;) 2683cb93a386Sopenharmony_ci for (int index = 0; index < fUsed; ++index) { 2684cb93a386Sopenharmony_ci if (fIsCoincident[0] & (1 << index)) { 2685cb93a386Sopenharmony_ci ++count; 2686cb93a386Sopenharmony_ci } 2687cb93a386Sopenharmony_ci#ifdef SK_DEBUG 2688cb93a386Sopenharmony_ci if (fIsCoincident[1] & (1 << index)) { 2689cb93a386Sopenharmony_ci ++count2; 2690cb93a386Sopenharmony_ci } 2691cb93a386Sopenharmony_ci#endif 2692cb93a386Sopenharmony_ci } 2693cb93a386Sopenharmony_ci SkASSERT(count == count2); 2694cb93a386Sopenharmony_ci return count; 2695cb93a386Sopenharmony_ci} 2696cb93a386Sopenharmony_ci 2697cb93a386Sopenharmony_ci#include "src/pathops/SkOpContour.h" 2698cb93a386Sopenharmony_ci 2699cb93a386Sopenharmony_ci// Commented-out lines keep this in sync with addOpp() 2700cb93a386Sopenharmony_civoid SkOpPtT::debugAddOpp(const SkOpPtT* opp, const SkOpPtT* oppPrev) const { 2701cb93a386Sopenharmony_ci SkDEBUGCODE(const SkOpPtT* oldNext = this->fNext); 2702cb93a386Sopenharmony_ci SkASSERT(this != opp); 2703cb93a386Sopenharmony_ci// this->fNext = opp; 2704cb93a386Sopenharmony_ci SkASSERT(oppPrev != oldNext); 2705cb93a386Sopenharmony_ci// oppPrev->fNext = oldNext; 2706cb93a386Sopenharmony_ci} 2707cb93a386Sopenharmony_ci 2708cb93a386Sopenharmony_cibool SkOpPtT::debugContains(const SkOpPtT* check) const { 2709cb93a386Sopenharmony_ci SkASSERT(this != check); 2710cb93a386Sopenharmony_ci const SkOpPtT* ptT = this; 2711cb93a386Sopenharmony_ci int links = 0; 2712cb93a386Sopenharmony_ci do { 2713cb93a386Sopenharmony_ci ptT = ptT->next(); 2714cb93a386Sopenharmony_ci if (ptT == check) { 2715cb93a386Sopenharmony_ci return true; 2716cb93a386Sopenharmony_ci } 2717cb93a386Sopenharmony_ci ++links; 2718cb93a386Sopenharmony_ci const SkOpPtT* test = this; 2719cb93a386Sopenharmony_ci for (int index = 0; index < links; ++index) { 2720cb93a386Sopenharmony_ci if (ptT == test) { 2721cb93a386Sopenharmony_ci return false; 2722cb93a386Sopenharmony_ci } 2723cb93a386Sopenharmony_ci test = test->next(); 2724cb93a386Sopenharmony_ci } 2725cb93a386Sopenharmony_ci } while (true); 2726cb93a386Sopenharmony_ci} 2727cb93a386Sopenharmony_ci 2728cb93a386Sopenharmony_ciconst SkOpPtT* SkOpPtT::debugContains(const SkOpSegment* check) const { 2729cb93a386Sopenharmony_ci SkASSERT(this->segment() != check); 2730cb93a386Sopenharmony_ci const SkOpPtT* ptT = this; 2731cb93a386Sopenharmony_ci int links = 0; 2732cb93a386Sopenharmony_ci do { 2733cb93a386Sopenharmony_ci ptT = ptT->next(); 2734cb93a386Sopenharmony_ci if (ptT->segment() == check) { 2735cb93a386Sopenharmony_ci return ptT; 2736cb93a386Sopenharmony_ci } 2737cb93a386Sopenharmony_ci ++links; 2738cb93a386Sopenharmony_ci const SkOpPtT* test = this; 2739cb93a386Sopenharmony_ci for (int index = 0; index < links; ++index) { 2740cb93a386Sopenharmony_ci if (ptT == test) { 2741cb93a386Sopenharmony_ci return nullptr; 2742cb93a386Sopenharmony_ci } 2743cb93a386Sopenharmony_ci test = test->next(); 2744cb93a386Sopenharmony_ci } 2745cb93a386Sopenharmony_ci } while (true); 2746cb93a386Sopenharmony_ci} 2747cb93a386Sopenharmony_ci 2748cb93a386Sopenharmony_ciconst SkOpPtT* SkOpPtT::debugEnder(const SkOpPtT* end) const { 2749cb93a386Sopenharmony_ci return fT < end->fT ? end : this; 2750cb93a386Sopenharmony_ci} 2751cb93a386Sopenharmony_ci 2752cb93a386Sopenharmony_ciint SkOpPtT::debugLoopLimit(bool report) const { 2753cb93a386Sopenharmony_ci int loop = 0; 2754cb93a386Sopenharmony_ci const SkOpPtT* next = this; 2755cb93a386Sopenharmony_ci do { 2756cb93a386Sopenharmony_ci for (int check = 1; check < loop - 1; ++check) { 2757cb93a386Sopenharmony_ci const SkOpPtT* checkPtT = this->fNext; 2758cb93a386Sopenharmony_ci const SkOpPtT* innerPtT = checkPtT; 2759cb93a386Sopenharmony_ci for (int inner = check + 1; inner < loop; ++inner) { 2760cb93a386Sopenharmony_ci innerPtT = innerPtT->fNext; 2761cb93a386Sopenharmony_ci if (checkPtT == innerPtT) { 2762cb93a386Sopenharmony_ci if (report) { 2763cb93a386Sopenharmony_ci SkDebugf("*** bad ptT loop ***\n"); 2764cb93a386Sopenharmony_ci } 2765cb93a386Sopenharmony_ci return loop; 2766cb93a386Sopenharmony_ci } 2767cb93a386Sopenharmony_ci } 2768cb93a386Sopenharmony_ci } 2769cb93a386Sopenharmony_ci // there's nothing wrong with extremely large loop counts -- but this may appear to hang 2770cb93a386Sopenharmony_ci // by taking a very long time to figure out that no loop entry is a duplicate 2771cb93a386Sopenharmony_ci // -- and it's likely that a large loop count is indicative of a bug somewhere 2772cb93a386Sopenharmony_ci if (++loop > 1000) { 2773cb93a386Sopenharmony_ci SkDebugf("*** loop count exceeds 1000 ***\n"); 2774cb93a386Sopenharmony_ci return 1000; 2775cb93a386Sopenharmony_ci } 2776cb93a386Sopenharmony_ci } while ((next = next->fNext) && next != this); 2777cb93a386Sopenharmony_ci return 0; 2778cb93a386Sopenharmony_ci} 2779cb93a386Sopenharmony_ci 2780cb93a386Sopenharmony_ciconst SkOpPtT* SkOpPtT::debugOppPrev(const SkOpPtT* opp) const { 2781cb93a386Sopenharmony_ci return this->oppPrev(const_cast<SkOpPtT*>(opp)); 2782cb93a386Sopenharmony_ci} 2783cb93a386Sopenharmony_ci 2784cb93a386Sopenharmony_civoid SkOpPtT::debugResetCoinT() const { 2785cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE_ORDER 2786cb93a386Sopenharmony_ci this->segment()->debugResetCoinT(); 2787cb93a386Sopenharmony_ci#endif 2788cb93a386Sopenharmony_ci} 2789cb93a386Sopenharmony_ci 2790cb93a386Sopenharmony_civoid SkOpPtT::debugSetCoinT(int index) const { 2791cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE_ORDER 2792cb93a386Sopenharmony_ci this->segment()->debugSetCoinT(index, fT); 2793cb93a386Sopenharmony_ci#endif 2794cb93a386Sopenharmony_ci} 2795cb93a386Sopenharmony_ci 2796cb93a386Sopenharmony_civoid SkOpPtT::debugValidate() const { 2797cb93a386Sopenharmony_ci#if DEBUG_COINCIDENCE 2798cb93a386Sopenharmony_ci if (this->globalState()->debugCheckHealth()) { 2799cb93a386Sopenharmony_ci return; 2800cb93a386Sopenharmony_ci } 2801cb93a386Sopenharmony_ci#endif 2802cb93a386Sopenharmony_ci#if DEBUG_VALIDATE 2803cb93a386Sopenharmony_ci SkOpPhase phase = contour()->globalState()->phase(); 2804cb93a386Sopenharmony_ci if (phase == SkOpPhase::kIntersecting || phase == SkOpPhase::kFixWinding) { 2805cb93a386Sopenharmony_ci return; 2806cb93a386Sopenharmony_ci } 2807cb93a386Sopenharmony_ci SkASSERT(fNext); 2808cb93a386Sopenharmony_ci SkASSERT(fNext != this); 2809cb93a386Sopenharmony_ci SkASSERT(fNext->fNext); 2810cb93a386Sopenharmony_ci SkASSERT(debugLoopLimit(false) == 0); 2811cb93a386Sopenharmony_ci#endif 2812cb93a386Sopenharmony_ci} 2813cb93a386Sopenharmony_ci 2814cb93a386Sopenharmony_cistatic void output_scalar(SkScalar num) { 2815cb93a386Sopenharmony_ci if (num == (int) num) { 2816cb93a386Sopenharmony_ci SkDebugf("%d", (int) num); 2817cb93a386Sopenharmony_ci } else { 2818cb93a386Sopenharmony_ci SkString str; 2819cb93a386Sopenharmony_ci str.printf("%1.9g", num); 2820cb93a386Sopenharmony_ci int width = (int) str.size(); 2821cb93a386Sopenharmony_ci const char* cStr = str.c_str(); 2822cb93a386Sopenharmony_ci while (cStr[width - 1] == '0') { 2823cb93a386Sopenharmony_ci --width; 2824cb93a386Sopenharmony_ci } 2825cb93a386Sopenharmony_ci str.resize(width); 2826cb93a386Sopenharmony_ci SkDebugf("%sf", str.c_str()); 2827cb93a386Sopenharmony_ci } 2828cb93a386Sopenharmony_ci} 2829cb93a386Sopenharmony_ci 2830cb93a386Sopenharmony_cistatic void output_points(const SkPoint* pts, int count) { 2831cb93a386Sopenharmony_ci for (int index = 0; index < count; ++index) { 2832cb93a386Sopenharmony_ci output_scalar(pts[index].fX); 2833cb93a386Sopenharmony_ci SkDebugf(", "); 2834cb93a386Sopenharmony_ci output_scalar(pts[index].fY); 2835cb93a386Sopenharmony_ci if (index + 1 < count) { 2836cb93a386Sopenharmony_ci SkDebugf(", "); 2837cb93a386Sopenharmony_ci } 2838cb93a386Sopenharmony_ci } 2839cb93a386Sopenharmony_ci} 2840cb93a386Sopenharmony_ci 2841cb93a386Sopenharmony_cistatic void showPathContours(const SkPath& path, const char* pathName) { 2842cb93a386Sopenharmony_ci for (auto [verb, pts, w] : SkPathPriv::Iterate(path)) { 2843cb93a386Sopenharmony_ci switch (verb) { 2844cb93a386Sopenharmony_ci case SkPathVerb::kMove: 2845cb93a386Sopenharmony_ci SkDebugf(" %s.moveTo(", pathName); 2846cb93a386Sopenharmony_ci output_points(&pts[0], 1); 2847cb93a386Sopenharmony_ci SkDebugf(");\n"); 2848cb93a386Sopenharmony_ci continue; 2849cb93a386Sopenharmony_ci case SkPathVerb::kLine: 2850cb93a386Sopenharmony_ci SkDebugf(" %s.lineTo(", pathName); 2851cb93a386Sopenharmony_ci output_points(&pts[1], 1); 2852cb93a386Sopenharmony_ci SkDebugf(");\n"); 2853cb93a386Sopenharmony_ci break; 2854cb93a386Sopenharmony_ci case SkPathVerb::kQuad: 2855cb93a386Sopenharmony_ci SkDebugf(" %s.quadTo(", pathName); 2856cb93a386Sopenharmony_ci output_points(&pts[1], 2); 2857cb93a386Sopenharmony_ci SkDebugf(");\n"); 2858cb93a386Sopenharmony_ci break; 2859cb93a386Sopenharmony_ci case SkPathVerb::kConic: 2860cb93a386Sopenharmony_ci SkDebugf(" %s.conicTo(", pathName); 2861cb93a386Sopenharmony_ci output_points(&pts[1], 2); 2862cb93a386Sopenharmony_ci SkDebugf(", %1.9gf);\n", *w); 2863cb93a386Sopenharmony_ci break; 2864cb93a386Sopenharmony_ci case SkPathVerb::kCubic: 2865cb93a386Sopenharmony_ci SkDebugf(" %s.cubicTo(", pathName); 2866cb93a386Sopenharmony_ci output_points(&pts[1], 3); 2867cb93a386Sopenharmony_ci SkDebugf(");\n"); 2868cb93a386Sopenharmony_ci break; 2869cb93a386Sopenharmony_ci case SkPathVerb::kClose: 2870cb93a386Sopenharmony_ci SkDebugf(" %s.close();\n", pathName); 2871cb93a386Sopenharmony_ci break; 2872cb93a386Sopenharmony_ci default: 2873cb93a386Sopenharmony_ci SkDEBUGFAIL("bad verb"); 2874cb93a386Sopenharmony_ci return; 2875cb93a386Sopenharmony_ci } 2876cb93a386Sopenharmony_ci } 2877cb93a386Sopenharmony_ci} 2878cb93a386Sopenharmony_ci 2879cb93a386Sopenharmony_cistatic const char* gFillTypeStr[] = { 2880cb93a386Sopenharmony_ci "kWinding", 2881cb93a386Sopenharmony_ci "kEvenOdd", 2882cb93a386Sopenharmony_ci "kInverseWinding", 2883cb93a386Sopenharmony_ci "kInverseEvenOdd" 2884cb93a386Sopenharmony_ci}; 2885cb93a386Sopenharmony_ci 2886cb93a386Sopenharmony_civoid SkPathOpsDebug::ShowOnePath(const SkPath& path, const char* name, bool includeDeclaration) { 2887cb93a386Sopenharmony_ci#define SUPPORT_RECT_CONTOUR_DETECTION 0 2888cb93a386Sopenharmony_ci#if SUPPORT_RECT_CONTOUR_DETECTION 2889cb93a386Sopenharmony_ci int rectCount = path.isRectContours() ? path.rectContours(nullptr, nullptr) : 0; 2890cb93a386Sopenharmony_ci if (rectCount > 0) { 2891cb93a386Sopenharmony_ci SkTDArray<SkRect> rects; 2892cb93a386Sopenharmony_ci SkTDArray<SkPathDirection> directions; 2893cb93a386Sopenharmony_ci rects.setCount(rectCount); 2894cb93a386Sopenharmony_ci directions.setCount(rectCount); 2895cb93a386Sopenharmony_ci path.rectContours(rects.begin(), directions.begin()); 2896cb93a386Sopenharmony_ci for (int contour = 0; contour < rectCount; ++contour) { 2897cb93a386Sopenharmony_ci const SkRect& rect = rects[contour]; 2898cb93a386Sopenharmony_ci SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLeft, rect.fTop, 2899cb93a386Sopenharmony_ci rect.fRight, rect.fBottom, directions[contour] == SkPathDirection::kCCW 2900cb93a386Sopenharmony_ci ? "SkPathDirection::kCCW" : "SkPathDirection::kCW"); 2901cb93a386Sopenharmony_ci } 2902cb93a386Sopenharmony_ci return; 2903cb93a386Sopenharmony_ci } 2904cb93a386Sopenharmony_ci#endif 2905cb93a386Sopenharmony_ci SkPathFillType fillType = path.getFillType(); 2906cb93a386Sopenharmony_ci SkASSERT(fillType >= SkPathFillType::kWinding && fillType <= SkPathFillType::kInverseEvenOdd); 2907cb93a386Sopenharmony_ci if (includeDeclaration) { 2908cb93a386Sopenharmony_ci SkDebugf(" SkPath %s;\n", name); 2909cb93a386Sopenharmony_ci } 2910cb93a386Sopenharmony_ci SkDebugf(" %s.setFillType(SkPath::%s);\n", name, gFillTypeStr[(int)fillType]); 2911cb93a386Sopenharmony_ci showPathContours(path, name); 2912cb93a386Sopenharmony_ci} 2913cb93a386Sopenharmony_ci 2914cb93a386Sopenharmony_ci#if DEBUG_DUMP_VERIFY 2915cb93a386Sopenharmony_ci#include "include/core/SkData.h" 2916cb93a386Sopenharmony_ci#include "include/core/SkStream.h" 2917cb93a386Sopenharmony_ci 2918cb93a386Sopenharmony_cistatic void dump_path(FILE* file, const SkPath& path, bool force, bool dumpAsHex) { 2919cb93a386Sopenharmony_ci SkDynamicMemoryWStream wStream; 2920cb93a386Sopenharmony_ci path.dump(&wStream, force, dumpAsHex); 2921cb93a386Sopenharmony_ci sk_sp<SkData> data(wStream.detachAsData()); 2922cb93a386Sopenharmony_ci fprintf(file, "%.*s\n", (int) data->size(), (char*) data->data()); 2923cb93a386Sopenharmony_ci} 2924cb93a386Sopenharmony_ci 2925cb93a386Sopenharmony_cistatic int dumpID = 0; 2926cb93a386Sopenharmony_ci 2927cb93a386Sopenharmony_civoid SkPathOpsDebug::DumpOp(const SkPath& one, const SkPath& two, SkPathOp op, 2928cb93a386Sopenharmony_ci const char* testName) { 2929cb93a386Sopenharmony_ci FILE* file = sk_fopen("op_dump.txt", kWrite_SkFILE_Flag); 2930cb93a386Sopenharmony_ci DumpOp(file, one, two, op, testName); 2931cb93a386Sopenharmony_ci} 2932cb93a386Sopenharmony_ci 2933cb93a386Sopenharmony_civoid SkPathOpsDebug::DumpOp(FILE* file, const SkPath& one, const SkPath& two, SkPathOp op, 2934cb93a386Sopenharmony_ci const char* testName) { 2935cb93a386Sopenharmony_ci const char* name = testName ? testName : "op"; 2936cb93a386Sopenharmony_ci fprintf(file, 2937cb93a386Sopenharmony_ci "\nstatic void %s_%d(skiatest::Reporter* reporter, const char* filename) {\n", 2938cb93a386Sopenharmony_ci name, ++dumpID); 2939cb93a386Sopenharmony_ci fprintf(file, " SkPath path;\n"); 2940cb93a386Sopenharmony_ci fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", one.getFillType()); 2941cb93a386Sopenharmony_ci dump_path(file, one, false, true); 2942cb93a386Sopenharmony_ci fprintf(file, " SkPath path1(path);\n"); 2943cb93a386Sopenharmony_ci fprintf(file, " path.reset();\n"); 2944cb93a386Sopenharmony_ci fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", two.getFillType()); 2945cb93a386Sopenharmony_ci dump_path(file, two, false, true); 2946cb93a386Sopenharmony_ci fprintf(file, " SkPath path2(path);\n"); 2947cb93a386Sopenharmony_ci fprintf(file, " testPathOp(reporter, path1, path2, (SkPathOp) %d, filename);\n", op); 2948cb93a386Sopenharmony_ci fprintf(file, "}\n\n"); 2949cb93a386Sopenharmony_ci fclose(file); 2950cb93a386Sopenharmony_ci} 2951cb93a386Sopenharmony_ci 2952cb93a386Sopenharmony_civoid SkPathOpsDebug::DumpSimplify(const SkPath& path, const char* testName) { 2953cb93a386Sopenharmony_ci FILE* file = sk_fopen("simplify_dump.txt", kWrite_SkFILE_Flag); 2954cb93a386Sopenharmony_ci DumpSimplify(file, path, testName); 2955cb93a386Sopenharmony_ci} 2956cb93a386Sopenharmony_ci 2957cb93a386Sopenharmony_civoid SkPathOpsDebug::DumpSimplify(FILE* file, const SkPath& path, const char* testName) { 2958cb93a386Sopenharmony_ci const char* name = testName ? testName : "simplify"; 2959cb93a386Sopenharmony_ci fprintf(file, 2960cb93a386Sopenharmony_ci "\nstatic void %s_%d(skiatest::Reporter* reporter, const char* filename) {\n", 2961cb93a386Sopenharmony_ci name, ++dumpID); 2962cb93a386Sopenharmony_ci fprintf(file, " SkPath path;\n"); 2963cb93a386Sopenharmony_ci fprintf(file, " path.setFillType((SkPath::FillType) %d);\n", path.getFillType()); 2964cb93a386Sopenharmony_ci dump_path(file, path, false, true); 2965cb93a386Sopenharmony_ci fprintf(file, " testSimplify(reporter, path, filename);\n"); 2966cb93a386Sopenharmony_ci fprintf(file, "}\n\n"); 2967cb93a386Sopenharmony_ci fclose(file); 2968cb93a386Sopenharmony_ci} 2969cb93a386Sopenharmony_ci 2970cb93a386Sopenharmony_ci#include "include/core/SkBitmap.h" 2971cb93a386Sopenharmony_ci#include "include/core/SkCanvas.h" 2972cb93a386Sopenharmony_ci#include "include/core/SkPaint.h" 2973cb93a386Sopenharmony_ci 2974cb93a386Sopenharmony_ciconst int bitWidth = 64; 2975cb93a386Sopenharmony_ciconst int bitHeight = 64; 2976cb93a386Sopenharmony_ci 2977cb93a386Sopenharmony_cistatic void debug_scale_matrix(const SkPath& one, const SkPath* two, SkMatrix& scale) { 2978cb93a386Sopenharmony_ci SkRect larger = one.getBounds(); 2979cb93a386Sopenharmony_ci if (two) { 2980cb93a386Sopenharmony_ci larger.join(two->getBounds()); 2981cb93a386Sopenharmony_ci } 2982cb93a386Sopenharmony_ci SkScalar largerWidth = larger.width(); 2983cb93a386Sopenharmony_ci if (largerWidth < 4) { 2984cb93a386Sopenharmony_ci largerWidth = 4; 2985cb93a386Sopenharmony_ci } 2986cb93a386Sopenharmony_ci SkScalar largerHeight = larger.height(); 2987cb93a386Sopenharmony_ci if (largerHeight < 4) { 2988cb93a386Sopenharmony_ci largerHeight = 4; 2989cb93a386Sopenharmony_ci } 2990cb93a386Sopenharmony_ci SkScalar hScale = (bitWidth - 2) / largerWidth; 2991cb93a386Sopenharmony_ci SkScalar vScale = (bitHeight - 2) / largerHeight; 2992cb93a386Sopenharmony_ci scale.reset(); 2993cb93a386Sopenharmony_ci scale.preScale(hScale, vScale); 2994cb93a386Sopenharmony_ci larger.fLeft *= hScale; 2995cb93a386Sopenharmony_ci larger.fRight *= hScale; 2996cb93a386Sopenharmony_ci larger.fTop *= vScale; 2997cb93a386Sopenharmony_ci larger.fBottom *= vScale; 2998cb93a386Sopenharmony_ci SkScalar dx = -16000 > larger.fLeft ? -16000 - larger.fLeft 2999cb93a386Sopenharmony_ci : 16000 < larger.fRight ? 16000 - larger.fRight : 0; 3000cb93a386Sopenharmony_ci SkScalar dy = -16000 > larger.fTop ? -16000 - larger.fTop 3001cb93a386Sopenharmony_ci : 16000 < larger.fBottom ? 16000 - larger.fBottom : 0; 3002cb93a386Sopenharmony_ci scale.preTranslate(dx, dy); 3003cb93a386Sopenharmony_ci} 3004cb93a386Sopenharmony_ci 3005cb93a386Sopenharmony_cistatic int debug_paths_draw_the_same(const SkPath& one, const SkPath& two, SkBitmap& bits) { 3006cb93a386Sopenharmony_ci if (bits.width() == 0) { 3007cb93a386Sopenharmony_ci bits.allocN32Pixels(bitWidth * 2, bitHeight); 3008cb93a386Sopenharmony_ci } 3009cb93a386Sopenharmony_ci SkCanvas canvas(bits); 3010cb93a386Sopenharmony_ci canvas.drawColor(SK_ColorWHITE); 3011cb93a386Sopenharmony_ci SkPaint paint; 3012cb93a386Sopenharmony_ci canvas.save(); 3013cb93a386Sopenharmony_ci const SkRect& bounds1 = one.getBounds(); 3014cb93a386Sopenharmony_ci canvas.translate(-bounds1.fLeft + 1, -bounds1.fTop + 1); 3015cb93a386Sopenharmony_ci canvas.drawPath(one, paint); 3016cb93a386Sopenharmony_ci canvas.restore(); 3017cb93a386Sopenharmony_ci canvas.save(); 3018cb93a386Sopenharmony_ci canvas.translate(-bounds1.fLeft + 1 + bitWidth, -bounds1.fTop + 1); 3019cb93a386Sopenharmony_ci canvas.drawPath(two, paint); 3020cb93a386Sopenharmony_ci canvas.restore(); 3021cb93a386Sopenharmony_ci int errors = 0; 3022cb93a386Sopenharmony_ci for (int y = 0; y < bitHeight - 1; ++y) { 3023cb93a386Sopenharmony_ci uint32_t* addr1 = bits.getAddr32(0, y); 3024cb93a386Sopenharmony_ci uint32_t* addr2 = bits.getAddr32(0, y + 1); 3025cb93a386Sopenharmony_ci uint32_t* addr3 = bits.getAddr32(bitWidth, y); 3026cb93a386Sopenharmony_ci uint32_t* addr4 = bits.getAddr32(bitWidth, y + 1); 3027cb93a386Sopenharmony_ci for (int x = 0; x < bitWidth - 1; ++x) { 3028cb93a386Sopenharmony_ci // count 2x2 blocks 3029cb93a386Sopenharmony_ci bool err = addr1[x] != addr3[x]; 3030cb93a386Sopenharmony_ci if (err) { 3031cb93a386Sopenharmony_ci errors += addr1[x + 1] != addr3[x + 1] 3032cb93a386Sopenharmony_ci && addr2[x] != addr4[x] && addr2[x + 1] != addr4[x + 1]; 3033cb93a386Sopenharmony_ci } 3034cb93a386Sopenharmony_ci } 3035cb93a386Sopenharmony_ci } 3036cb93a386Sopenharmony_ci return errors; 3037cb93a386Sopenharmony_ci} 3038cb93a386Sopenharmony_ci 3039cb93a386Sopenharmony_civoid SkPathOpsDebug::ReportOpFail(const SkPath& one, const SkPath& two, SkPathOp op) { 3040cb93a386Sopenharmony_ci SkDebugf("// Op did not expect failure\n"); 3041cb93a386Sopenharmony_ci DumpOp(stderr, one, two, op, "opTest"); 3042cb93a386Sopenharmony_ci fflush(stderr); 3043cb93a386Sopenharmony_ci} 3044cb93a386Sopenharmony_ci 3045cb93a386Sopenharmony_civoid SkPathOpsDebug::VerifyOp(const SkPath& one, const SkPath& two, SkPathOp op, 3046cb93a386Sopenharmony_ci const SkPath& result) { 3047cb93a386Sopenharmony_ci SkPath pathOut, scaledPathOut; 3048cb93a386Sopenharmony_ci SkRegion rgnA, rgnB, openClip, rgnOut; 3049cb93a386Sopenharmony_ci openClip.setRect(-16000, -16000, 16000, 16000); 3050cb93a386Sopenharmony_ci rgnA.setPath(one, openClip); 3051cb93a386Sopenharmony_ci rgnB.setPath(two, openClip); 3052cb93a386Sopenharmony_ci rgnOut.op(rgnA, rgnB, (SkRegion::Op) op); 3053cb93a386Sopenharmony_ci rgnOut.getBoundaryPath(&pathOut); 3054cb93a386Sopenharmony_ci SkMatrix scale; 3055cb93a386Sopenharmony_ci debug_scale_matrix(one, &two, scale); 3056cb93a386Sopenharmony_ci SkRegion scaledRgnA, scaledRgnB, scaledRgnOut; 3057cb93a386Sopenharmony_ci SkPath scaledA, scaledB; 3058cb93a386Sopenharmony_ci scaledA.addPath(one, scale); 3059cb93a386Sopenharmony_ci scaledA.setFillType(one.getFillType()); 3060cb93a386Sopenharmony_ci scaledB.addPath(two, scale); 3061cb93a386Sopenharmony_ci scaledB.setFillType(two.getFillType()); 3062cb93a386Sopenharmony_ci scaledRgnA.setPath(scaledA, openClip); 3063cb93a386Sopenharmony_ci scaledRgnB.setPath(scaledB, openClip); 3064cb93a386Sopenharmony_ci scaledRgnOut.op(scaledRgnA, scaledRgnB, (SkRegion::Op) op); 3065cb93a386Sopenharmony_ci scaledRgnOut.getBoundaryPath(&scaledPathOut); 3066cb93a386Sopenharmony_ci SkBitmap bitmap; 3067cb93a386Sopenharmony_ci SkPath scaledOut; 3068cb93a386Sopenharmony_ci scaledOut.addPath(result, scale); 3069cb93a386Sopenharmony_ci scaledOut.setFillType(result.getFillType()); 3070cb93a386Sopenharmony_ci int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut, bitmap); 3071cb93a386Sopenharmony_ci const int MAX_ERRORS = 9; 3072cb93a386Sopenharmony_ci if (errors > MAX_ERRORS) { 3073cb93a386Sopenharmony_ci fprintf(stderr, "// Op did not expect errors=%d\n", errors); 3074cb93a386Sopenharmony_ci DumpOp(stderr, one, two, op, "opTest"); 3075cb93a386Sopenharmony_ci fflush(stderr); 3076cb93a386Sopenharmony_ci } 3077cb93a386Sopenharmony_ci} 3078cb93a386Sopenharmony_ci 3079cb93a386Sopenharmony_civoid SkPathOpsDebug::ReportSimplifyFail(const SkPath& path) { 3080cb93a386Sopenharmony_ci SkDebugf("// Simplify did not expect failure\n"); 3081cb93a386Sopenharmony_ci DumpSimplify(stderr, path, "simplifyTest"); 3082cb93a386Sopenharmony_ci fflush(stderr); 3083cb93a386Sopenharmony_ci} 3084cb93a386Sopenharmony_ci 3085cb93a386Sopenharmony_civoid SkPathOpsDebug::VerifySimplify(const SkPath& path, const SkPath& result) { 3086cb93a386Sopenharmony_ci SkPath pathOut, scaledPathOut; 3087cb93a386Sopenharmony_ci SkRegion rgnA, openClip, rgnOut; 3088cb93a386Sopenharmony_ci openClip.setRect(-16000, -16000, 16000, 16000); 3089cb93a386Sopenharmony_ci rgnA.setPath(path, openClip); 3090cb93a386Sopenharmony_ci rgnOut.getBoundaryPath(&pathOut); 3091cb93a386Sopenharmony_ci SkMatrix scale; 3092cb93a386Sopenharmony_ci debug_scale_matrix(path, nullptr, scale); 3093cb93a386Sopenharmony_ci SkRegion scaledRgnA; 3094cb93a386Sopenharmony_ci SkPath scaledA; 3095cb93a386Sopenharmony_ci scaledA.addPath(path, scale); 3096cb93a386Sopenharmony_ci scaledA.setFillType(path.getFillType()); 3097cb93a386Sopenharmony_ci scaledRgnA.setPath(scaledA, openClip); 3098cb93a386Sopenharmony_ci scaledRgnA.getBoundaryPath(&scaledPathOut); 3099cb93a386Sopenharmony_ci SkBitmap bitmap; 3100cb93a386Sopenharmony_ci SkPath scaledOut; 3101cb93a386Sopenharmony_ci scaledOut.addPath(result, scale); 3102cb93a386Sopenharmony_ci scaledOut.setFillType(result.getFillType()); 3103cb93a386Sopenharmony_ci int errors = debug_paths_draw_the_same(scaledPathOut, scaledOut, bitmap); 3104cb93a386Sopenharmony_ci const int MAX_ERRORS = 9; 3105cb93a386Sopenharmony_ci if (errors > MAX_ERRORS) { 3106cb93a386Sopenharmony_ci fprintf(stderr, "// Simplify did not expect errors=%d\n", errors); 3107cb93a386Sopenharmony_ci DumpSimplify(stderr, path, "simplifyTest"); 3108cb93a386Sopenharmony_ci fflush(stderr); 3109cb93a386Sopenharmony_ci } 3110cb93a386Sopenharmony_ci} 3111cb93a386Sopenharmony_ci 3112cb93a386Sopenharmony_ci#endif 3113cb93a386Sopenharmony_ci 3114cb93a386Sopenharmony_ci// global path dumps for msvs Visual Studio 17 to use from Immediate Window 3115cb93a386Sopenharmony_civoid Dump(const SkPath& path) { 3116cb93a386Sopenharmony_ci path.dump(); 3117cb93a386Sopenharmony_ci} 3118cb93a386Sopenharmony_ci 3119cb93a386Sopenharmony_civoid DumpHex(const SkPath& path) { 3120cb93a386Sopenharmony_ci path.dumpHex(); 3121cb93a386Sopenharmony_ci} 3122