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 "SkPathOps.h" 11 #include "SkTypes.h" 12 13 #include <stdlib.h> 14 #include <stdio.h> 15 16 enum class SkOpPhase : char; 17 class SkOpContourHead; 18 19 #ifdef SK_RELEASE 20 #define FORCE_RELEASE 1 21 #else 22 #define FORCE_RELEASE 1 // set force release to 1 for multiple thread -- no debugging 23 #endif 24 25 #define DEBUG_UNDER_DEVELOPMENT 0 26 27 #define ONE_OFF_DEBUG 0 28 #define ONE_OFF_DEBUG_MATHEMATICA 0 29 30 #if defined(SK_BUILD_FOR_WIN) || defined(SK_BUILD_FOR_ANDROID) 31 #define SK_RAND(seed) rand() 32 #else 33 #define SK_RAND(seed) rand_r(&seed) 34 #endif 35 #ifdef SK_BUILD_FOR_WIN 36 #define SK_SNPRINTF _snprintf 37 #else 38 #define SK_SNPRINTF snprintf 39 #endif 40 41 #define WIND_AS_STRING(x) char x##Str[12]; \ 42 if (!SkPathOpsDebug::ValidWind(x)) strcpy(x##Str, "?"); \ 43 else SK_SNPRINTF(x##Str, sizeof(x##Str), "%d", x) 44 45 #if FORCE_RELEASE 46 47 #define DEBUG_ACTIVE_OP 0 48 #define DEBUG_ACTIVE_SPANS 0 49 #define DEBUG_ADD_INTERSECTING_TS 0 50 #define DEBUG_ADD_T 0 51 #define DEBUG_ALIGNMENT 0 52 #define DEBUG_ANGLE 0 53 #define DEBUG_ASSEMBLE 0 54 #define DEBUG_COINCIDENCE 0 // sanity checking 55 #define DEBUG_COINCIDENCE_DUMP 0 // accumulate and dump which algorithms fired 56 #define DEBUG_COINCIDENCE_ORDER 0 // for well behaved curves, check if pairs match up in t-order 57 #define DEBUG_COINCIDENCE_VERBOSE 0 // usually whether the next function generates coincidence 58 #define DEBUG_CUBIC_BINARY_SEARCH 0 59 #define DEBUG_CUBIC_SPLIT 0 60 #define DEBUG_DUMP_SEGMENTS 0 61 #define DEBUG_DUMP_VERIFY 0 62 #define DEBUG_FLOW 0 63 #define DEBUG_LIMIT_WIND_SUM 0 64 #define DEBUG_MARK_DONE 0 65 #define DEBUG_PATH_CONSTRUCTION 0 66 #define DEBUG_PERP 0 67 #define DEBUG_SHOW_TEST_NAME 0 68 #define DEBUG_SORT 0 69 #define DEBUG_T_SECT 0 70 #define DEBUG_T_SECT_DUMP 0 71 #define DEBUG_T_SECT_LOOP_COUNT 0 72 #define DEBUG_VALIDATE 0 73 #define DEBUG_WINDING 0 74 #define DEBUG_WINDING_AT_T 0 75 76 #else 77 78 #define DEBUG_ACTIVE_OP 1 79 #define DEBUG_ACTIVE_SPANS 1 80 #define DEBUG_ADD_INTERSECTING_TS 1 81 #define DEBUG_ADD_T 1 82 #define DEBUG_ALIGNMENT 0 83 #define DEBUG_ANGLE 1 84 #define DEBUG_ASSEMBLE 1 85 #define DEBUG_COINCIDENCE 1 86 #define DEBUG_COINCIDENCE_DUMP 0 87 #define DEBUG_COINCIDENCE_ORDER 0 // tight arc quads may generate out-of-order coincdence spans 88 #define DEBUG_COINCIDENCE_VERBOSE 1 89 #define DEBUG_CUBIC_BINARY_SEARCH 0 90 #define DEBUG_CUBIC_SPLIT 1 91 #define DEBUG_DUMP_VERIFY 0 92 #define DEBUG_DUMP_SEGMENTS 1 93 #define DEBUG_FLOW 1 94 #define DEBUG_LIMIT_WIND_SUM 15 95 #define DEBUG_MARK_DONE 1 96 #define DEBUG_PATH_CONSTRUCTION 1 97 #define DEBUG_PERP 1 98 #define DEBUG_SHOW_TEST_NAME 1 99 #define DEBUG_SORT 1 100 #define DEBUG_T_SECT 0 101 #define DEBUG_T_SECT_DUMP 0 // Use 1 normally. Use 2 to number segments, 3 for script output 102 #define DEBUG_T_SECT_LOOP_COUNT 0 103 #define DEBUG_VALIDATE 1 104 #define DEBUG_WINDING 1 105 #define DEBUG_WINDING_AT_T 1 106 107 #endif 108 109 #ifdef SK_RELEASE 110 #define SkDEBUGRELEASE(a, b) b 111 #define SkDEBUGPARAMS(...) 112 #else 113 #define SkDEBUGRELEASE(a, b) a 114 #define SkDEBUGPARAMS(...) , __VA_ARGS__ 115 #endif 116 117 #if DEBUG_VALIDATE == 0 118 #define PATH_OPS_DEBUG_VALIDATE_PARAMS(...) 119 #else 120 #define PATH_OPS_DEBUG_VALIDATE_PARAMS(...) , __VA_ARGS__ 121 #endif 122 123 #if DEBUG_T_SECT == 0 124 #define PATH_OPS_DEBUG_T_SECT_RELEASE(a, b) b 125 #define PATH_OPS_DEBUG_T_SECT_PARAMS(...) 126 #define PATH_OPS_DEBUG_T_SECT_CODE(...) 127 #else 128 #define PATH_OPS_DEBUG_T_SECT_RELEASE(a, b) a 129 #define PATH_OPS_DEBUG_T_SECT_PARAMS(...) , __VA_ARGS__ 130 #define PATH_OPS_DEBUG_T_SECT_CODE(...) __VA_ARGS__ 131 #endif 132 133 #if DEBUG_T_SECT_DUMP > 1 134 extern int gDumpTSectNum; 135 #endif 136 137 #if DEBUG_COINCIDENCE || DEBUG_COINCIDENCE_DUMP 138 #define DEBUG_COIN 1 139 #else 140 #define DEBUG_COIN 0 141 #endif 142 143 #if DEBUG_COIN 144 #define DEBUG_COIN_DECLARE_ONLY_PARAMS() \ 145 int lineNo, SkOpPhase phase, int iteration 146 #define DEBUG_COIN_DECLARE_PARAMS() \ 147 , DEBUG_COIN_DECLARE_ONLY_PARAMS() 148 #define DEBUG_COIN_ONLY_PARAMS() \ 149 __LINE__, SkOpPhase::kNoChange, 0 150 #define DEBUG_COIN_PARAMS() \ 151 , DEBUG_COIN_ONLY_PARAMS() 152 #define DEBUG_ITER_ONLY_PARAMS(iteration) \ 153 __LINE__, SkOpPhase::kNoChange, iteration 154 #define DEBUG_ITER_PARAMS(iteration) \ 155 , DEBUG_ITER_ONLY_PARAMS(iteration) 156 #define DEBUG_PHASE_ONLY_PARAMS(phase) \ 157 __LINE__, SkOpPhase::phase, 0 158 #define DEBUG_PHASE_PARAMS(phase) \ 159 , DEBUG_PHASE_ONLY_PARAMS(phase) 160 #define DEBUG_SET_PHASE() \ 161 this->globalState()->debugSetPhase(__func__, lineNo, phase, iteration) 162 #define DEBUG_STATIC_SET_PHASE(obj) \ 163 obj->globalState()->debugSetPhase(__func__, lineNo, phase, iteration) 164 #elif DEBUG_VALIDATE 165 #define DEBUG_COIN_DECLARE_ONLY_PARAMS() \ 166 SkOpPhase phase 167 #define DEBUG_COIN_DECLARE_PARAMS() \ 168 , DEBUG_COIN_DECLARE_ONLY_PARAMS() 169 #define DEBUG_COIN_ONLY_PARAMS() \ 170 SkOpPhase::kNoChange 171 #define DEBUG_COIN_PARAMS() \ 172 , DEBUG_COIN_ONLY_PARAMS() 173 #define DEBUG_ITER_ONLY_PARAMS(iteration) \ 174 SkOpPhase::kNoChange 175 #define DEBUG_ITER_PARAMS(iteration) \ 176 , DEBUG_ITER_ONLY_PARAMS(iteration) 177 #define DEBUG_PHASE_ONLY_PARAMS(phase) \ 178 SkOpPhase::phase 179 #define DEBUG_PHASE_PARAMS(phase) \ 180 , DEBUG_PHASE_ONLY_PARAMS(phase) 181 #define DEBUG_SET_PHASE() \ 182 this->globalState()->debugSetPhase(phase) 183 #define DEBUG_STATIC_SET_PHASE(obj) \ 184 obj->globalState()->debugSetPhase(phase) 185 #else 186 #define DEBUG_COIN_DECLARE_ONLY_PARAMS() 187 #define DEBUG_COIN_DECLARE_PARAMS() 188 #define DEBUG_COIN_ONLY_PARAMS() 189 #define DEBUG_COIN_PARAMS() 190 #define DEBUG_ITER_ONLY_PARAMS(iteration) 191 #define DEBUG_ITER_PARAMS(iteration) 192 #define DEBUG_PHASE_ONLY_PARAMS(phase) 193 #define DEBUG_PHASE_PARAMS(phase) 194 #define DEBUG_SET_PHASE() 195 #define DEBUG_STATIC_SET_PHASE(obj) 196 #endif 197 198 #define CUBIC_DEBUG_STR "{{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}" 199 #define CONIC_DEBUG_STR "{{{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}, %1.9g}" 200 #define QUAD_DEBUG_STR "{{{%1.9g,%1.9g}, {%1.9g,%1.9g}, {%1.9g,%1.9g}}}" 201 #define LINE_DEBUG_STR "{{{%1.9g,%1.9g}, {%1.9g,%1.9g}}}" 202 #define PT_DEBUG_STR "{{%1.9g,%1.9g}}" 203 204 #define T_DEBUG_STR(t, n) #t "[" #n "]=%1.9g" 205 #define TX_DEBUG_STR(t) #t "[%d]=%1.9g" 206 #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 207 #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 208 #define QUAD_DEBUG_DATA(q) q[0].fX, q[0].fY, q[1].fX, q[1].fY, q[2].fX, q[2].fY 209 #define LINE_DEBUG_DATA(l) l[0].fX, l[0].fY, l[1].fX, l[1].fY 210 #define PT_DEBUG_DATA(i, n) i.pt(n).asSkPoint().fX, i.pt(n).asSkPoint().fY 211 212 #ifndef DEBUG_TEST 213 #define DEBUG_TEST 0 214 #endif 215 216 #if DEBUG_SHOW_TEST_NAME 217 #include "SkTLS.h" 218 #endif 219 220 // Tests with extreme numbers may fail, but all other tests should never fail. 221 #define FAIL_IF(cond) \ 222 do { bool fail = (cond); SkOPASSERT(!fail); if (fail) return false; } while (false) 223 224 #define FAIL_WITH_NULL_IF(cond) \ 225 do { bool fail = (cond); SkOPASSERT(!fail); if (fail) return nullptr; } while (false) 226 227 // Some functions serve two masters: one allows the function to fail, the other expects success 228 // always. If abort is true, tests with normal numbers may not fail and assert if they do so. 229 // If abort is false, both normal and extreme numbers may return false without asserting. 230 #define RETURN_FALSE_IF(abort, cond) \ 231 do { bool fail = (cond); SkOPASSERT(!(abort) || !fail); if (fail) return false; \ 232 } while (false) 233 234 class SkPathOpsDebug { 235 public: 236 static const char* kLVerbStr[]; 237 238 #if DEBUG_COIN 239 struct GlitchLog; 240 241 enum GlitchType { 242 kUninitialized_Glitch, 243 kAddCorruptCoin_Glitch, 244 kAddExpandedCoin_Glitch, 245 kAddExpandedFail_Glitch, 246 kAddIfCollapsed_Glitch, 247 kAddIfMissingCoin_Glitch, 248 kAddMissingCoin_Glitch, 249 kAddMissingExtend_Glitch, 250 kAddOrOverlap_Glitch, 251 kCollapsedCoin_Glitch, 252 kCollapsedDone_Glitch, 253 kCollapsedOppValue_Glitch, 254 kCollapsedSpan_Glitch, 255 kCollapsedWindValue_Glitch, 256 kCorrectEnd_Glitch, 257 kDeletedCoin_Glitch, 258 kExpandCoin_Glitch, 259 kFail_Glitch, 260 kMarkCoinEnd_Glitch, 261 kMarkCoinInsert_Glitch, 262 kMarkCoinMissing_Glitch, 263 kMarkCoinStart_Glitch, 264 kMergeMatches_Glitch, 265 kMissingCoin_Glitch, 266 kMissingDone_Glitch, 267 kMissingIntersection_Glitch, 268 kMoveMultiple_Glitch, 269 kMoveNearbyClearAll_Glitch, 270 kMoveNearbyClearAll2_Glitch, 271 kMoveNearbyMerge_Glitch, 272 kMoveNearbyMergeFinal_Glitch, 273 kMoveNearbyRelease_Glitch, 274 kMoveNearbyReleaseFinal_Glitch, 275 kReleasedSpan_Glitch, 276 kReturnFalse_Glitch, 277 kUnaligned_Glitch, 278 kUnalignedHead_Glitch, 279 kUnalignedTail_Glitch, 280 }; 281 282 struct CoinDictEntry { 283 int fIteration; 284 int fLineNumber; 285 GlitchType fGlitchType; 286 const char* fFunctionName; 287 }; 288 289 struct CoinDict { 290 void add(const CoinDictEntry& key); 291 void add(const CoinDict& dict); 292 void dump(const char* str, bool visitCheck) const; 293 SkTDArray<CoinDictEntry> fDict; 294 }; 295 296 static CoinDict gCoinSumChangedDict; 297 static CoinDict gCoinSumVisitedDict; 298 static CoinDict gCoinVistedDict; 299 #endif 300 301 #if defined(SK_DEBUG) || !FORCE_RELEASE 302 static int gContourID; 303 static int gSegmentID; 304 #endif 305 306 #if DEBUG_SORT 307 static int gSortCountDefault; 308 static int gSortCount; 309 #endif 310 311 #if DEBUG_ACTIVE_OP 312 static const char* kPathOpStr[]; 313 #endif 314 315 static void MathematicaIze(char* str, size_t bufferSize); 316 static bool ValidWind(int winding); 317 static void WindingPrintf(int winding); 318 319 #if DEBUG_SHOW_TEST_NAME 320 static void* CreateNameStr(); 321 static void DeleteNameStr(void* v); 322 #define DEBUG_FILENAME_STRING_LENGTH 64 323 #define DEBUG_FILENAME_STRING (reinterpret_cast<char* >(SkTLS::Get(SkPathOpsDebug::CreateNameStr, \ 324 SkPathOpsDebug::DeleteNameStr))) 325 static void BumpTestName(char* ); 326 #endif 327 static const char* OpStr(SkPathOp ); 328 static void ShowActiveSpans(SkOpContourHead* contourList); 329 static void ShowOnePath(const SkPath& path, const char* name, bool includeDeclaration); 330 static void ShowPath(const SkPath& one, const SkPath& two, SkPathOp op, const char* name); 331 332 static bool ChaseContains(const SkTDArray<class SkOpSpanBase*>& , const class SkOpSpanBase* ); 333 334 static void CheckHealth(class SkOpContourHead* contourList); 335 336 static const class SkOpAngle* DebugAngleAngle(const class SkOpAngle*, int id); 337 static class SkOpContour* DebugAngleContour(class SkOpAngle*, int id); 338 static const class SkOpPtT* DebugAnglePtT(const class SkOpAngle*, int id); 339 static const class SkOpSegment* DebugAngleSegment(const class SkOpAngle*, int id); 340 static const class SkOpSpanBase* DebugAngleSpan(const class SkOpAngle*, int id); 341 342 static const class SkOpAngle* DebugContourAngle(class SkOpContour*, int id); 343 static class SkOpContour* DebugContourContour(class SkOpContour*, int id); 344 static const class SkOpPtT* DebugContourPtT(class SkOpContour*, int id); 345 static const class SkOpSegment* DebugContourSegment(class SkOpContour*, int id); 346 static const class SkOpSpanBase* DebugContourSpan(class SkOpContour*, int id); 347 348 static const class SkOpAngle* DebugCoincidenceAngle(class SkOpCoincidence*, int id); 349 static class SkOpContour* DebugCoincidenceContour(class SkOpCoincidence*, int id); 350 static const class SkOpPtT* DebugCoincidencePtT(class SkOpCoincidence*, int id); 351 static const class SkOpSegment* DebugCoincidenceSegment(class SkOpCoincidence*, int id); 352 static const class SkOpSpanBase* DebugCoincidenceSpan(class SkOpCoincidence*, int id); 353 354 static const class SkOpAngle* DebugPtTAngle(const class SkOpPtT*, int id); 355 static class SkOpContour* DebugPtTContour(class SkOpPtT*, int id); 356 static const class SkOpPtT* DebugPtTPtT(const class SkOpPtT*, int id); 357 static const class SkOpSegment* DebugPtTSegment(const class SkOpPtT*, int id); 358 static const class SkOpSpanBase* DebugPtTSpan(const class SkOpPtT*, int id); 359 360 static const class SkOpAngle* DebugSegmentAngle(const class SkOpSegment*, int id); 361 static class SkOpContour* DebugSegmentContour(class SkOpSegment*, int id); 362 static const class SkOpPtT* DebugSegmentPtT(const class SkOpSegment*, int id); 363 static const class SkOpSegment* DebugSegmentSegment(const class SkOpSegment*, int id); 364 static const class SkOpSpanBase* DebugSegmentSpan(const class SkOpSegment*, int id); 365 366 static const class SkOpAngle* DebugSpanAngle(const class SkOpSpanBase*, int id); 367 static class SkOpContour* DebugSpanContour(class SkOpSpanBase*, int id); 368 static const class SkOpPtT* DebugSpanPtT(const class SkOpSpanBase*, int id); 369 static const class SkOpSegment* DebugSpanSegment(const class SkOpSpanBase*, int id); 370 static const class SkOpSpanBase* DebugSpanSpan(const class SkOpSpanBase*, int id); 371 372 #if DEBUG_COIN 373 static void DumpCoinDict(); 374 static void DumpGlitchType(GlitchType ); 375 #endif 376 377 static bool gRunFail; 378 static bool gVeryVerbose; 379 380 #if DEBUG_DUMP_VERIFY 381 static bool gDumpOp; 382 static bool gVerifyOp; 383 384 static void DumpOp(const SkPath& one, const SkPath& two, SkPathOp op, 385 const char* testName); 386 static void DumpOp(FILE* file, const SkPath& one, const SkPath& two, SkPathOp op, 387 const char* testName); 388 static void DumpSimplify(const SkPath& path, const char* testName); 389 static void DumpSimplify(FILE* file, const SkPath& path, const char* testName); 390 static void ReportOpFail(const SkPath& one, const SkPath& two, SkPathOp op); 391 static void ReportSimplifyFail(const SkPath& path); 392 static void VerifyOp(const SkPath& one, const SkPath& two, SkPathOp op, 393 const SkPath& result); 394 static void VerifySimplify(const SkPath& path, const SkPath& result); 395 #endif 396 397 #if DEBUG_ACTIVE_SPANS 398 static SkString gActiveSpans; 399 #endif 400 401 }; 402 403 struct SkDQuad; 404 405 // generates tools/path_sorter.htm and path_visualizer.htm compatible data 406 void DumpQ(const SkDQuad& quad1, const SkDQuad& quad2, int testNo); 407 void DumpT(const SkDQuad& quad, double t); 408 409 #endif 410