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 16enum class SkOpPhase : char; 17class 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 234class SkPathOpsDebug { 235public: 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 403struct SkDQuad; 404 405// generates tools/path_sorter.htm and path_visualizer.htm compatible data 406void DumpQ(const SkDQuad& quad1, const SkDQuad& quad2, int testNo); 407void DumpT(const SkDQuad& quad, double t); 408 409#endif 410