1 /* 2 * Copyright 2013 Google Inc. 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 #ifndef SkPathOpsDebug_DEFINED 8 #define SkPathOpsDebug_DEFINED 9 10 #include "include/core/SkTypes.h" 11 #include "include/pathops/SkPathOps.h" 12 #include "include/private/base/SkTDArray.h" 13 14 #include <cstddef> 15 16 class SkOpAngle; 17 class SkOpCoincidence; 18 class SkOpContour; 19 class SkOpContourHead; 20 class SkOpPtT; 21 class SkOpSegment; 22 class SkOpSpan; 23 class SkOpSpanBase; 24 class SkPath; 25 struct SkDConic; 26 struct SkDCubic; 27 struct SkDLine; 28 struct SkDPoint; 29 struct SkDQuad; 30 31 // define this when running fuzz 32 // #define SK_BUILD_FOR_FUZZER 33 34 #ifdef SK_RELEASE 35 #define FORCE_RELEASE 1 36 #else 37 #define FORCE_RELEASE 1 // set force release to 1 for multiple thread -- no debugging 38 #endif 39 40 #define DEBUG_UNDER_DEVELOPMENT 0 41 42 #define ONE_OFF_DEBUG 0 43 #define ONE_OFF_DEBUG_MATHEMATICA 0 44 45 #if defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_ANDROID) 46 #define SK_RAND(seed) rand() 47 #else 48 #define SK_RAND(seed) rand_r(&seed) 49 #endif 50 51 #define WIND_AS_STRING(x) char x##Str[12]; \ 52 if (!SkPathOpsDebug::ValidWind(x)) strcpy(x##Str, "?"); \ 53 else snprintf(x##Str, sizeof(x##Str), "%d", x) 54 55 #if FORCE_RELEASE 56 57 #define DEBUG_ACTIVE_OP 0 58 #define DEBUG_ACTIVE_SPANS 0 59 #define DEBUG_ADD_INTERSECTING_TS 0 60 #define DEBUG_ADD_T 0 61 #define DEBUG_ALIGNMENT 0 62 #define DEBUG_ANGLE 0 63 #define DEBUG_ASSEMBLE 0 64 #define DEBUG_COINCIDENCE 0 65 #define DEBUG_COINCIDENCE_DUMP 0 // accumulate and dump which algorithms fired 66 #define DEBUG_COINCIDENCE_ORDER 0 // for well behaved curves, check if pairs match up in t-order 67 #define DEBUG_COINCIDENCE_VERBOSE 0 // usually whether the next function generates coincidence 68 #define DEBUG_CUBIC_BINARY_SEARCH 0 69 #define DEBUG_CUBIC_SPLIT 0 70 #define DEBUG_DUMP_SEGMENTS 0 71 #define DEBUG_DUMP_VERIFY 0 72 #define DEBUG_FLOW 0 73 #define DEBUG_LIMIT_WIND_SUM 0 74 #define DEBUG_MARK_DONE 0 75 #define DEBUG_PATH_CONSTRUCTION 0 76 #define DEBUG_PERP 0 77 #define DEBUG_SORT 0 78 #define DEBUG_T_SECT 0 79 #define DEBUG_T_SECT_DUMP 0 80 #define DEBUG_T_SECT_LOOP_COUNT 0 81 #define DEBUG_VALIDATE 0 82 #define DEBUG_WINDING 0 83 #define DEBUG_WINDING_AT_T 0 84 85 #else 86 87 #define DEBUG_ACTIVE_OP 1 88 #define DEBUG_ACTIVE_SPANS 1 89 #define DEBUG_ADD_INTERSECTING_TS 1 90 #define DEBUG_ADD_T 1 91 #define DEBUG_ALIGNMENT 0 92 #define DEBUG_ANGLE 1 93 #define DEBUG_ASSEMBLE 1 94 #define DEBUG_COINCIDENCE 1 95 #define DEBUG_COINCIDENCE_DUMP 1 96 #define DEBUG_COINCIDENCE_ORDER 1 // tight arc quads may generate out-of-order coincidence spans 97 #define DEBUG_COINCIDENCE_VERBOSE 1 98 #define DEBUG_CUBIC_BINARY_SEARCH 0 99 #define DEBUG_CUBIC_SPLIT 1 100 #define DEBUG_DUMP_VERIFY 1 101 #define DEBUG_DUMP_SEGMENTS 1 102 #define DEBUG_FLOW 1 103 #define DEBUG_LIMIT_WIND_SUM 15 104 #define DEBUG_MARK_DONE 1 105 #define DEBUG_PATH_CONSTRUCTION 1 106 #define DEBUG_PERP 1 107 #define DEBUG_SORT 1 108 #define DEBUG_T_SECT 0 // enabling may trigger validate asserts even though op does not fail 109 #define DEBUG_T_SECT_DUMP 0 // Use 1 normally. Use 2 to number segments, 3 for script output 110 #define DEBUG_T_SECT_LOOP_COUNT 0 111 #define DEBUG_VALIDATE 1 112 #define DEBUG_WINDING 1 113 #define DEBUG_WINDING_AT_T 1 114 115 #endif 116 117 #ifdef SK_RELEASE 118 #define SkDEBUGRELEASE(a, b) b 119 #define SkDEBUGPARAMS(...) 120 #else 121 #define SkDEBUGRELEASE(a, b) a 122 #define SkDEBUGPARAMS(...) , __VA_ARGS__ 123 #endif 124 125 #if DEBUG_VALIDATE == 0 126 #define PATH_OPS_DEBUG_VALIDATE_PARAMS(...) 127 #else 128 #define PATH_OPS_DEBUG_VALIDATE_PARAMS(...) , __VA_ARGS__ 129 #endif 130 131 #if DEBUG_T_SECT == 0 132 #define PATH_OPS_DEBUG_T_SECT_RELEASE(a, b) b 133 #define PATH_OPS_DEBUG_T_SECT_PARAMS(...) 134 #define PATH_OPS_DEBUG_T_SECT_CODE(...) 135 #else 136 #define PATH_OPS_DEBUG_T_SECT_RELEASE(a, b) a 137 #define PATH_OPS_DEBUG_T_SECT_PARAMS(...) , __VA_ARGS__ 138 #define PATH_OPS_DEBUG_T_SECT_CODE(...) __VA_ARGS__ 139 #endif 140 141 #if DEBUG_T_SECT_DUMP > 1 142 extern int gDumpTSectNum; 143 #endif 144 145 #if DEBUG_COINCIDENCE || DEBUG_COINCIDENCE_DUMP 146 #define DEBUG_COIN 1 147 #else 148 #define DEBUG_COIN 0 149 #endif 150 151 #if DEBUG_COIN 152 enum class SkOpPhase : char; 153 154 #define DEBUG_COIN_DECLARE_ONLY_PARAMS() \ 155 int lineNo, SkOpPhase phase, int iteration 156 #define DEBUG_COIN_DECLARE_PARAMS() \ 157 , DEBUG_COIN_DECLARE_ONLY_PARAMS() 158 #define DEBUG_COIN_ONLY_PARAMS() \ 159 __LINE__, SkOpPhase::kNoChange, 0 160 #define DEBUG_COIN_PARAMS() \ 161 , DEBUG_COIN_ONLY_PARAMS() 162 #define DEBUG_ITER_ONLY_PARAMS(iteration) \ 163 __LINE__, SkOpPhase::kNoChange, iteration 164 #define DEBUG_ITER_PARAMS(iteration) \ 165 , DEBUG_ITER_ONLY_PARAMS(iteration) 166 #define DEBUG_PHASE_ONLY_PARAMS(phase) \ 167 __LINE__, SkOpPhase::phase, 0 168 #define DEBUG_PHASE_PARAMS(phase) \ 169 , DEBUG_PHASE_ONLY_PARAMS(phase) 170 #define DEBUG_SET_PHASE() \ 171 this->globalState()->debugSetPhase(__func__, lineNo, phase, iteration) 172 #define DEBUG_STATIC_SET_PHASE(obj) \ 173 obj->globalState()->debugSetPhase(__func__, lineNo, phase, iteration) 174 #elif DEBUG_VALIDATE 175 #define DEBUG_COIN_DECLARE_ONLY_PARAMS() \ 176 SkOpPhase phase 177 #define DEBUG_COIN_DECLARE_PARAMS() \ 178 , DEBUG_COIN_DECLARE_ONLY_PARAMS() 179 #define DEBUG_COIN_ONLY_PARAMS() \ 180 SkOpPhase::kNoChange 181 #define DEBUG_COIN_PARAMS() \ 182 , DEBUG_COIN_ONLY_PARAMS() 183 #define DEBUG_ITER_ONLY_PARAMS(iteration) \ 184 SkOpPhase::kNoChange 185 #define DEBUG_ITER_PARAMS(iteration) \ 186 , DEBUG_ITER_ONLY_PARAMS(iteration) 187 #define DEBUG_PHASE_ONLY_PARAMS(phase) \ 188 SkOpPhase::phase 189 #define DEBUG_PHASE_PARAMS(phase) \ 190 , DEBUG_PHASE_ONLY_PARAMS(phase) 191 #define DEBUG_SET_PHASE() \ 192 this->globalState()->debugSetPhase(phase) 193 #define DEBUG_STATIC_SET_PHASE(obj) \ 194 obj->globalState()->debugSetPhase(phase) 195 #else 196 #define DEBUG_COIN_DECLARE_ONLY_PARAMS() 197 #define DEBUG_COIN_DECLARE_PARAMS() 198 #define DEBUG_COIN_ONLY_PARAMS() 199 #define DEBUG_COIN_PARAMS() 200 #define DEBUG_ITER_ONLY_PARAMS(iteration) 201 #define DEBUG_ITER_PARAMS(iteration) 202 #define DEBUG_PHASE_ONLY_PARAMS(phase) 203 #define DEBUG_PHASE_PARAMS(phase) 204 #define DEBUG_SET_PHASE() 205 #define DEBUG_STATIC_SET_PHASE(obj) 206 #endif 207 208 #define CUBIC_DEBUG_STR "{{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}" 209 #define CONIC_DEBUG_STR "{{{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}, %1.9g}" 210 #define QUAD_DEBUG_STR "{{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}" 211 #define LINE_DEBUG_STR "{{{%1.9g,%1.9g}, {%1.9g,%1.9g}}}" 212 #define PT_DEBUG_STR "{{%1.9g,%1.9g}}" 213 214 #define T_DEBUG_STR(t, n) #t "[" #n "]=%1.9g" 215 #define TX_DEBUG_STR(t) #t "[%d]=%1.9g" 216 #define CUBIC_DEBUG_DATA(c) c[0].fX, c[0].fY, c[1].fX, c[1].fY, c[2].fX, c[2].fY, c[3].fX, c[3].fY 217 #define CONIC_DEBUG_DATA(c, w) c[0].fX, c[0].fY, c[1].fX, c[1].fY, c[2].fX, c[2].fY, w 218 #define QUAD_DEBUG_DATA(q) q[0].fX, q[0].fY, q[1].fX, q[1].fY, q[2].fX, q[2].fY 219 #define LINE_DEBUG_DATA(l) l[0].fX, l[0].fY, l[1].fX, l[1].fY 220 #define PT_DEBUG_DATA(i, n) i.pt(n).asSkPoint().fX, i.pt(n).asSkPoint().fY 221 222 #ifndef DEBUG_TEST 223 #define DEBUG_TEST 0 224 #endif 225 226 // Tests with extreme numbers may fail, but all other tests should never fail. 227 #define FAIL_IF(cond) \ 228 do { bool fail = (cond); SkOPASSERT(!fail); if (fail) return false; } while (false) 229 230 #define FAIL_WITH_NULL_IF(cond) \ 231 do { bool fail = (cond); SkOPASSERT(!fail); if (fail) return nullptr; } while (false) 232 233 class SkPathOpsDebug { 234 public: 235 #if DEBUG_COIN 236 struct GlitchLog; 237 238 enum GlitchType { 239 kUninitialized_Glitch, 240 kAddCorruptCoin_Glitch, 241 kAddExpandedCoin_Glitch, 242 kAddExpandedFail_Glitch, 243 kAddIfCollapsed_Glitch, 244 kAddIfMissingCoin_Glitch, 245 kAddMissingCoin_Glitch, 246 kAddMissingExtend_Glitch, 247 kAddOrOverlap_Glitch, 248 kCollapsedCoin_Glitch, 249 kCollapsedDone_Glitch, 250 kCollapsedOppValue_Glitch, 251 kCollapsedSpan_Glitch, 252 kCollapsedWindValue_Glitch, 253 kCorrectEnd_Glitch, 254 kDeletedCoin_Glitch, 255 kExpandCoin_Glitch, 256 kFail_Glitch, 257 kMarkCoinEnd_Glitch, 258 kMarkCoinInsert_Glitch, 259 kMarkCoinMissing_Glitch, 260 kMarkCoinStart_Glitch, 261 kMergeMatches_Glitch, 262 kMissingCoin_Glitch, 263 kMissingDone_Glitch, 264 kMissingIntersection_Glitch, 265 kMoveMultiple_Glitch, 266 kMoveNearbyClearAll_Glitch, 267 kMoveNearbyClearAll2_Glitch, 268 kMoveNearbyMerge_Glitch, 269 kMoveNearbyMergeFinal_Glitch, 270 kMoveNearbyRelease_Glitch, 271 kMoveNearbyReleaseFinal_Glitch, 272 kReleasedSpan_Glitch, 273 kReturnFalse_Glitch, 274 kUnaligned_Glitch, 275 kUnalignedHead_Glitch, 276 kUnalignedTail_Glitch, 277 }; 278 279 struct CoinDictEntry { 280 int fIteration; 281 int fLineNumber; 282 GlitchType fGlitchType; 283 const char* fFunctionName; 284 }; 285 286 struct CoinDict { 287 void add(const CoinDictEntry& key); 288 void add(const CoinDict& dict); 289 void dump(const char* str, bool visitCheck) const; 290 SkTDArray<CoinDictEntry> fDict; 291 }; 292 293 static CoinDict gCoinSumChangedDict; 294 static CoinDict gCoinSumVisitedDict; 295 static CoinDict gCoinVistedDict; 296 #endif 297 298 #if defined(SK_DEBUG) || !FORCE_RELEASE 299 static int gContourID; 300 static int gSegmentID; 301 #endif 302 303 #if DEBUG_SORT 304 static int gSortCountDefault; 305 static int gSortCount; 306 #endif 307 308 #if DEBUG_ACTIVE_OP 309 static const char* kPathOpStr[]; 310 #endif 311 static bool gRunFail; 312 static bool gVeryVerbose; 313 314 #if DEBUG_ACTIVE_SPANS 315 static SkString gActiveSpans; 316 #endif 317 #if DEBUG_DUMP_VERIFY 318 static bool gDumpOp; 319 static bool gVerifyOp; 320 #endif 321 322 static const char* OpStr(SkPathOp ); 323 static void MathematicaIze(char* str, size_t bufferSize); 324 static bool ValidWind(int winding); 325 static void WindingPrintf(int winding); 326 327 static void ShowActiveSpans(SkOpContourHead* contourList); 328 static void ShowOnePath(const SkPath& path, const char* name, bool includeDeclaration); 329 static void ShowPath(const SkPath& one, const SkPath& two, SkPathOp op, const char* name); 330 331 static bool ChaseContains(const SkTDArray<SkOpSpanBase*>& , const SkOpSpanBase* ); 332 333 static void CheckHealth(class SkOpContourHead* contourList); 334 335 #if DEBUG_COIN 336 static void DumpCoinDict(); 337 static void DumpGlitchType(GlitchType ); 338 #endif 339 340 }; 341 342 // Visual Studio 2017 does not permit calling member functions from the Immediate Window. 343 // Global functions work fine, however. Use globals rather than static members inside a class. 344 const SkOpAngle* AngleAngle(const SkOpAngle*, int id); 345 SkOpContour* AngleContour(SkOpAngle*, int id); 346 const SkOpPtT* AnglePtT(const SkOpAngle*, int id); 347 const SkOpSegment* AngleSegment(const SkOpAngle*, int id); 348 const SkOpSpanBase* AngleSpan(const SkOpAngle*, int id); 349 350 const SkOpAngle* ContourAngle(SkOpContour*, int id); 351 SkOpContour* ContourContour(SkOpContour*, int id); 352 const SkOpPtT* ContourPtT(SkOpContour*, int id); 353 const SkOpSegment* ContourSegment(SkOpContour*, int id); 354 const SkOpSpanBase* ContourSpan(SkOpContour*, int id); 355 356 const SkOpAngle* CoincidenceAngle(SkOpCoincidence*, int id); 357 SkOpContour* CoincidenceContour(SkOpCoincidence*, int id); 358 const SkOpPtT* CoincidencePtT(SkOpCoincidence*, int id); 359 const SkOpSegment* CoincidenceSegment(SkOpCoincidence*, int id); 360 const SkOpSpanBase* CoincidenceSpan(SkOpCoincidence*, int id); 361 362 const SkOpAngle* PtTAngle(const SkOpPtT*, int id); 363 SkOpContour* PtTContour(SkOpPtT*, int id); 364 const SkOpPtT* PtTPtT(const SkOpPtT*, int id); 365 const SkOpSegment* PtTSegment(const SkOpPtT*, int id); 366 const SkOpSpanBase* PtTSpan(const SkOpPtT*, int id); 367 368 const SkOpAngle* SegmentAngle(const SkOpSegment*, int id); 369 SkOpContour* SegmentContour(SkOpSegment*, int id); 370 const SkOpPtT* SegmentPtT(const SkOpSegment*, int id); 371 const SkOpSegment* SegmentSegment(const SkOpSegment*, int id); 372 const SkOpSpanBase* SegmentSpan(const SkOpSegment*, int id); 373 374 const SkOpAngle* SpanAngle(const SkOpSpanBase*, int id); 375 SkOpContour* SpanContour(SkOpSpanBase*, int id); 376 const SkOpPtT* SpanPtT(const SkOpSpanBase*, int id); 377 const SkOpSegment* SpanSegment(const SkOpSpanBase*, int id); 378 const SkOpSpanBase* SpanSpan(const SkOpSpanBase*, int id); 379 380 #if DEBUG_DUMP_VERIFY 381 void DumpOp(const SkPath& one, const SkPath& two, SkPathOp op, 382 const char* testName); 383 void DumpOp(FILE* file, const SkPath& one, const SkPath& two, SkPathOp op, 384 const char* testName); 385 void DumpSimplify(const SkPath& path, const char* testName); 386 void DumpSimplify(FILE* file, const SkPath& path, const char* testName); 387 void ReportOpFail(const SkPath& one, const SkPath& two, SkPathOp op); 388 void ReportSimplifyFail(const SkPath& path); 389 void VerifyOp(const SkPath& one, const SkPath& two, SkPathOp op, 390 const SkPath& result); 391 void VerifySimplify(const SkPath& path, const SkPath& result); 392 #endif 393 394 // global path dumps for msvs Visual Studio 17 to use from Immediate Window 395 void Dump(const SkOpContour& ); 396 void DumpAll(const SkOpContour& ); 397 void DumpAngles(const SkOpContour& ); 398 void DumpContours(const SkOpContour& ); 399 void DumpContoursAll(const SkOpContour& ); 400 void DumpContoursAngles(const SkOpContour& ); 401 void DumpContoursPts(const SkOpContour& ); 402 void DumpContoursPt(const SkOpContour& , int segmentID); 403 void DumpContoursSegment(const SkOpContour& , int segmentID); 404 void DumpContoursSpan(const SkOpContour& , int segmentID); 405 void DumpContoursSpans(const SkOpContour& ); 406 void DumpPt(const SkOpContour& , int ); 407 void DumpPts(const SkOpContour& , const char* prefix = "seg"); 408 void DumpSegment(const SkOpContour& , int ); 409 void DumpSegments(const SkOpContour& , const char* prefix = "seg", SkPathOp op = (SkPathOp) -1); 410 void DumpSpan(const SkOpContour& , int ); 411 void DumpSpans(const SkOpContour& ); 412 413 void Dump(const SkOpSegment& ); 414 void DumpAll(const SkOpSegment& ); 415 void DumpAngles(const SkOpSegment& ); 416 void DumpCoin(const SkOpSegment& ); 417 void DumpPts(const SkOpSegment& , const char* prefix = "seg"); 418 419 void Dump(const SkOpPtT& ); 420 void DumpAll(const SkOpPtT& ); 421 422 void Dump(const SkOpSpanBase& ); 423 void DumpCoin(const SkOpSpanBase& ); 424 void DumpAll(const SkOpSpanBase& ); 425 426 void DumpCoin(const SkOpSpan& ); 427 bool DumpSpan(const SkOpSpan& ); 428 429 void Dump(const SkDConic& ); 430 void DumpID(const SkDConic& , int id); 431 432 void Dump(const SkDCubic& ); 433 void DumpID(const SkDCubic& , int id); 434 435 void Dump(const SkDLine& ); 436 void DumpID(const SkDLine& , int id); 437 438 void Dump(const SkDQuad& ); 439 void DumpID(const SkDQuad& , int id); 440 441 void Dump(const SkDPoint& ); 442 443 void Dump(const SkOpAngle& ); 444 445 // generates tools/path_sorter.htm and path_visualizer.htm compatible data 446 void DumpQ(const SkDQuad& quad1, const SkDQuad& quad2, int testNo); 447 void DumpT(const SkDQuad& quad, double t); 448 449 // global path dumps for msvs Visual Studio 17 to use from Immediate Window 450 void Dump(const SkPath& path); 451 void DumpHex(const SkPath& path); 452 453 #endif 454