• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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