Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(16)

Side by Side Diff: src/pathops/SkPathOpsDebug.cpp

Issue 2128633003: pathops coincidence and security rewrite (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: require resulting t to be between 0 and 1 Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 /* 1 /*
2 * Copyright 2013 Google Inc. 2 * Copyright 2013 Google Inc.
3 * 3 *
4 * Use of this source code is governed by a BSD-style license that can be 4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file. 5 * found in the LICENSE file.
6 */ 6 */
7 7
8 #include "SkMutex.h" 8 #include "SkMutex.h"
9 #include "SkOpCoincidence.h" 9 #include "SkOpCoincidence.h"
10 #include "SkOpContour.h" 10 #include "SkOpContour.h"
11 #include "SkPath.h" 11 #include "SkPath.h"
12 #include "SkPathOpsDebug.h" 12 #include "SkPathOpsDebug.h"
13 #include "SkString.h" 13 #include "SkString.h"
14 14
15 struct SkCoincidentSpans; 15 class SkCoincidentSpans;
16 16
17 #if DEBUG_VALIDATE 17 #if DEBUG_VALIDATE
18 extern bool FLAGS_runFail; 18 extern bool FLAGS_runFail;
19 #endif 19 #endif
20 20
21 #if DEBUG_SORT 21 #if DEBUG_SORT
22 int SkPathOpsDebug::gSortCountDefault = SK_MaxS32; 22 int SkPathOpsDebug::gSortCountDefault = SK_MaxS32;
23 int SkPathOpsDebug::gSortCount; 23 int SkPathOpsDebug::gSortCount;
24 #endif 24 #endif
25 25
(...skipping 13 matching lines...) Expand all
39 for (int index = 0; index < chaseArray.count(); ++index) { 39 for (int index = 0; index < chaseArray.count(); ++index) {
40 const SkOpSpanBase* entry = chaseArray[index]; 40 const SkOpSpanBase* entry = chaseArray[index];
41 if (entry == span) { 41 if (entry == span) {
42 return true; 42 return true;
43 } 43 }
44 } 44 }
45 return false; 45 return false;
46 } 46 }
47 #endif 47 #endif
48 48
49 #if DEBUG_COINCIDENCE 49 #if DEBUG_COINCIDENCE_VERBOSE
50 enum GlitchType { 50 enum GlitchType {
51 kAddCorruptCoin_Glitch, 51 kAddCorruptCoin_Glitch,
52 kAddExpandedCoin_Glitch, 52 kAddExpandedCoin_Glitch,
53 kAddExpandedFail_Glitch,
54 kAddIfMissingCoin_Glitch,
53 kAddMissingCoin_Glitch, 55 kAddMissingCoin_Glitch,
56 kAddMissingExtend_Glitch,
57 kAddOrOverlap_Glitch,
54 kCollapsedCoin_Glitch, 58 kCollapsedCoin_Glitch,
55 kCollapsedDone_Glitch, 59 kCollapsedDone_Glitch,
56 kCollapsedOppValue_Glitch, 60 kCollapsedOppValue_Glitch,
57 kCollapsedSpan_Glitch, 61 kCollapsedSpan_Glitch,
58 kCollapsedWindValue_Glitch, 62 kCollapsedWindValue_Glitch,
59 kDeletedCoin_Glitch, 63 kDeletedCoin_Glitch,
60 kExpandCoin_Glitch, 64 kExpandCoin_Glitch,
61 kMarkCoinEnd_Glitch, 65 kMarkCoinEnd_Glitch,
62 kMarkCoinInsert_Glitch, 66 kMarkCoinInsert_Glitch,
67 kMarkCoinMissing_Glitch,
68 kMarkCoinStart_Glitch,
69 kMergeContained_Glitch,
63 kMissingCoin_Glitch, 70 kMissingCoin_Glitch,
64 kMissingDone_Glitch, 71 kMissingDone_Glitch,
65 kMissingIntersection_Glitch, 72 kMissingIntersection_Glitch,
66 kMoveMultiple_Glitch, 73 kMoveMultiple_Glitch,
74 kMoveNearbyClearAll_Glitch,
75 kMoveNearbyClearAll2_Glitch,
76 kMoveNearbyMerge_Glitch,
77 kMoveNearbyMergeFinal_Glitch,
78 kMoveNearbyRelease_Glitch,
79 kMoveNearbyReleaseFinal_Glitch,
80 kReleasedSpan_Glitch,
67 kUnaligned_Glitch, 81 kUnaligned_Glitch,
68 kUnalignedHead_Glitch, 82 kUnalignedHead_Glitch,
69 kUnalignedTail_Glitch, 83 kUnalignedTail_Glitch,
70 kUndetachedSpan_Glitch,
71 kUnmergedSpan_Glitch,
72 }; 84 };
73 85
74 static const int kGlitchType_Count = kUnmergedSpan_Glitch + 1; 86 static const int kGlitchType_Count = kUnalignedTail_Glitch + 1;
75 87
76 struct SpanGlitch { 88 struct SpanGlitch {
77 const char* fStage; 89 const char* fStage;
78 const SkOpSpanBase* fBase; 90 const SkOpSpanBase* fBase;
79 const SkOpSpanBase* fSuspect; 91 const SkOpSpanBase* fSuspect;
80 const SkCoincidentSpans* fCoin;
81 const SkOpSegment* fSegment; 92 const SkOpSegment* fSegment;
93 const SkOpSegment* fOppSegment;
82 const SkOpPtT* fCoinSpan; 94 const SkOpPtT* fCoinSpan;
83 const SkOpPtT* fEndSpan; 95 const SkOpPtT* fEndSpan;
84 const SkOpPtT* fOppSpan; 96 const SkOpPtT* fOppSpan;
85 const SkOpPtT* fOppEndSpan; 97 const SkOpPtT* fOppEndSpan;
86 double fT; 98 double fStartT;
99 double fEndT;
100 double fOppStartT;
101 double fOppEndT;
87 SkPoint fPt; 102 SkPoint fPt;
88 GlitchType fType; 103 GlitchType fType;
89 }; 104 };
90 105
91 struct SkPathOpsDebug::GlitchLog { 106 struct SkPathOpsDebug::GlitchLog {
92 SpanGlitch* recordCommon(GlitchType type, const char* stage) { 107 SpanGlitch* recordCommon(GlitchType type, const char* stage) {
93 SpanGlitch* glitch = fGlitches.push(); 108 SpanGlitch* glitch = fGlitches.push();
94 glitch->fStage = stage; 109 glitch->fStage = stage;
95 glitch->fBase = nullptr; 110 glitch->fBase = nullptr;
96 glitch->fSuspect = nullptr; 111 glitch->fSuspect = nullptr;
97 glitch->fCoin = nullptr;
98 glitch->fSegment = nullptr; 112 glitch->fSegment = nullptr;
113 glitch->fOppSegment = nullptr;
99 glitch->fCoinSpan = nullptr; 114 glitch->fCoinSpan = nullptr;
100 glitch->fEndSpan = nullptr; 115 glitch->fEndSpan = nullptr;
101 glitch->fOppSpan = nullptr; 116 glitch->fOppSpan = nullptr;
102 glitch->fOppEndSpan = nullptr; 117 glitch->fOppEndSpan = nullptr;
103 glitch->fT = SK_ScalarNaN; 118 glitch->fStartT = SK_ScalarNaN;
119 glitch->fEndT = SK_ScalarNaN;
120 glitch->fOppStartT = SK_ScalarNaN;
121 glitch->fOppEndT = SK_ScalarNaN;
104 glitch->fPt = { SK_ScalarNaN, SK_ScalarNaN }; 122 glitch->fPt = { SK_ScalarNaN, SK_ScalarNaN };
105 glitch->fType = type; 123 glitch->fType = type;
106 return glitch; 124 return glitch;
107 } 125 }
108 126
109 void record(GlitchType type, const char* stage, const SkOpSpanBase* base, 127 void record(GlitchType type, const char* stage, const SkOpSpanBase* base,
110 const SkOpSpanBase* suspect = NULL) { 128 const SkOpSpanBase* suspect = NULL) {
111 SpanGlitch* glitch = recordCommon(type, stage); 129 SpanGlitch* glitch = recordCommon(type, stage);
112 glitch->fBase = base; 130 glitch->fBase = base;
113 glitch->fSuspect = suspect; 131 glitch->fSuspect = suspect;
114 } 132 }
115 133
134 void record(GlitchType type, const char* stage, const SkOpSpanBase* base,
135 const SkOpPtT* ptT) {
136 SpanGlitch* glitch = recordCommon(type, stage);
137 glitch->fBase = base;
138 glitch->fCoinSpan = ptT;
139 }
140
116 void record(GlitchType type, const char* stage, const SkCoincidentSpans* coi n, 141 void record(GlitchType type, const char* stage, const SkCoincidentSpans* coi n,
117 const SkOpPtT* coinSpan) { 142 const SkCoincidentSpans* opp = NULL) {
118 SpanGlitch* glitch = recordCommon(type, stage); 143 SpanGlitch* glitch = recordCommon(type, stage);
119 glitch->fCoin = coin; 144 glitch->fCoinSpan = coin->coinPtTStart();
120 glitch->fCoinSpan = coinSpan; 145 glitch->fEndSpan = coin->coinPtTEnd();
146 if (opp) {
147 glitch->fOppSpan = opp->coinPtTStart();
148 glitch->fOppEndSpan = opp->coinPtTEnd();
149 }
121 } 150 }
122 151
123 void record(GlitchType type, const char* stage, const SkOpSpanBase* base, 152 void record(GlitchType type, const char* stage, const SkOpSpanBase* base,
124 const SkOpSegment* seg, double t, SkPoint pt) { 153 const SkOpSegment* seg, double t, SkPoint pt) {
125 SpanGlitch* glitch = recordCommon(type, stage); 154 SpanGlitch* glitch = recordCommon(type, stage);
126 glitch->fBase = base; 155 glitch->fBase = base;
127 glitch->fSegment = seg; 156 glitch->fSegment = seg;
128 glitch->fT = t; 157 glitch->fStartT = t;
129 glitch->fPt = pt; 158 glitch->fPt = pt;
130 } 159 }
131 160
132 void record(GlitchType type, const char* stage, const SkOpSpanBase* base, do uble t, 161 void record(GlitchType type, const char* stage, const SkOpSpanBase* base, do uble t,
133 SkPoint pt) { 162 SkPoint pt) {
134 SpanGlitch* glitch = recordCommon(type, stage); 163 SpanGlitch* glitch = recordCommon(type, stage);
135 glitch->fBase = base; 164 glitch->fBase = base;
136 glitch->fT = t; 165 glitch->fStartT = t;
137 glitch->fPt = pt; 166 glitch->fPt = pt;
138 } 167 }
139 168
140 void record(GlitchType type, const char* stage, const SkCoincidentSpans* coi n, 169 void record(GlitchType type, const char* stage, const SkCoincidentSpans* coi n,
141 const SkOpPtT* coinSpan, const SkOpPtT* endSpan) { 170 const SkOpPtT* coinSpan, const SkOpPtT* endSpan) {
142 SpanGlitch* glitch = recordCommon(type, stage); 171 SpanGlitch* glitch = recordCommon(type, stage);
143 glitch->fCoin = coin; 172 glitch->fCoinSpan = coin->coinPtTStart();
144 glitch->fCoinSpan = coinSpan; 173 glitch->fEndSpan = coin->coinPtTEnd();
145 glitch->fEndSpan = endSpan; 174 glitch->fEndSpan = endSpan;
175 glitch->fOppSpan = coinSpan;
176 glitch->fOppEndSpan = endSpan;
146 } 177 }
147 178
148 void record(GlitchType type, const char* stage, const SkCoincidentSpans* coi n, 179 void record(GlitchType type, const char* stage, const SkCoincidentSpans* coi n,
149 const SkOpSpanBase* suspect) { 180 const SkOpSpanBase* base) {
150 SpanGlitch* glitch = recordCommon(type, stage); 181 SpanGlitch* glitch = recordCommon(type, stage);
151 glitch->fSuspect = suspect; 182 glitch->fBase = base;
152 glitch->fCoin = coin; 183 glitch->fCoinSpan = coin->coinPtTStart();
184 glitch->fEndSpan = coin->coinPtTEnd();
153 } 185 }
154 186
155 void record(GlitchType type, const char* stage, const SkOpPtT* ptTS, const S kOpPtT* ptTE, 187 void record(GlitchType type, const char* stage, const SkOpPtT* ptTS, const S kOpPtT* ptTE,
156 const SkOpPtT* oPtTS, const SkOpPtT* oPtTE) { 188 const SkOpPtT* oPtTS, const SkOpPtT* oPtTE) {
157 SpanGlitch* glitch = recordCommon(type, stage); 189 SpanGlitch* glitch = recordCommon(type, stage);
158 glitch->fCoinSpan = ptTS; 190 glitch->fCoinSpan = ptTS;
159 glitch->fEndSpan = ptTE; 191 glitch->fEndSpan = ptTE;
160 glitch->fOppSpan = oPtTS; 192 glitch->fOppSpan = oPtTS;
161 glitch->fOppEndSpan = oPtTE; 193 glitch->fOppEndSpan = oPtTE;
162 } 194 }
163 195
196 void record(GlitchType type, const char* stage, const SkOpSegment* seg, doub le startT,
197 double endT, const SkOpSegment* oppSeg, double oppStartT, double opp EndT) {
198 SpanGlitch* glitch = recordCommon(type, stage);
199 glitch->fSegment = seg;
200 glitch->fStartT = startT;
201 glitch->fEndT = endT;
202 glitch->fOppSegment = oppSeg;
203 glitch->fOppStartT = oppStartT;
204 glitch->fOppEndT = oppEndT;
205 }
206
207 void record(GlitchType type, const char* stage, const SkOpSegment* seg,
208 const SkOpSpan* span) {
209 SpanGlitch* glitch = recordCommon(type, stage);
210 glitch->fSegment = seg;
211 glitch->fBase = span;
212 }
213
214 void record(GlitchType type, const char* stage, double t, const SkOpSpanBase * span) {
215 SpanGlitch* glitch = recordCommon(type, stage);
216 glitch->fStartT = t;
217 glitch->fBase = span;
218 }
219
220 void record(GlitchType type, const char* stage, const SkOpSegment* seg) {
221 SpanGlitch* glitch = recordCommon(type, stage);
222 glitch->fSegment = seg;
223 }
224
225 void record(GlitchType type, const char* stage, const SkCoincidentSpans* coi n,
226 const SkOpPtT* ptT) {
227 SpanGlitch* glitch = recordCommon(type, stage);
228 glitch->fCoinSpan = coin->coinPtTStart();
229 glitch->fEndSpan = ptT;
230 }
231
164 SkTDArray<SpanGlitch> fGlitches; 232 SkTDArray<SpanGlitch> fGlitches;
165 }; 233 };
234 #endif
166 235
236 void SkPathOpsDebug::ShowActiveSpans(SkOpContourHead* contourList) {
237 #if DEBUG_ACTIVE_SPANS
238 SkOpContour* contour = contourList;
239 do {
240 contour->debugShowActiveSpans();
241 } while ((contour = contour->next()));
242 #endif
243 }
244
245 #if DEBUG_COINCIDENCE
167 void SkPathOpsDebug::CheckHealth(SkOpContourHead* contourList, const char* id) { 246 void SkPathOpsDebug::CheckHealth(SkOpContourHead* contourList, const char* id) {
247 contourList->globalState()->debugSetCheckHealth(true);
248 #if DEBUG_COINCIDENCE_VERBOSE
168 GlitchLog glitches; 249 GlitchLog glitches;
169 const SkOpContour* contour = contourList; 250 const SkOpContour* contour = contourList;
170 const SkOpCoincidence* coincidence = contour->globalState()->coincidence(); 251 const SkOpCoincidence* coincidence = contour->globalState()->coincidence();
252 coincidence->debugCheckValid(id, &glitches); // don't call validate; spans m ay be inconsistent
171 do { 253 do {
172 contour->debugCheckHealth(id, &glitches); 254 contour->debugCheckHealth(id, &glitches);
173 contour->debugMissingCoincidence(id, &glitches, coincidence); 255 contour->debugMissingCoincidence(id, &glitches);
174 } while ((contour = contour->next())); 256 } while ((contour = contour->next()));
175 coincidence->debugFixAligned(id, &glitches); 257 coincidence->debugRemoveCollapsed(id, &glitches);
176 coincidence->debugAddMissing(id, &glitches); 258 coincidence->debugAddMissing(id, &glitches);
177 coincidence->debugExpand(id, &glitches); 259 coincidence->debugExpand(id, &glitches);
178 coincidence->debugAddExpanded(id, &glitches); 260 coincidence->debugAddExpanded(id, &glitches);
179 coincidence->debugMark(id, &glitches); 261 coincidence->debugMark(id, &glitches);
262 coincidence->debugReorder(id, &glitches);
180 unsigned mask = 0; 263 unsigned mask = 0;
181 for (int index = 0; index < glitches.fGlitches.count(); ++index) { 264 for (int index = 0; index < glitches.fGlitches.count(); ++index) {
182 const SpanGlitch& glitch = glitches.fGlitches[index]; 265 const SpanGlitch& glitch = glitches.fGlitches[index];
183 mask |= 1 << glitch.fType; 266 mask |= 1 << glitch.fType;
184 } 267 }
185 for (int index = 0; index < kGlitchType_Count; ++index) { 268 for (int index = 0; index < kGlitchType_Count; ++index) {
186 SkDebugf(mask & (1 << index) ? "x" : "-"); 269 SkDebugf(mask & (1 << index) ? "x" : "-");
187 } 270 }
188 SkDebugf(" %s\n", id); 271 SkDebugf(" %s\n", id);
272 for (int index = 0; index < glitches.fGlitches.count(); ++index) {
273 const SpanGlitch& glitch = glitches.fGlitches[index];
274 SkDebugf("%02d: ", index);
275 if (glitch.fBase) {
276 SkDebugf(" base=%d", glitch.fBase->debugID());
277 }
278 if (glitch.fSuspect) {
279 SkDebugf(" base=%d", glitch.fSuspect->debugID());
280 }
281 if (glitch.fSegment) {
282 SkDebugf(" segment=%d", glitch.fSegment->debugID());
283 }
284 if (glitch.fCoinSpan) {
285 SkDebugf(" coinSpan=%d", glitch.fCoinSpan->debugID());
286 }
287 if (glitch.fEndSpan) {
288 SkDebugf(" endSpan=%d", glitch.fEndSpan->debugID());
289 }
290 if (glitch.fOppSpan) {
291 SkDebugf(" oppSpan=%d", glitch.fOppSpan->debugID());
292 }
293 if (glitch.fOppEndSpan) {
294 SkDebugf(" oppEndSpan=%d", glitch.fOppEndSpan->debugID());
295 }
296 if (!SkScalarIsNaN(glitch.fStartT)) {
297 SkDebugf(" startT=%g", glitch.fStartT);
298 }
299 if (!SkScalarIsNaN(glitch.fEndT)) {
300 SkDebugf(" endT=%g", glitch.fEndT);
301 }
302 if (glitch.fOppSegment) {
303 SkDebugf(" segment=%d", glitch.fOppSegment->debugID());
304 }
305 if (!SkScalarIsNaN(glitch.fOppStartT)) {
306 SkDebugf(" oppStartT=%g", glitch.fOppStartT);
307 }
308 if (!SkScalarIsNaN(glitch.fOppEndT)) {
309 SkDebugf(" oppEndT=%g", glitch.fOppEndT);
310 }
311 if (!SkScalarIsNaN(glitch.fPt.fX) || !SkScalarIsNaN(glitch.fPt.fY)) {
312 SkDebugf(" pt=%g,%g", glitch.fPt.fX, glitch.fPt.fY);
313 }
314 switch (glitch.fType) {
315 case kAddCorruptCoin_Glitch: SkDebugf(" AddCorruptCoin"); break;
316 case kAddExpandedCoin_Glitch: SkDebugf(" AddExpandedCoin"); break;
317 case kAddExpandedFail_Glitch: SkDebugf(" AddExpandedFail"); break;
318 case kAddIfMissingCoin_Glitch: SkDebugf(" AddIfMissingCoin"); break;
319 case kAddMissingCoin_Glitch: SkDebugf(" AddMissingCoin"); break;
320 case kAddMissingExtend_Glitch: SkDebugf(" AddMissingExtend"); break;
321 case kAddOrOverlap_Glitch: SkDebugf(" AAddOrOverlap"); break;
322 case kCollapsedCoin_Glitch: SkDebugf(" CollapsedCoin"); break;
323 case kCollapsedDone_Glitch: SkDebugf(" CollapsedDone"); break;
324 case kCollapsedOppValue_Glitch: SkDebugf(" CollapsedOppValue"); brea k;
325 case kCollapsedSpan_Glitch: SkDebugf(" CollapsedSpan"); break;
326 case kCollapsedWindValue_Glitch: SkDebugf(" CollapsedWindValue"); br eak;
327 case kDeletedCoin_Glitch: SkDebugf(" DeletedCoin"); break;
328 case kExpandCoin_Glitch: SkDebugf(" ExpandCoin"); break;
329 case kMarkCoinEnd_Glitch: SkDebugf(" MarkCoinEnd"); break;
330 case kMarkCoinInsert_Glitch: SkDebugf(" MarkCoinInsert"); break;
331 case kMarkCoinMissing_Glitch: SkDebugf(" MarkCoinMissing"); break;
332 case kMarkCoinStart_Glitch: SkDebugf(" MarkCoinStart"); break;
333 case kMergeContained_Glitch: SkDebugf(" MergeContained"); break;
334 case kMissingCoin_Glitch: SkDebugf(" MissingCoin"); break;
335 case kMissingDone_Glitch: SkDebugf(" MissingDone"); break;
336 case kMissingIntersection_Glitch: SkDebugf(" MissingIntersection"); break;
337 case kMoveMultiple_Glitch: SkDebugf(" MoveMultiple"); break;
338 case kMoveNearbyClearAll_Glitch: SkDebugf(" MoveNearbyClearAll"); br eak;
339 case kMoveNearbyClearAll2_Glitch: SkDebugf(" MoveNearbyClearAll2"); break;
340 case kMoveNearbyMerge_Glitch: SkDebugf(" MoveNearbyMerge"); break;
341 case kMoveNearbyMergeFinal_Glitch: SkDebugf(" MoveNearbyMergeFinal") ; break;
342 case kMoveNearbyRelease_Glitch: SkDebugf(" MoveNearbyRelease"); brea k;
343 case kMoveNearbyReleaseFinal_Glitch: SkDebugf(" MoveNearbyReleaseFin al"); break;
344 case kReleasedSpan_Glitch: SkDebugf(" ReleasedSpan"); break;
345 case kUnaligned_Glitch: SkDebugf(" Unaligned"); break;
346 case kUnalignedHead_Glitch: SkDebugf(" UnalignedHead"); break;
347 case kUnalignedTail_Glitch: SkDebugf(" UnalignedTail"); break;
348 default: SkASSERT(0);
349 }
350 SkDebugf("\n");
351 }
352 contourList->globalState()->debugSetCheckHealth(false);
353 #if DEBUG_ACTIVE_SPANS
354 SkDebugf("active after %s:\n", id);
355 ShowActiveSpans(contourList);
356 #endif
357 #endif
189 } 358 }
190 #endif 359 #endif
191 360
192 #if defined SK_DEBUG || !FORCE_RELEASE 361 #if defined SK_DEBUG || !FORCE_RELEASE
193 void SkPathOpsDebug::MathematicaIze(char* str, size_t bufferLen) { 362 void SkPathOpsDebug::MathematicaIze(char* str, size_t bufferLen) {
194 size_t len = strlen(str); 363 size_t len = strlen(str);
195 bool num = false; 364 bool num = false;
196 for (size_t idx = 0; idx < len; ++idx) { 365 for (size_t idx = 0; idx < len; ++idx) {
197 if (num && str[idx] == 'e') { 366 if (num && str[idx] == 'e') {
198 if (len + 2 >= bufferLen) { 367 if (len + 2 >= bufferLen) {
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
247 SkDebugf("\nstatic void %s(skiatest::Reporter* reporter, const char* filenam e) {\n", functionName); 416 SkDebugf("\nstatic void %s(skiatest::Reporter* reporter, const char* filenam e) {\n", functionName);
248 if (strcmp("skphealth_com76", functionName) == 0) { 417 if (strcmp("skphealth_com76", functionName) == 0) {
249 SkDebugf("found it\n"); 418 SkDebugf("found it\n");
250 } 419 }
251 } 420 }
252 421
253 static const char* gOpStrs[] = { 422 static const char* gOpStrs[] = {
254 "kDifference_SkPathOp", 423 "kDifference_SkPathOp",
255 "kIntersect_SkPathOp", 424 "kIntersect_SkPathOp",
256 "kUnion_SkPathOp", 425 "kUnion_SkPathOp",
257 "kXor_PathOp", 426 "kXOR_PathOp",
258 "kReverseDifference_SkPathOp", 427 "kReverseDifference_SkPathOp",
259 }; 428 };
260 429
261 const char* SkPathOpsDebug::OpStr(SkPathOp op) { 430 const char* SkPathOpsDebug::OpStr(SkPathOp op) {
262 return gOpStrs[op]; 431 return gOpStrs[op];
263 } 432 }
264 433
265 static void show_op(SkPathOp op, const char* pathOne, const char* pathTwo) { 434 static void show_op(SkPathOp op, const char* pathOne, const char* pathTwo) {
266 SkDebugf(" testPathOp(reporter, %s, %s, %s, filename);\n", pathOne, pathT wo, gOpStrs[op]); 435 SkDebugf(" testPathOp(reporter, %s, %s, %s, filename);\n", pathOne, pathT wo, gOpStrs[op]);
267 SkDebugf("}\n"); 436 SkDebugf("}\n");
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
405 } 574 }
406 575
407 void SkDRect::debugInit() { 576 void SkDRect::debugInit() {
408 fLeft = fTop = fRight = fBottom = SK_ScalarNaN; 577 fLeft = fTop = fRight = fBottom = SK_ScalarNaN;
409 } 578 }
410 579
411 #include "SkOpAngle.h" 580 #include "SkOpAngle.h"
412 #include "SkOpSegment.h" 581 #include "SkOpSegment.h"
413 582
414 #if DEBUG_COINCIDENCE 583 #if DEBUG_COINCIDENCE
415 void SkOpSegment::debugAddAlignIntersection(const char* id, SkPathOpsDebug::Glit chLog* log, 584 // commented-out lines keep this in sync with addT()
416 const SkOpPtT& endPtT, const SkPoint& oldPt, const SkOpContourHead* con tourList) const { 585 const SkOpPtT* SkOpSegment::debugAddT(double t, AliasMatch allowAlias, bool* al located) const {
417 const SkPoint& newPt = endPtT.fPt; 586 debugValidate();
418 if (newPt == oldPt) { 587 SkPoint pt = this->ptAtT(t);
419 return; 588 const SkOpSpanBase* span = &fHead;
420 }
421 SkPoint line[2] = { newPt, oldPt };
422 SkPathOpsBounds lineBounds;
423 lineBounds.setBounds(line, 2);
424 SkDLine aLine;
425 aLine.set(line);
426 const SkOpContour* current = contourList;
427 do { 589 do {
428 if (!SkPathOpsBounds::Intersects(current->bounds(), lineBounds)) { 590 const SkOpPtT* result = span->ptT();
429 continue; 591 const SkOpPtT* loop;
592 bool duplicatePt;
593 if (t == result->fT) {
594 goto bumpSpan;
430 } 595 }
431 const SkOpSegment* segment = current->first(); 596 if (this->match(result, this, t, pt, allowAlias)) {
432 do { 597 // see if any existing alias matches segment, pt, and t
433 if (!SkPathOpsBounds::Intersects(segment->bounds(), lineBounds)) { 598 loop = result->next();
434 continue; 599 duplicatePt = false;
600 while (loop != result) {
601 bool ptMatch = loop->fPt == pt;
602 if (loop->segment() == this && loop->fT == t && ptMatch) {
603 goto bumpSpan;
604 }
605 duplicatePt |= ptMatch;
606 loop = loop->next();
435 } 607 }
436 if (newPt == segment->fPts[0]) { 608 if (kNoAliasMatch == allowAlias) {
437 continue; 609 bumpSpan:
610 // span->bumpSpanAdds();
611 return result;
438 } 612 }
439 if (newPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) { 613 // SkOpPtT* alias = SkOpTAllocator<SkOpPtT>::Allocate(allocator);
440 continue; 614 // alias->init(result->span(), t, pt, duplicatePt);
615 // result->insert(alias);
616 // result->span()->unaligned();
617 this->debugValidate();
618 // #if DEBUG_ADD_T
619 // SkDebugf("%s alias t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
620 // alias->segment()->debugID(), alias->span()->debugID());
621 // #endif
622 // span->bumpSpanAdds();
623 if (allocated) {
624 *allocated = true;
441 } 625 }
442 if (oldPt == segment->fPts[0]) { 626 return nullptr;
443 continue; 627 }
628 if (t < result->fT) {
629 const SkOpSpan* prev = result->span()->prev();
630 if (!prev) {
631 return nullptr; // FIXME: this is a fail case; nullptr return e lsewhere means result was allocated in non-const version
444 } 632 }
445 if (oldPt == segment->fPts[SkPathOpsVerbToPoints(segment->fVerb)]) { 633 // SkOpSpan* span = insert(prev, allocator);
446 continue; 634 // span->init(this, prev, t, pt);
635 this->debugValidate();
636 // #if DEBUG_ADD_T
637 // SkDebugf("%s insert t=%1.9g segID=%d spanID=%d\n", __FUNCTION__, t,
638 // span->segment()->debugID(), span->debugID());
639 // #endif
640 // span->bumpSpanAdds();
641 if (allocated) {
642 *allocated = true;
447 } 643 }
448 if (endPtT.debugContains(segment)) { 644 return nullptr;
449 continue;
450 }
451 SkIntersections i;
452 switch (segment->fVerb) {
453 case SkPath::kLine_Verb: {
454 SkDLine bLine;
455 bLine.set(segment->fPts);
456 i.intersect(bLine, aLine);
457 } break;
458 case SkPath::kQuad_Verb: {
459 SkDQuad bQuad;
460 bQuad.set(segment->fPts);
461 i.intersect(bQuad, aLine);
462 } break;
463 case SkPath::kConic_Verb: {
464 SkDConic bConic;
465 bConic.set(segment->fPts, segment->fWeight);
466 i.intersect(bConic, aLine);
467 } break;
468 case SkPath::kCubic_Verb: {
469 SkDCubic bCubic;
470 bCubic.set(segment->fPts);
471 i.intersect(bCubic, aLine);
472 } break;
473 default:
474 SkASSERT(0);
475 }
476 if (i.used()) {
477 SkASSERT(i.used() == 1);
478 SkASSERT(!zero_or_one(i[0][0]));
479 SkOpSpanBase* checkSpan = fHead.next();
480 while (!checkSpan->final()) {
481 if (checkSpan->contains(segment)) {
482 goto nextSegment;
483 }
484 checkSpan = checkSpan->upCast()->next();
485 }
486 log->record(kMissingIntersection_Glitch, id, checkSpan, segment, i[0][0], newPt);
487 }
488 nextSegment:
489 ;
490 } while ((segment = segment->next()));
491 } while ((current = current->next()));
492 }
493
494 bool SkOpSegment::debugAddMissing(double t, const SkOpSegment* opp) const {
495 const SkOpSpanBase* existing = nullptr;
496 const SkOpSpanBase* test = &fHead;
497 double testT;
498 do {
499 if ((testT = test->ptT()->fT) >= t) {
500 if (testT == t) {
501 existing = test;
502 }
503 break;
504 } 645 }
505 } while ((test = test->upCast()->next())); 646 SkASSERT(span != &fTail);
506 return !existing || !existing->debugContains(opp); 647 } while ((span = span->upCast()->next()));
507 } 648 SkASSERT(0);
508 649 return nullptr;
509 void SkOpSegment::debugAlign(const char* id, SkPathOpsDebug::GlitchLog* glitches ) const {
510 const SkOpSpanBase* span = &fHead;
511 if (!span->aligned()) {
512 if (!span->debugAlignedEnd(0, fPts[0])) {
513 glitches->record(kUnalignedHead_Glitch, id, span);
514 }
515 }
516 while ((span = span->upCast()->next())) {
517 if (span == &fTail) {
518 break;
519 }
520 if (!span->aligned()) {
521 glitches->record(kUnaligned_Glitch, id, span);
522 }
523 }
524 if (!span->aligned()) {
525 span->debugAlignedEnd(1, fPts[SkPathOpsVerbToPoints(fVerb)]);
526 }
527 if (this->collapsed()) {
528 const SkOpSpan* span = &fHead;
529 do {
530 if (span->windValue()) {
531 glitches->record(kCollapsedWindValue_Glitch, id, span);
532 }
533 if (span->oppValue()) {
534 glitches->record(kCollapsedOppValue_Glitch, id, span);
535 }
536 if (!span->done()) {
537 glitches->record(kCollapsedDone_Glitch, id, span);
538 }
539 } while ((span = span->next()->upCastable()));
540 }
541 } 650 }
542 #endif 651 #endif
543 652
544 #if DEBUG_ANGLE 653 #if DEBUG_ANGLE
545 void SkOpSegment::debugCheckAngleCoin() const { 654 void SkOpSegment::debugCheckAngleCoin() const {
546 const SkOpSpanBase* base = &fHead; 655 const SkOpSpanBase* base = &fHead;
547 const SkOpSpan* span; 656 const SkOpSpan* span;
548 do { 657 do {
549 const SkOpAngle* angle = base->fromAngle(); 658 const SkOpAngle* angle = base->fromAngle();
550 if (angle && angle->fCheckCoincidence) { 659 if (angle && angle->debugCheckCoincidence()) {
551 angle->debugCheckNearCoincidence(); 660 angle->debugCheckNearCoincidence();
552 } 661 }
553 if (base->final()) { 662 if (base->final()) {
554 break; 663 break;
555 } 664 }
556 span = base->upCast(); 665 span = base->upCast();
557 angle = span->toAngle(); 666 angle = span->toAngle();
558 if (angle && angle->fCheckCoincidence) { 667 if (angle && angle->debugCheckCoincidence()) {
559 angle->debugCheckNearCoincidence(); 668 angle->debugCheckNearCoincidence();
560 } 669 }
561 } while ((base = span->next())); 670 } while ((base = span->next()));
562 } 671 }
563 #endif 672 #endif
564 673
565 #if DEBUG_COINCIDENCE 674 #if DEBUG_COINCIDENCE_VERBOSE
566 // this mimics the order of the checks in handle coincidence 675 // this mimics the order of the checks in handle coincidence
567 void SkOpSegment::debugCheckHealth(const char* id, SkPathOpsDebug::GlitchLog* gl itches) const { 676 void SkOpSegment::debugCheckHealth(const char* id, SkPathOpsDebug::GlitchLog* gl itches) const {
568 debugMoveMultiples(id, glitches); 677 debugMoveMultiples(id, glitches);
569 debugFindCollapsed(id, glitches);
570 debugMoveNearby(id, glitches); 678 debugMoveNearby(id, glitches);
571 debugAlign(id, glitches); 679 debugMissingCoincidence(id, glitches);
572 debugAddAlignIntersections(id, glitches, this->globalState()->contourHead()) ;
573
574 } 680 }
575 681
576 void SkOpSegment::debugFindCollapsed(const char* id, SkPathOpsDebug::GlitchLog* glitches) const { 682 // commented-out lines keep this in sync with clearAll()
577 if (fHead.contains(&fTail)) { 683 void SkOpSegment::debugClearAll(const char* id, SkPathOpsDebug::GlitchLog* glitc hes) const {
578 const SkOpSpan* span = this->head(); 684 const SkOpSpan* span = &fHead;
579 bool missingDone = false; 685 do {
580 do { 686 this->debugClearOne(span, id, glitches);
581 missingDone |= !span->done(); 687 } while ((span = span->next()->upCastable()));
582 } while ((span = span->next()->upCastable())); 688 this->globalState()->coincidence()->debugRelease(id, glitches, this);
583 if (missingDone) { 689 }
584 glitches->record(kMissingDone_Glitch, id, &fHead); 690
585 } 691 // commented-out lines keep this in sync with clearOne()
586 if (!fHead.debugAlignedEnd(0, fHead.pt())) { 692 void SkOpSegment::debugClearOne(const SkOpSpan* span, const char* id, SkPathOpsD ebug::GlitchLog* glitches) const {
587 glitches->record(kUnalignedHead_Glitch, id, &fHead); 693 if (span->windValue()) glitches->record(kCollapsedWindValue_Glitch, id, span );
588 } 694 if (span->oppValue()) glitches->record(kCollapsedOppValue_Glitch, id, span);
589 if (!fTail.aligned()) { 695 if (!span->done()) glitches->record(kCollapsedDone_Glitch, id, span);
590 glitches->record(kUnalignedTail_Glitch, id, &fTail);
591 }
592 }
593 } 696 }
594 #endif 697 #endif
595 698
596 SkOpAngle* SkOpSegment::debugLastAngle() { 699 SkOpAngle* SkOpSegment::debugLastAngle() {
597 SkOpAngle* result = nullptr; 700 SkOpAngle* result = nullptr;
598 SkOpSpan* span = this->head(); 701 SkOpSpan* span = this->head();
599 do { 702 do {
600 if (span->toAngle()) { 703 if (span->toAngle()) {
601 SkASSERT(!result); 704 SkASSERT(!result);
602 result = span->toAngle(); 705 result = span->toAngle();
603 } 706 }
604 } while ((span = span->next()->upCastable())); 707 } while ((span = span->next()->upCastable()));
605 SkASSERT(result); 708 SkASSERT(result);
606 return result; 709 return result;
607 } 710 }
608 711
609 #if DEBUG_COINCIDENCE 712 #if DEBUG_COINCIDENCE
610 void SkOpSegment::debugMissingCoincidence(const char* id, SkPathOpsDebug::Glitch Log* log, 713 // commented-out lines keep this in sync with ClearVisited
611 const SkOpCoincidence* coincidences) const { 714 void SkOpSegment::DebugClearVisited(const SkOpSpanBase* span) {
612 if (this->verb() != SkPath::kLine_Verb) { 715 // reset visited flag back to false
613 return; 716 do {
614 } 717 const SkOpPtT* ptT = span->ptT(), * stopPtT = ptT;
718 while ((ptT = ptT->next()) != stopPtT) {
719 const SkOpSegment* opp = ptT->segment();
720 opp->resetDebugVisited();
721 }
722 } while (!span->final() && (span = span->upCast()->next()));
723 }
724 #endif
725
726 #if DEBUG_COINCIDENCE_VERBOSE
727 // commented-out lines keep this in sync with missingCoincidence()
728 // look for pairs of undetected coincident curves
729 // assumes that segments going in have visited flag clear
730 // Even though pairs of curves correct detect coincident runs, a run may be miss ed
731 // if the coincidence is a product of multiple intersections. For instance, give n
732 // curves A, B, and C:
733 // A-B intersect at a point 1; A-C and B-C intersect at point 2, so near
734 // the end of C that the intersection is replaced with the end of C.
735 // Even though A-B correctly do not detect an intersection at point 2,
736 // the resulting run from point 1 to point 2 is coincident on A and B.
737 void SkOpSegment::debugMissingCoincidence(const char* id, SkPathOpsDebug::Glitch Log* log) const {
615 if (this->done()) { 738 if (this->done()) {
616 return; 739 return;
617 } 740 }
618 const SkOpSpan* prior = nullptr; 741 const SkOpSpan* prior = nullptr;
619 const SkOpSpanBase* spanBase = &fHead; 742 const SkOpSpanBase* spanBase = &fHead;
743 // bool result = false;
620 do { 744 do {
621 const SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT; 745 const SkOpPtT* ptT = spanBase->ptT(), * spanStopPtT = ptT;
622 SkASSERT(ptT->span() == spanBase); 746 SkASSERT(ptT->span() == spanBase);
623 while ((ptT = ptT->next()) != spanStopPtT) { 747 while ((ptT = ptT->next()) != spanStopPtT) {
624 if (ptT->deleted()) { 748 if (ptT->deleted()) {
625 continue; 749 continue;
626 } 750 }
627 SkOpSegment* opp = ptT->span()->segment(); 751 const SkOpSegment* opp = ptT->span()->segment();
628 // if (opp->verb() == SkPath::kLine_Verb) {
629 // continue;
630 // }
631 if (opp->done()) { 752 if (opp->done()) {
632 continue; 753 continue;
633 } 754 }
634 // when opp is encounted the 1st time, continue; on 2nd encounter, l ook for coincidence 755 // when opp is encounted the 1st time, continue; on 2nd encounter, l ook for coincidence
635 if (!opp->visited()) { 756 if (!opp->debugVisited()) {
636 continue; 757 continue;
637 } 758 }
638 if (spanBase == &fHead) { 759 if (spanBase == &fHead) {
639 continue; 760 continue;
640 } 761 }
762 if (ptT->segment() == this) {
763 continue;
764 }
641 const SkOpSpan* span = spanBase->upCastable(); 765 const SkOpSpan* span = spanBase->upCastable();
642 // FIXME?: this assumes that if the opposite segment is coincident t hen no more 766 // FIXME?: this assumes that if the opposite segment is coincident t hen no more
643 // coincidence needs to be detected. This may not be true. 767 // coincidence needs to be detected. This may not be true.
644 if (span && span->segment() != opp && span->containsCoincidence(opp) ) { 768 if (span && span->segment() != opp && span->containsCoincidence(opp) ) { // debug has additional condition since it may be called before inner dupli cate points have been deleted
herb_g 2016/07/18 15:13:39 Comments on next line?
caryclark 2016/07/18 15:55:49 The crazy formatting here is so that SkOpSegment::
645 continue; 769 continue;
646 } 770 }
647 if (spanBase->segment() != opp && spanBase->containsCoinEnd(opp)) { 771 if (spanBase->segment() != opp && spanBase->containsCoinEnd(opp)) { // debug has additional condition since it may be called before inner duplicate points have been deleted
648 continue; 772 continue;
649 } 773 }
650 const SkOpPtT* priorPtT = nullptr, * priorStopPtT; 774 const SkOpPtT* priorPtT = nullptr, * priorStopPtT;
651 // find prior span containing opp segment 775 // find prior span containing opp segment
652 const SkOpSegment* priorOpp = nullptr; 776 const SkOpSegment* priorOpp = nullptr;
653 const SkOpSpan* priorTest = spanBase->prev(); 777 const SkOpSpan* priorTest = spanBase->prev();
654 while (!priorOpp && priorTest) { 778 while (!priorOpp && priorTest) {
655 priorStopPtT = priorPtT = priorTest->ptT(); 779 priorStopPtT = priorPtT = priorTest->ptT();
656 while ((priorPtT = priorPtT->next()) != priorStopPtT) { 780 while ((priorPtT = priorPtT->next()) != priorStopPtT) {
657 if (priorPtT->deleted()) { 781 if (priorPtT->deleted()) {
658 continue; 782 continue;
659 } 783 }
660 SkOpSegment* segment = priorPtT->span()->segment(); 784 SkOpSegment* segment = priorPtT->span()->segment();
661 if (segment == opp) { 785 if (segment == opp) {
662 prior = priorTest; 786 prior = priorTest;
663 priorOpp = opp; 787 priorOpp = opp;
664 break; 788 break;
665 } 789 }
666 } 790 }
667 priorTest = priorTest->prev(); 791 priorTest = priorTest->prev();
668 } 792 }
669 if (!priorOpp) { 793 if (!priorOpp) {
670 continue; 794 continue;
671 } 795 }
796 if (priorPtT == ptT) {
797 continue;
798 }
672 const SkOpPtT* oppStart = prior->ptT(); 799 const SkOpPtT* oppStart = prior->ptT();
673 const SkOpPtT* oppEnd = spanBase->ptT(); 800 const SkOpPtT* oppEnd = spanBase->ptT();
674 bool swapped = priorPtT->fT > ptT->fT; 801 bool swapped = priorPtT->fT > ptT->fT;
675 if (swapped) { 802 if (swapped) {
676 SkTSwap(priorPtT, ptT); 803 SkTSwap(priorPtT, ptT);
677 SkTSwap(oppStart, oppEnd); 804 SkTSwap(oppStart, oppEnd);
678 } 805 }
679 bool flipped = oppStart->fT > oppEnd->fT; 806 const SkOpCoincidence* coincidence = this->globalState()->coincidenc e();
680 bool coincident = false; 807 const SkOpPtT* rootPriorPtT = priorPtT->span()->ptT();
681 if (coincidences->contains(priorPtT, ptT, oppStart, oppEnd, flipped) ) { 808 const SkOpPtT* rootPtT = ptT->span()->ptT();
809 const SkOpPtT* rootOppStart = oppStart->span()->ptT();
810 const SkOpPtT* rootOppEnd = oppEnd->span()->ptT();
811 if (coincidence->contains(rootPriorPtT, rootPtT, rootOppStart, rootO ppEnd)) {
682 goto swapBack; 812 goto swapBack;
683 } 813 }
684 if (opp->verb() == SkPath::kLine_Verb) { 814 if (testForCoincidence(rootPriorPtT, rootPtT, prior, spanBase, opp)) {
685 coincident = (SkDPoint::ApproximatelyEqual(priorPtT->fPt, oppSta rt->fPt) || 815 // mark coincidence
686 SkDPoint::ApproximatelyEqual(priorPtT->fPt, oppEnd->fPt) ) && 816 #if DEBUG_COINCIDENCE
687 (SkDPoint::ApproximatelyEqual(ptT->fPt, oppStart->fPt) | | 817 // SkDebugf("%s coinSpan=%d endSpan=%d oppSpan=%d oppEndSpan=%d\ n", __FUNCTION__,
herb_g 2016/07/18 15:13:39 Remove commented out code.
caryclark 2016/07/18 15:55:49 See above
688 SkDPoint::ApproximatelyEqual(ptT->fPt, oppEnd->fPt)); 818 // rootPriorPtT->debugID(), rootPtT->debugID(), rootOppS tart->debugID(),
689 } 819 // rootOppEnd->debugID());
690 if (!coincident) { 820 #endif
691 coincident = testForCoincidence(priorPtT, ptT, prior, spanBase, opp, 5000);
692 }
693 if (coincident) {
694 log->record(kMissingCoin_Glitch, id, priorPtT, ptT, oppStart, op pEnd); 821 log->record(kMissingCoin_Glitch, id, priorPtT, ptT, oppStart, op pEnd);
822 // coincidences->add(rootPriorPtT, rootPtT, rootOppStart, root OppEnd);
823 // }
824 #if DEBUG_COINCIDENCE
825 // SkASSERT(coincidences->contains(rootPriorPtT, rootPtT, rootOpp Start, rootOppEnd)
826 #endif
827 // result = true;
695 } 828 }
696 swapBack: 829 swapBack:
697 if (swapped) { 830 if (swapped) {
698 SkTSwap(priorPtT, ptT); 831 SkTSwap(priorPtT, ptT);
699 } 832 }
700 } 833 }
701 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next( ))); 834 } while ((spanBase = spanBase->final() ? nullptr : spanBase->upCast()->next( )));
835 DebugClearVisited(&fHead);
836 return;
702 } 837 }
703 838
839 // commented-out lines keep this in sync with moveMultiples()
840 // if a span has more than one intersection, merge the other segments' span as n eeded
704 void SkOpSegment::debugMoveMultiples(const char* id, SkPathOpsDebug::GlitchLog* glitches) const { 841 void SkOpSegment::debugMoveMultiples(const char* id, SkPathOpsDebug::GlitchLog* glitches) const {
842 debugValidate();
705 const SkOpSpanBase* test = &fHead; 843 const SkOpSpanBase* test = &fHead;
706 do { 844 do {
707 int addCount = test->spanAddsCount(); 845 int addCount = test->spanAddsCount();
708 SkASSERT(addCount >= 1); 846 SkASSERT(addCount >= 1);
709 if (addCount == 1) { 847 if (addCount == 1) {
710 continue; 848 continue;
711 } 849 }
712 const SkOpPtT* startPtT = test->ptT(); 850 const SkOpPtT* startPtT = test->ptT();
713 const SkOpPtT* testPtT = startPtT; 851 const SkOpPtT* testPtT = startPtT;
714 do { // iterate through all spans associated with start 852 do { // iterate through all spans associated with start
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after
770 goto tryNextSpan; 908 goto tryNextSpan;
771 } 909 }
772 const SkOpPtT* matchPtT = startPtT; 910 const SkOpPtT* matchPtT = startPtT;
773 do { 911 do {
774 if (matchPtT->segment() == oppPtTSegment) { 912 if (matchPtT->segment() == oppPtTSegment) {
775 goto foundMatch; 913 goto foundMatch;
776 } 914 }
777 } while ((matchPtT = matchPtT->next()) != startPtT); 915 } while ((matchPtT = matchPtT->next()) != startPtT);
778 goto tryNextSpan; 916 goto tryNextSpan;
779 foundMatch: // merge oppTest and oppSpan 917 foundMatch: // merge oppTest and oppSpan
918 oppSegment->debugValidate();
780 if (oppTest == &oppSegment->fTail || oppTest == &oppSegment- >fHead) { 919 if (oppTest == &oppSegment->fTail || oppTest == &oppSegment- >fHead) {
781 SkASSERT(oppSpan != &oppSegment->fHead); // don't expect collapse 920 SkASSERT(oppSpan != &oppSegment->fHead); // don't expect collapse
782 SkASSERT(oppSpan != &oppSegment->fTail); 921 SkASSERT(oppSpan != &oppSegment->fTail);
783 glitches->record(kMoveMultiple_Glitch, id, oppTest, oppS pan); 922 glitches->record(kMoveMultiple_Glitch, id, oppTest, oppS pan);
784 } else { 923 } else {
785 glitches->record(kMoveMultiple_Glitch, id, oppSpan, oppT est); 924 glitches->record(kMoveMultiple_Glitch, id, oppSpan, oppT est);
786 } 925 }
926 oppSegment->debugValidate();
787 goto checkNextSpan; 927 goto checkNextSpan;
788 } 928 }
789 tryNextSpan: 929 tryNextSpan:
790 ; 930 ;
791 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()) ); 931 } while (oppTest != oppLast && (oppTest = oppTest->upCast()->next()) );
792 } while ((testPtT = testPtT->next()) != startPtT); 932 } while ((testPtT = testPtT->next()) != startPtT);
793 checkNextSpan: 933 checkNextSpan:
794 ; 934 ;
795 } while ((test = test->final() ? nullptr : test->upCast()->next())); 935 } while ((test = test->final() ? nullptr : test->upCast()->next()));
936 debugValidate();
937 return;
796 } 938 }
797 939
940 // commented-out lines keep this in sync with moveNearby()
941 // Move nearby t values and pts so they all hang off the same span. Alignment ha ppens later.
798 void SkOpSegment::debugMoveNearby(const char* id, SkPathOpsDebug::GlitchLog* gli tches) const { 942 void SkOpSegment::debugMoveNearby(const char* id, SkPathOpsDebug::GlitchLog* gli tches) const {
799 const SkOpSpanBase* spanS = &fHead; 943 debugValidate();
944 // release undeleted spans pointing to this seg that are linked to the prima ry span
945 const SkOpSpanBase* spanBase = &fHead;
800 do { 946 do {
801 const SkOpSpanBase* test = spanS->upCast()->next(); 947 const SkOpPtT* ptT = spanBase->ptT();
802 const SkOpSpanBase* next; 948 const SkOpPtT* headPtT = ptT;
803 if (spanS->contains(test)) { 949 while ((ptT = ptT->next()) != headPtT) {
804 if (!test->final()) { 950 const SkOpSpanBase* test = ptT->span();
805 glitches->record(kUndetachedSpan_Glitch, id, test, spanS); 951 if (ptT->segment() == this && !ptT->deleted() && test != spanBase
806 } else if (spanS != &fHead) { 952 && test->ptT() == ptT) {
807 glitches->record(kUndetachedSpan_Glitch, id, spanS, test); 953 if (test->final()) {
954 if (spanBase == &fHead) {
955 glitches->record(kMoveNearbyClearAll_Glitch, id, this);
956 // return;
herb_g 2016/07/18 15:13:39 Remove commented out code.
caryclark 2016/07/18 15:55:49 See comment above.
957 }
958 glitches->record(kMoveNearbyReleaseFinal_Glitch, id, spanBas e, ptT);
959 } else if (test->prev()) {
960 glitches->record(kMoveNearbyRelease_Glitch, id, test, headPt T);
961 }
962 // break;
808 } 963 }
809 } 964 }
810 do { // iterate through all spans associated with start 965 spanBase = spanBase->upCast()->next();
811 const SkOpPtT* startBase = spanS->ptT(); 966 } while (!spanBase->final());
812 next = test->final() ? nullptr : test->upCast()->next(); 967
813 do { 968 // This loop looks for adjacent spans which are near by
814 const SkOpPtT* testBase = test->ptT(); 969 spanBase = &fHead;
815 do { 970 do { // iterate through all spans associated with start
816 if (startBase == testBase) { 971 const SkOpSpanBase* test = spanBase->upCast()->next();
817 goto checkNextSpan; 972 if (this->spansNearby(spanBase, test)) {
818 } 973 if (test->final()) {
819 if (testBase->duplicate()) { 974 if (spanBase->prev()) {
820 continue; 975 glitches->record(kMoveNearbyMergeFinal_Glitch, id, test);
821 } 976 } else {
822 if (this->match(startBase, testBase->segment(), testBase->fT , testBase->fPt)) { 977 glitches->record(kMoveNearbyClearAll2_Glitch, id, this);
823 if (test == &this->fTail) { 978 // return
824 if (spanS == &fHead) { 979 }
825 glitches->record(kCollapsedSpan_Glitch, id, span S); 980 } else {
826 } else { 981 glitches->record(kMoveNearbyMerge_Glitch, id, spanBase);
827 glitches->record(kUnmergedSpan_Glitch, id, &this ->fTail, spanS); 982 }
828 } 983 }
829 } else { 984 spanBase = test;
830 glitches->record(kUnmergedSpan_Glitch, id, spanS, te st); 985 } while (!spanBase->final());
831 goto checkNextSpan; 986 debugValidate();
832 }
833 }
834 } while ((testBase = testBase->next()) != test->ptT());
835 } while ((startBase = startBase->next()) != spanS->ptT());
836 checkNextSpan:
837 ;
838 } while ((test = next));
839 spanS = spanS->upCast()->next();
840 } while (!spanS->final());
841 } 987 }
842 #endif 988 #endif
843 989
844 void SkOpSegment::debugReset() { 990 void SkOpSegment::debugReset() {
845 this->init(this->fPts, this->fWeight, this->contour(), this->verb()); 991 this->init(this->fPts, this->fWeight, this->contour(), this->verb());
846 } 992 }
847 993
848 #if DEBUG_ACTIVE_SPANS 994 #if DEBUG_ACTIVE_SPANS
849 void SkOpSegment::debugShowActiveSpans() const { 995 void SkOpSegment::debugShowActiveSpans() const {
850 debugValidate(); 996 debugValidate();
851 if (done()) { 997 if (done()) {
852 return; 998 return;
853 } 999 }
854 int lastId = -1; 1000 int lastId = -1;
855 double lastT = -1; 1001 double lastT = -1;
856 const SkOpSpan* span = &fHead; 1002 const SkOpSpan* span = &fHead;
857 do { 1003 do {
858 if (span->done()) { 1004 if (span->done()) {
859 continue; 1005 continue;
860 } 1006 }
861 if (lastId == this->debugID() && lastT == span->t()) { 1007 if (lastId == this->debugID() && lastT == span->t()) {
862 continue; 1008 continue;
863 } 1009 }
864 lastId = this->debugID(); 1010 lastId = this->debugID();
865 lastT = span->t(); 1011 lastT = span->t();
866 SkDebugf("%s id=%d", __FUNCTION__, this->debugID()); 1012 SkDebugf("%s id=%d", __FUNCTION__, this->debugID());
867 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); 1013 // since endpoints may have be adjusted, show actual computed curves
1014 SkDCurve curvePart;
1015 this->subDivide(span, span->next(), &curvePart);
1016 const SkDPoint* pts = curvePart.fCubic.fPts;
1017 SkDebugf(" (%1.9g,%1.9g", pts[0].fX, pts[0].fY);
868 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { 1018 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
869 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); 1019 SkDebugf(" %1.9g,%1.9g", pts[vIndex].fX, pts[vIndex].fY);
870 } 1020 }
871 if (SkPath::kConic_Verb == fVerb) { 1021 if (SkPath::kConic_Verb == fVerb) {
872 SkDebugf(" %1.9gf", fWeight); 1022 SkDebugf(" %1.9gf", curvePart.fConic.fWeight);
873 } 1023 }
874 const SkOpPtT* ptT = span->ptT(); 1024 SkDebugf(") t=%1.9g tEnd=%1.9g", span->t(), span->next()->t());
875 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", ptT->fT, ptT->fPt.fX, ptT->fPt.fY);
876 SkDebugf(" tEnd=%1.9g", span->next()->t());
877 if (span->windSum() == SK_MinS32) { 1025 if (span->windSum() == SK_MinS32) {
878 SkDebugf(" windSum=?"); 1026 SkDebugf(" windSum=?");
879 } else { 1027 } else {
880 SkDebugf(" windSum=%d", span->windSum()); 1028 SkDebugf(" windSum=%d", span->windSum());
881 } 1029 }
882 if (span->oppValue() && span->oppSum() == SK_MinS32) { 1030 if (span->oppValue() && span->oppSum() == SK_MinS32) {
883 SkDebugf(" oppSum=?"); 1031 SkDebugf(" oppSum=?");
884 } else if (span->oppValue() || span->oppSum() != SK_MinS32) { 1032 } else if (span->oppValue() || span->oppSum() != SK_MinS32) {
885 SkDebugf(" oppSum=%d", span->oppSum()); 1033 SkDebugf(" oppSum=%d", span->oppSum());
886 } 1034 }
(...skipping 64 matching lines...) Expand 10 before | Expand all | Expand 10 after
951 SkDebugf("%d", span->windSum()); 1099 SkDebugf("%d", span->windSum());
952 } 1100 }
953 SkDebugf(" windValue=%d oppValue=%d\n", span->windValue(), span->oppValue()) ; 1101 SkDebugf(" windValue=%d oppValue=%d\n", span->windValue(), span->oppValue()) ;
954 } 1102 }
955 1103
956 #endif 1104 #endif
957 1105
958 // loop looking for a pair of angle parts that are too close to be sorted 1106 // loop looking for a pair of angle parts that are too close to be sorted
959 /* This is called after other more simple intersection and angle sorting tests h ave been exhausted. 1107 /* This is called after other more simple intersection and angle sorting tests h ave been exhausted.
960 This should be rarely called -- the test below is thorough and time consuming . 1108 This should be rarely called -- the test below is thorough and time consuming .
961 This checks the distance between start points; the distance between 1109 This checks the distance between start points; the distance between
962 */ 1110 */
963 #if DEBUG_ANGLE 1111 #if DEBUG_ANGLE
964 void SkOpAngle::debugCheckNearCoincidence() const { 1112 void SkOpAngle::debugCheckNearCoincidence() const {
965 const SkOpAngle* test = this; 1113 const SkOpAngle* test = this;
966 do { 1114 do {
967 const SkOpSegment* testSegment = test->segment(); 1115 const SkOpSegment* testSegment = test->segment();
968 double testStartT = test->start()->t(); 1116 double testStartT = test->start()->t();
969 SkDPoint testStartPt = testSegment->dPtAtT(testStartT); 1117 SkDPoint testStartPt = testSegment->dPtAtT(testStartT);
970 double testEndT = test->end()->t(); 1118 double testEndT = test->end()->t();
971 SkDPoint testEndPt = testSegment->dPtAtT(testEndT); 1119 SkDPoint testEndPt = testSegment->dPtAtT(testEndT);
(...skipping 17 matching lines...) Expand all
989 SkDebugf("%s testMidDistSq=%1.9g\n", __FUNCTION__, testMidDistSq); 1137 SkDebugf("%s testMidDistSq=%1.9g\n", __FUNCTION__, testMidDistSq);
990 SkDebugf("%s testEndDistSq=%1.9g\n", __FUNCTION__, testEndDistSq); 1138 SkDebugf("%s testEndDistSq=%1.9g\n", __FUNCTION__, testEndDistSq);
991 SkDebugf("%s nextMidDistSq=%1.9g\n", __FUNCTION__, nextMidDistSq); 1139 SkDebugf("%s nextMidDistSq=%1.9g\n", __FUNCTION__, nextMidDistSq);
992 SkDebugf("%s nextEndDistSq=%1.9g\n", __FUNCTION__, nextEndDistSq); 1140 SkDebugf("%s nextEndDistSq=%1.9g\n", __FUNCTION__, nextEndDistSq);
993 SkDPoint nextEndPt = nextSegment->dPtAtT(nextEndT); 1141 SkDPoint nextEndPt = nextSegment->dPtAtT(nextEndT);
994 double nextLenSq = nextStartPt.distanceSquared(nextEndPt); 1142 double nextLenSq = nextStartPt.distanceSquared(nextEndPt);
995 SkDebugf("%s nextLenSq=%1.9g\n", __FUNCTION__, nextLenSq); 1143 SkDebugf("%s nextLenSq=%1.9g\n", __FUNCTION__, nextLenSq);
996 SkDebugf("\n"); 1144 SkDebugf("\n");
997 } 1145 }
998 test = test->fNext; 1146 test = test->fNext;
999 } while (test->fNext != this); 1147 } while (test->fNext != this);
1000 } 1148 }
1001 #endif 1149 #endif
1002 1150
1003 #if DEBUG_ANGLE 1151 #if DEBUG_ANGLE
1004 SkString SkOpAngle::debugPart() const { 1152 SkString SkOpAngle::debugPart() const {
1005 SkString result; 1153 SkString result;
1006 switch (this->segment()->verb()) { 1154 switch (this->segment()->verb()) {
1007 case SkPath::kLine_Verb: 1155 case SkPath::kLine_Verb:
1008 result.printf(LINE_DEBUG_STR " id=%d", LINE_DEBUG_DATA(fCurvePart), 1156 result.printf(LINE_DEBUG_STR " id=%d", LINE_DEBUG_DATA(fCurvePart),
1009 this->segment()->debugID()); 1157 this->segment()->debugID());
(...skipping 29 matching lines...) Expand all
1039 } while (next && next != first); 1187 } while (next && next != first);
1040 next = first; 1188 next = first;
1041 do { 1189 do {
1042 next->debugValidate(); 1190 next->debugValidate();
1043 next = next->fNext; 1191 next = next->fNext;
1044 } while (next && next != first); 1192 } while (next && next != first);
1045 } 1193 }
1046 #endif 1194 #endif
1047 1195
1048 void SkOpAngle::debugValidate() const { 1196 void SkOpAngle::debugValidate() const {
1197 #if DEBUG_COINCIDENCE
1198 if (this->globalState()->debugCheckHealth()) {
1199 return;
1200 }
1201 #endif
1049 #if DEBUG_VALIDATE 1202 #if DEBUG_VALIDATE
1050 const SkOpAngle* first = this; 1203 const SkOpAngle* first = this;
1051 const SkOpAngle* next = this; 1204 const SkOpAngle* next = this;
1052 int wind = 0; 1205 int wind = 0;
1053 int opp = 0; 1206 int opp = 0;
1054 int lastXor = -1; 1207 int lastXor = -1;
1055 int lastOppXor = -1; 1208 int lastOppXor = -1;
1056 do { 1209 do {
1057 if (next->unorderable()) { 1210 if (next->unorderable()) {
1058 return; 1211 return;
(...skipping 42 matching lines...) Expand 10 before | Expand all | Expand 10 after
1101 break; 1254 break;
1102 } 1255 }
1103 SkASSERT_RELEASE(!angles.contains(next)); 1256 SkASSERT_RELEASE(!angles.contains(next));
1104 if (!next) { 1257 if (!next) {
1105 return; 1258 return;
1106 } 1259 }
1107 } while (true); 1260 } while (true);
1108 #endif 1261 #endif
1109 } 1262 }
1110 1263
1111 1264 #ifdef SK_DEBUG
1112 #if DEBUG_COINCIDENCE 1265 void SkCoincidentSpans::debugStartCheck(const SkOpSpanBase* outer, const SkOpSpa nBase* over,
1266 const SkOpGlobalState* debugState) const {
1267 SkASSERT(coinPtTEnd()->span() == over || !debugState->debugRunFail());
1268 SkASSERT(oppPtTEnd()->span() == outer || !debugState->debugRunFail());
1269 }
1270 #endif
1271
1272 #if DEBUG_COINCIDENCE_VERBOSE
1273 /* Commented-out lines keep this in sync with expand */
1274 bool SkCoincidentSpans::debugExpand(const char* id, SkPathOpsDebug::GlitchLog* l og) const {
1275 bool expanded = false;
1276 const SkOpSegment* segment = coinPtTStart()->segment();
1277 const SkOpSegment* oppSegment = oppPtTStart()->segment();
1278 do {
1279 const SkOpSpan* start = coinPtTStart()->span()->upCast();
1280 const SkOpSpan* prev = start->prev();
1281 const SkOpPtT* oppPtT;
1282 if (!prev || !(oppPtT = prev->contains(oppSegment))) {
1283 break;
1284 }
1285 double midT = (prev->t() + start->t()) / 2;
1286 if (!segment->isClose(midT, oppSegment)) {
1287 break;
1288 }
1289 if (log) log->record(kExpandCoin_Glitch, id, this, prev->ptT(), oppPtT);
1290 expanded = true;
1291 } while (false); // actual continues while expansion is possible
1292 do {
1293 const SkOpSpanBase* end = coinPtTEnd()->span();
1294 SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next();
1295 const SkOpPtT* oppPtT;
1296 if (!next || !(oppPtT = next->contains(oppSegment))) {
1297 break;
1298 }
1299 double midT = (end->t() + next->t()) / 2;
1300 if (!segment->isClose(midT, oppSegment)) {
1301 break;
1302 }
1303 if (log) log->record(kExpandCoin_Glitch, id, this, next->ptT(), oppPtT);
1304 expanded = true;
1305 } while (false); // actual continues while expansion is possible
1306 return expanded;
1307 }
1308
1309 #define FAIL_IF(cond) do { if (cond) log->record(kAddExpandedFail_Glitch, id, c oin); } while (false)
1310
1311 /* Commented-out lines keep this in sync with addExpanded */
1312 // for each coincident pair, match the spans
1313 // if the spans don't match, add the mssing pt to the segment and loop it in the opposite span
1113 void SkOpCoincidence::debugAddExpanded(const char* id, SkPathOpsDebug::GlitchLog * log) const { 1314 void SkOpCoincidence::debugAddExpanded(const char* id, SkPathOpsDebug::GlitchLog * log) const {
1114 // for each coincident pair, match the spans
1115 // if the spans don't match, add the mssing pt to the segment and loop it in the opposite span
1116 const SkCoincidentSpans* coin = this->fHead; 1315 const SkCoincidentSpans* coin = this->fHead;
1117 if (!coin) { 1316 if (!coin) {
1118 coin = this->fTop; 1317 return;
1119 } 1318 }
1120 if (!coin) { 1319 do {
1121 return; 1320 const SkOpPtT* startPtT = coin->coinPtTStart();
1122 } 1321 const SkOpPtT* oStartPtT = coin->oppPtTStart();
1123 do {
1124 const SkOpPtT* startPtT = coin->fCoinPtTStart;
1125 const SkOpPtT* oStartPtT = coin->fOppPtTStart;
1126 SkASSERT(startPtT->contains(oStartPtT)); 1322 SkASSERT(startPtT->contains(oStartPtT));
1127 SkASSERT(coin->fCoinPtTEnd->contains(coin->fOppPtTEnd)); 1323 SkASSERT(coin->coinPtTEnd()->contains(coin->oppPtTEnd()));
1128 const SkOpSpanBase* start = startPtT->span(); 1324 const SkOpSpanBase* start = startPtT->span();
1129 const SkOpSpanBase* oStart = oStartPtT->span(); 1325 const SkOpSpanBase* oStart = oStartPtT->span();
1130 const SkOpSpanBase* end = coin->fCoinPtTEnd->span(); 1326 const SkOpSpanBase* end = coin->coinPtTEnd()->span();
1131 const SkOpSpanBase* oEnd = coin->fOppPtTEnd->span(); 1327 const SkOpSpanBase* oEnd = coin->oppPtTEnd()->span();
1328 FAIL_IF(oEnd->deleted());
1132 const SkOpSpanBase* test = start->upCast()->next(); 1329 const SkOpSpanBase* test = start->upCast()->next();
1133 const SkOpSpanBase* oTest = coin->fFlipped ? oStart->prev() : oStart->up Cast()->next(); 1330 const SkOpSpanBase* oTest = coin->flipped() ? oStart->prev() : oStart->u pCast()->next();
1331 if (!oTest) {
1332 return;
1333 }
1134 while (test != end || oTest != oEnd) { 1334 while (test != end || oTest != oEnd) {
1135 bool bumpTest = true; 1335 if (!test->ptT()->contains(oTest->segment())
1136 bool bumpOTest = true; 1336 || !oTest->ptT()->contains(start->segment())) {
1137 if (!test->ptT()->contains(oTest->ptT())) {
1138 // use t ranges to guess which one is missing 1337 // use t ranges to guess which one is missing
1139 double startRange = coin->fCoinPtTEnd->fT - startPtT->fT; 1338 double startRange = coin->coinPtTEnd()->fT - startPtT->fT;
1339 FAIL_IF(!startRange);
1140 double startPart = (test->t() - startPtT->fT) / startRange; 1340 double startPart = (test->t() - startPtT->fT) / startRange;
1141 double oStartRange = coin->fOppPtTEnd->fT - oStartPtT->fT; 1341 double oStartRange = coin->oppPtTEnd()->fT - oStartPtT->fT;
1342 FAIL_IF(!oStartRange);
1142 double oStartPart = (oTest->t() - oStartPtT->fT) / oStartRange; 1343 double oStartPart = (oTest->t() - oStartPtT->fT) / oStartRange;
1143 if (startPart == oStartPart) { 1344 FAIL_IF(startPart == oStartPart);
1144 // data is corrupt 1345 bool startOver = false;
1145 log->record(kAddCorruptCoin_Glitch, id, start, oStart); 1346 if (startPart < oStartPart)
1146 break; 1347 log->record(kAddExpandedCoin_Glitch, id, // strange deb ug formatting lines up with original
1147 } 1348 oStartPtT->fT + oStartRange * startPart, test);
1148 if (startPart < oStartPart) { 1349 else log->record(kAddExpandedCoin_Glitch, id,
1149 double newT = oStartPtT->fT + oStartRange * startPart; 1350 startPtT->fT + startRange * oStartPart, oTest);
1150 log->record(kAddExpandedCoin_Glitch, id, oStart, newT, test- >pt()); 1351 if (false) {
1151 bumpOTest = false; 1352 SkASSERT(0);
1152 } else { 1353 return;
1153 double newT = startPtT->fT + startRange * oStartPart; 1354 }
1154 log->record(kAddExpandedCoin_Glitch, id, start, newT, oTest- >pt()); 1355 if (startOver) {
1155 bumpTest = false; 1356 test = start;
1156 } 1357 oTest = oStart;
1157 } 1358 }
1158 if (bumpTest && test != end) { 1359 }
1360 if (test != end) {
1159 test = test->upCast()->next(); 1361 test = test->upCast()->next();
1160 } 1362 }
1161 if (bumpOTest && oTest != oEnd) { 1363 if (oTest != oEnd) {
1162 oTest = coin->fFlipped ? oTest->prev() : oTest->upCast()->next() ; 1364 oTest = coin->flipped() ? oTest->prev() : oTest->upCast()->next( );
1163 } 1365 if (!oTest) {
1164 } 1366 return;
1165 } while ((coin = coin->fNext)); 1367 }
1166 } 1368 }
1167 1369 }
1168 static void t_range(const SkOpPtT* overS, const SkOpPtT* overE, double tStart, d ouble tEnd, 1370 } while ((coin = coin->next()));
1169 const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, double* coinTs, double* coinTe) { 1371 return;
1170 double denom = overE->fT - overS->fT; 1372 }
1171 double start = 0 < denom ? tStart : tEnd; 1373
1172 double end = 0 < denom ? tEnd : tStart; 1374 /* Commented-out lines keep this in sync with addIfMissing() */
1173 double sRatio = (start - overS->fT) / denom; 1375 void SkOpCoincidence::debugAddIfMissing(const SkCoincidentSpans* outer, const Sk OpPtT* over1s,
1174 double eRatio = (end - overS->fT) / denom; 1376 const SkOpPtT* over1e, const char* id, SkPathOpsDebug::GlitchLog* lo g) const {
1175 *coinTs = coinPtTStart->fT + (coinPtTEnd->fT - coinPtTStart->fT) * sRatio; 1377 // SkASSERT(fTop);
1176 *coinTe = coinPtTStart->fT + (coinPtTEnd->fT - coinPtTStart->fT) * eRatio; 1378 if (fTop && alreadyAdded(fTop, outer, over1s, over1e)) { // in debug, fTop may be null
1177 } 1379 return;
1178 1380 }
1179 bool SkOpCoincidence::debugAddIfMissing(const SkCoincidentSpans* outer, const Sk OpPtT* over1s, 1381 if (fHead && alreadyAdded(fHead, outer, over1s, over1e)) {
1180 const SkOpPtT* over1e) const { 1382 return;
1181 const SkCoincidentSpans* check = this->fTop; 1383 }
1182 while (check) { 1384 log->record(kAddIfMissingCoin_Glitch, id, outer->coinPtTStart(), outer->coin PtTEnd(), over1s, over1e);
1183 if (check->fCoinPtTStart->span() == over1s->span() 1385 this->debugValidate();
1184 && check->fOppPtTStart->span() == outer->fOppPtTStart->span()) { 1386 return;
1185 SkASSERT(check->fCoinPtTEnd->span() == over1e->span() 1387 }
1186 || !fDebugState->debugRunFail()); 1388
1187 SkASSERT(check->fOppPtTEnd->span() == outer->fOppPtTEnd->span() 1389 /* Commented-out lines keep this in sync addIfMissing() */
1188 || !fDebugState->debugRunFail()); 1390 void SkOpCoincidence::debugAddIfMissing(const SkOpPtT* over1s, const SkOpPtT* ov er1e,
1189 return false; 1391 const SkOpPtT* over2s, const SkOpPtT* over2e, double tStart, double tEnd ,
1190 } 1392 const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
1191 if (check->fCoinPtTStart->span() == outer->fCoinPtTStart->span() 1393 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd, const char* id, Sk PathOpsDebug::GlitchLog* log) const {
1192 && check->fOppPtTStart->span() == over1s->span()) {
1193 SkASSERT(check->fCoinPtTEnd->span() == outer->fCoinPtTEnd->span()
1194 || !fDebugState->debugRunFail());
1195 SkASSERT(check->fOppPtTEnd->span() == over1e->span()
1196 || !fDebugState->debugRunFail());
1197 return false;
1198 }
1199 check = check->fNext;
1200 }
1201 return true;
1202 }
1203
1204 bool SkOpCoincidence::debugAddIfMissing(const SkOpPtT* over1s, const SkOpPtT* ov er1e,
1205 const SkOpPtT* over2s, const SkOpPtT* over2e, double tStar t, double tEnd,
1206 SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
1207 SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const {
1208 double coinTs, coinTe, oppTs, oppTe; 1394 double coinTs, coinTe, oppTs, oppTe;
1209 t_range(over1s, over1e, tStart, tEnd, coinPtTStart, coinPtTEnd, &coinTs, &co inTe); 1395 TRange(over1s, over1e, tStart, tEnd, coinPtTStart, coinPtTEnd, &coinTs, &coi nTe);
1210 t_range(over2s, over2e, tStart, tEnd, oppPtTStart, oppPtTEnd, &oppTs, &oppTe ); 1396 TRange(over2s, over2e, tStart, tEnd, oppPtTStart, oppPtTEnd, &oppTs, &oppTe) ;
1397 bool swap = coinTs > coinTe;
1398 if (swap) {
1399 SkTSwap(coinTs, coinTe);
1400 }
1401 if ((over1s->fT < over1e->fT) != (over2s->fT < over2e->fT)) {
1402 SkTSwap(oppTs, oppTe);
1403 }
1404 if (swap) {
1405 SkTSwap(oppTs, oppTe);
1406 }
1211 const SkOpSegment* coinSeg = coinPtTStart->segment(); 1407 const SkOpSegment* coinSeg = coinPtTStart->segment();
1212 const SkOpSegment* oppSeg = oppPtTStart->segment(); 1408 const SkOpSegment* oppSeg = oppPtTStart->segment();
1213 SkASSERT(coinSeg != oppSeg); 1409 if (coinSeg == oppSeg) {
1214 const SkCoincidentSpans* check = this->fTop; 1410 return;
1215 ; 1411 }
1216 while (check) { 1412 return this->debugAddOrOverlap(coinSeg, oppSeg, coinTs, coinTe, oppTs, oppTe , id, log);
1217 const SkOpSegment* checkCoinSeg = check->fCoinPtTStart->segment(); 1413 }
1218 const SkOpSegment* checkOppSeg; 1414
1219 if (checkCoinSeg != coinSeg && checkCoinSeg != oppSeg) { 1415 /* Commented-out lines keep this in sync addOrOverlap() */
1220 goto next; 1416 void SkOpCoincidence::debugAddOrOverlap(const SkOpSegment* coinSeg, const SkOpSe gment* oppSeg,
1221 } 1417 double coinTs, double coinTe, double oppTs, double oppTe, const char* id , SkPathOpsDebug::GlitchLog* log) const {
1222 checkOppSeg = check->fOppPtTStart->segment(); 1418 SkTDArray<SkCoincidentSpans*> overlaps;
1223 if (checkOppSeg != coinSeg && checkOppSeg != oppSeg) { 1419 SkASSERT(!fTop); // this is (correctly) reversed in addifMissing()
1224 goto next; 1420 if (fTop && !this->checkOverlap(fTop, coinSeg, oppSeg, coinTs, coinTe, oppTs , oppTe, &overlaps)) {
1225 } 1421 return;
1226 { 1422 }
1227 int cTs = coinTs; 1423 if (fHead && !this->checkOverlap(fHead, coinSeg, oppSeg, coinTs,
1228 int cTe = coinTe; 1424 coinTe, oppTs, oppTe, &overlaps)) {
1229 int oTs = oppTs; 1425 return;
1230 int oTe = oppTe; 1426 }
1231 if (checkCoinSeg != coinSeg) { 1427 const SkCoincidentSpans* overlap = overlaps.count() ? overlaps[0] : nullptr;
1232 SkASSERT(checkOppSeg != oppSeg); 1428 for (int index = 1; index < overlaps.count(); ++index) { // combine overlaps before continuing
1233 SkTSwap(cTs, oTs); 1429 const SkCoincidentSpans* test = overlaps[index];
1234 SkTSwap(cTe, oTe); 1430 if (overlap->coinPtTStart()->fT > test->coinPtTStart()->fT) {
1235 } 1431 log->record(kAddOrOverlap_Glitch, id, overlap, test->coinPtTStart()) ;
1236 int tweenCount = (int) between(check->fCoinPtTStart->fT, cTs, check- >fCoinPtTEnd->fT) 1432 }
1237 + (int) between(check->fCoinPtTStart->fT, cTe, check- >fCoinPtTEnd->fT) 1433 if (overlap->coinPtTEnd()->fT < test->coinPtTEnd()->fT) {
1238 + (int) between(check->fOppPtTStart->fT, oTs, check-> fOppPtTEnd->fT) 1434 log->record(kAddOrOverlap_Glitch, id, overlap, test->coinPtTEnd());
1239 + (int) between(check->fOppPtTStart->fT, oTe, check-> fOppPtTEnd->fT); 1435 }
1240 // SkASSERT(tweenCount == 0 || tweenCount == 4); 1436 if (overlap->flipped()
1241 if (tweenCount) { 1437 ? overlap->oppPtTStart()->fT < test->oppPtTStart()->fT
1242 return true; 1438 : overlap->oppPtTStart()->fT > test->oppPtTStart()->fT) {
1243 } 1439 log->record(kAddOrOverlap_Glitch, id, overlap, test->oppPtTStart());
1244 } 1440 }
1245 next: 1441 if (overlap->flipped()
1246 check = check->fNext; 1442 ? overlap->oppPtTEnd()->fT > test->oppPtTEnd()->fT
1247 } 1443 : overlap->oppPtTEnd()->fT < test->oppPtTEnd()->fT) {
1248 if ((over1s->fT < over1e->fT) != (over2s->fT < over2e->fT)) { 1444 log->record(kAddOrOverlap_Glitch, id, overlap, test->oppPtTEnd());
1249 SkTSwap(oppTs, oppTe); 1445 }
1250 } 1446 if (!fHead) {
1251 if (coinTs > coinTe) { 1447 SkAssertResult(true);
1252 SkTSwap(coinTs, coinTe); 1448 }
1253 SkTSwap(oppTs, oppTe); 1449 }
1254 } 1450 const SkOpPtT* cs = coinSeg->existing(coinTs, oppSeg);
1255 bool cs = coinSeg->debugAddMissing(coinTs, oppSeg); 1451 const SkOpPtT* ce = coinSeg->existing(coinTe, oppSeg);
1256 bool ce = coinSeg->debugAddMissing(coinTe, oppSeg); 1452 if (overlap && cs && ce && overlap->contains(cs, ce)) {
1257 if (cs == ce) { 1453 return;
1258 return false; 1454 }
1259 } 1455 SkASSERT(cs != ce || !cs);
1260 return true; 1456 const SkOpPtT* os = oppSeg->existing(oppTs, coinSeg);
1261 } 1457 const SkOpPtT* oe = oppSeg->existing(oppTe, coinSeg);
1262 1458 if (overlap && os && oe && overlap->contains(os, oe)) {
1459 return;
1460 }
1461 SkASSERT(true || !cs || !cs->deleted());
1462 SkASSERT(true || !os || !os->deleted());
1463 SkASSERT(true || !ce || !ce->deleted());
1464 SkASSERT(true || !oe || !oe->deleted());
1465 const SkOpPtT* csExisting = !cs ? coinSeg->existing(coinTs, nullptr) : nullp tr;
1466 const SkOpPtT* ceExisting = !ce ? coinSeg->existing(coinTe, nullptr) : nullp tr;
1467 if (csExisting && csExisting == ceExisting) {
1468 return;
1469 }
1470 if (csExisting && (csExisting == ce || csExisting->contains(ceExisting ? ceE xisting : ce))) {
1471 return;
1472 }
1473 if (ceExisting && (ceExisting == cs || ceExisting->contains(csExisting ? csE xisting : cs))) {
1474 return;
1475 }
1476 const SkOpPtT* osExisting = !os ? oppSeg->existing(oppTs, nullptr) : nullptr ;
1477 const SkOpPtT* oeExisting = !oe ? oppSeg->existing(oppTe, nullptr) : nullptr ;
1478 if (osExisting && osExisting == oeExisting) {
1479 return;
1480 }
1481 if (osExisting && (osExisting == oe || osExisting->contains(oeExisting ? oeE xisting : oe))) {
1482 return;
1483 }
1484 if (oeExisting && (oeExisting == os || oeExisting->contains(osExisting ? osE xisting : os))) {
1485 return;
1486 }
1487 bool csDeleted = false, osDeleted = false, ceDeleted = false, oeDeleted = f alse;
1488 this->debugValidate();
1489 if (!cs || !os) {
1490 if (!cs)
1491 cs = coinSeg->debugAddT(coinTs, SkOpSegment::kNoAliasMatch, nullptr) ;
1492 if (!os)
1493 os = oppSeg->debugAddT(oppTs, SkOpSegment::kNoAliasMatch, nullptr);
1494 if (cs && os) cs->span()->debugAddOppAndMerge(id, log, os->span(), &csDe leted, &osDeleted);
1495 // cs = csWritable;
herb_g 2016/07/18 15:13:39 You have a bunch of commented out code in this rou
caryclark 2016/07/18 15:55:49 See reply above.
1496 // os = osWritable;
1497 if ((ce && ce->deleted()) || (oe && oe->deleted())) {
1498 return;
1499 }
1500 }
1501 if (!ce || !oe) {
1502 if (!ce)
1503 ce = coinSeg->debugAddT(coinTe, SkOpSegment::kNoAliasMatch, nullptr) ;
1504 if (!oe)
1505 oe = oppSeg->debugAddT(oppTe, SkOpSegment::kNoAliasMatch, nullptr);
1506 if (ce && oe) ce->span()->debugAddOppAndMerge(id, log, oe->span(), &ceDe leted, &oeDeleted);
1507 // ce = ceWritable;
1508 // oe = oeWritable;
1509 }
1510 this->debugValidate();
1511 if (csDeleted || osDeleted || ceDeleted || oeDeleted) {
1512 return;
1513 }
1514 if (!cs || !ce || cs->contains(ce) || !os || !oe || os->contains(oe)) {
1515 return;
1516 }
1517 // bool result = true;
1518 if (overlap) {
1519 if (overlap->coinPtTStart()->segment() == coinSeg) {
1520 log->record(kAddMissingExtend_Glitch, id, coinSeg, coinTs, coinT e, oppSeg, oppTs, oppTe);
1521 } else {
1522 if (oppTs > oppTe) {
1523 SkTSwap(coinTs, coinTe);
1524 SkTSwap(oppTs, oppTe);
1525 }
1526 log->record(kAddMissingExtend_Glitch, id, oppSeg, oppTs, oppTe, coin Seg, coinTs, coinTe);
1527 }
1528 #if DEBUG_COINCIDENCE_VERBOSE
1529 // if (result) {
1530 // overlap->debugShow();
1531 // }
1532 #endif
1533 } else {
1534 log->record(kAddMissingCoin_Glitch, id, coinSeg, coinTs, coinTe, oppSeg, oppTs, oppTe);
1535 #if DEBUG_COINCIDENCE_VERBOSE
1536 // fHead->debugShow();
1537 #endif
1538 }
1539 this->debugValidate();
1540 return;
1541 }
1542
1543 // Extra commented-out lines keep this in sync with addMissing()
1544 /* detects overlaps of different coincident runs on same segment */
1545 /* does not detect overlaps for pairs without any segments in common */
1546 // returns true if caller should loop again
1263 void SkOpCoincidence::debugAddMissing(const char* id, SkPathOpsDebug::GlitchLog* log) const { 1547 void SkOpCoincidence::debugAddMissing(const char* id, SkPathOpsDebug::GlitchLog* log) const {
1264 const SkCoincidentSpans* outer = fHead; 1548 const SkCoincidentSpans* outer = fHead;
1265 if (!outer) { 1549 if (!outer) {
1266 return; 1550 return;
1267 } 1551 }
1552 // bool added = false;
1553 // fTop = outer;
1554 // fHead = nullptr;
1268 do { 1555 do {
1269 // addifmissing can modify the list that this is walking 1556 // addifmissing can modify the list that this is walking
1270 // save head so that walker can iterate over old data unperturbed 1557 // save head so that walker can iterate over old data unperturbed
1271 // addifmissing adds to head freely then add saved head in the end 1558 // addifmissing adds to head freely then add saved head in the end
1272 const SkOpSegment* outerCoin = outer->fCoinPtTStart->segment(); 1559 const SkOpSegment* outerCoin = outer->coinPtTStart()->segment();
1273 SkASSERT(outerCoin == outer->fCoinPtTEnd->segment()); 1560 const SkOpSegment* outerOpp = outer->oppPtTStart()->segment();
1274 const SkOpSegment* outerOpp = outer->fOppPtTStart->segment(); 1561 if (outerCoin->done() || outerOpp->done()) {
1275 SkASSERT(outerOpp == outer->fOppPtTEnd->segment()); 1562 continue;
1563 }
1276 const SkCoincidentSpans* inner = outer; 1564 const SkCoincidentSpans* inner = outer;
1277 while ((inner = inner->fNext)) { 1565 while ((inner = inner->next())) {
1566 this->debugValidate();
1278 double overS, overE; 1567 double overS, overE;
1279 const SkOpSegment* innerCoin = inner->fCoinPtTStart->segment(); 1568 const SkOpSegment* innerCoin = inner->coinPtTStart()->segment();
1280 SkASSERT(innerCoin == inner->fCoinPtTEnd->segment()); 1569 const SkOpSegment* innerOpp = inner->oppPtTStart()->segment();
1281 const SkOpSegment* innerOpp = inner->fOppPtTStart->segment(); 1570 if (innerCoin->done() || innerOpp->done()) {
1282 SkASSERT(innerOpp == inner->fOppPtTEnd->segment()); 1571 continue;
1283 if (outerCoin == innerCoin 1572 }
1284 && this->overlap(outer->fCoinPtTStart, outer->fCoinPtTEnd, 1573 if (outerCoin == innerCoin) {
1285 inner->fCoinPtTStart, inner->fCoinPtTEnd, &overS, &overE)) { 1574 if (outerOpp != innerOpp
1286 if (this->debugAddIfMissing(outer->fCoinPtTStart, outer->fCoinPt TEnd, 1575 && this->overlap(outer->coinPtTStart(), outer->coinPtTEn d(),
1287 inner->fCoinPtTStart, inner->fCoinPtTEnd, overS, overE, 1576 inner->coinPtTStart(), inner->coinPtTEnd(), &overS, &ove rE)) {
1288 outer->fOppPtTStart, outer->fOppPtTEnd, 1577 this->debugAddIfMissing(outer->coinPtTStart(), outer->coinPt TEnd(),
1289 inner->fOppPtTStart, inner->fOppPtTEnd)) { 1578 inner->coinPtTStart(), inner->coinPtTEnd(), overS, o verE,
1290 log->record(kAddMissingCoin_Glitch, id, outer, inner->fCoinP tTStart); 1579 outer->oppPtTStart(), outer->oppPtTEnd(),
1291 } 1580 inner->oppPtTStart(), inner->oppPtTEnd(), id, log);
1292 } else if (outerCoin == innerOpp 1581 }
1293 && this->overlap(outer->fCoinPtTStart, outer->fCoinPtTEnd, 1582 } else if (outerCoin == innerOpp) {
1294 inner->fOppPtTStart, inner->fOppPtTEnd, &overS, &overE)) { 1583 if (outerOpp != innerCoin
1295 if (this->debugAddIfMissing(outer->fCoinPtTStart, outer->fCoinPt TEnd, 1584 && this->overlap(outer->coinPtTStart(), outer->coinPtTEn d(),
1296 inner->fOppPtTStart, inner->fOppPtTEnd, overS, overE, 1585 inner->oppPtTStart(), inner->oppPtTEnd(), &overS, &overE )) {
1297 outer->fOppPtTStart, outer->fOppPtTEnd, 1586 this->debugAddIfMissing(outer->coinPtTStart(), outer->coinPt TEnd(),
1298 inner->fCoinPtTStart, inner->fCoinPtTEnd)) { 1587 inner->oppPtTStart(), inner->oppPtTEnd(), overS, ove rE,
1299 log->record(kAddMissingCoin_Glitch, id, outer, inner->fOppPt TStart); 1588 outer->oppPtTStart(), outer->oppPtTEnd(),
1300 } 1589 inner->coinPtTStart(), inner->coinPtTEnd(), id, log) ;
1301 } else if (outerOpp == innerCoin 1590 }
1302 && this->overlap(outer->fOppPtTStart, outer->fOppPtTEnd, 1591 } else if (outerOpp == innerCoin) {
1303 inner->fCoinPtTStart, inner->fCoinPtTEnd, &overS, &overE)) { 1592 SkASSERT(outerCoin != innerOpp);
1304 if (this->debugAddIfMissing(outer->fOppPtTStart, outer->fOppPtTE nd, 1593 if (this->overlap(outer->oppPtTStart(), outer->oppPtTEnd(),
1305 inner->fCoinPtTStart, inner->fCoinPtTEnd, overS, overE, 1594 inner->coinPtTStart(), inner->coinPtTEnd(), &overS, &ove rE)) {
1306 outer->fCoinPtTStart, outer->fCoinPtTEnd, 1595 this->debugAddIfMissing(outer->oppPtTStart(), outer->oppPtTE nd(),
1307 inner->fOppPtTStart, inner->fOppPtTEnd)) { 1596 inner->coinPtTStart(), inner->coinPtTEnd(), overS, o verE,
1308 log->record(kAddMissingCoin_Glitch, id, outer, inner->fCoinP tTStart); 1597 outer->coinPtTStart(), outer->coinPtTEnd(),
1309 } 1598 inner->oppPtTStart(), inner->oppPtTEnd(), id, log);
1310 } else if (outerOpp == innerOpp 1599 }
1311 && this->overlap(outer->fOppPtTStart, outer->fOppPtTEnd, 1600 } else if (outerOpp == innerOpp) {
1312 inner->fOppPtTStart, inner->fOppPtTEnd, &overS, &overE)) { 1601 SkASSERT(outerCoin != innerCoin);
1313 if (this->debugAddIfMissing(outer->fOppPtTStart, outer->fOppPtTE nd, 1602 if (this->overlap(outer->oppPtTStart(), outer->oppPtTEnd(),
1314 inner->fOppPtTStart, inner->fOppPtTEnd, overS, overE, 1603 inner->oppPtTStart(), inner->oppPtTEnd(), &overS, &overE )) {
1315 outer->fCoinPtTStart, outer->fCoinPtTEnd, 1604 this->debugAddIfMissing(outer->oppPtTStart(), outer->oppPtTE nd(),
1316 inner->fCoinPtTStart, inner->fCoinPtTEnd)) { 1605 inner->oppPtTStart(), inner->oppPtTEnd(), overS, ove rE,
1317 log->record(kAddMissingCoin_Glitch, id, outer, inner->fOppPt TStart); 1606 outer->coinPtTStart(), outer->coinPtTEnd(),
1318 } 1607 inner->coinPtTStart(), inner->coinPtTEnd(), id, log) ;
1319 } else if (outerCoin != innerCoin) { 1608 }
1320 // check to see if outer span overlaps the inner span 1609 }
1321 // look for inner segment in pt-t list 1610 this->debugValidate();
1322 // if present, and if t values are in coincident range 1611 }
1323 // add two pairs of new coincidence 1612 } while ((outer = outer->next()));
1324 const SkOpPtT* testS = outer->fCoinPtTStart->debugContains(inner Coin); 1613 // this->restoreHead();
1325 const SkOpPtT* testE = outer->fCoinPtTEnd->debugContains(innerCo in); 1614 return;
1326 if (testS && testS->fT >= inner->fCoinPtTStart->fT 1615 }
1327 && testE && testE->fT <= inner->fCoinPtTEnd->fT 1616
1328 && this->testForCoincidence(outer, testS, testE)) { 1617 // Commented-out lines keep this in sync with release()
1329 if (this->debugAddIfMissing(outer, testS, testE)) { 1618 void SkOpCoincidence::debugRelease(const char* id, SkPathOpsDebug::GlitchLog* lo g, const SkOpSegment* deleted) const {
1330 log->record(kAddMissingCoin_Glitch, id, outer, testS, te stE); 1619 const SkCoincidentSpans* coin = fHead;
1331 } 1620 if (!coin) {
1332 } else { 1621 return;
1333 testS = inner->fCoinPtTStart->debugContains(outerCoin); 1622 }
1334 testE = inner->fCoinPtTEnd->debugContains(outerCoin); 1623 do {
1335 if (testS && testS->fT >= outer->fCoinPtTStart->fT 1624 if (coin->coinPtTStart()->segment() == deleted
1336 && testE && testE->fT <= outer->fCoinPtTEnd->fT 1625 || coin->coinPtTEnd()->segment() == deleted
1337 && this->testForCoincidence(inner, testS, testE)) { 1626 || coin->oppPtTStart()->segment() == deleted
1338 if (this->debugAddIfMissing(inner, testS, testE)) { 1627 || coin->oppPtTEnd()->segment() == deleted) {
1339 log->record(kAddMissingCoin_Glitch, id, inner, testS , testE); 1628 log->record(kReleasedSpan_Glitch, id, coin);
1340 } 1629 }
1341 } 1630 } while ((coin = coin->next()));
1342 } 1631 }
1343 } 1632
1344 } 1633 // Commented-out lines keep this in sync with reorder()
1345 } while ((outer = outer->fNext)); 1634 // iterate through all coincident pairs, looking for ranges greater than 1
1346 } 1635 // if found, see if the opposite pair can match it -- which may require
1347 1636 // reordering the ptT pairs
1637 void SkOpCoincidence::debugReorder(const char* id, SkPathOpsDebug::GlitchLog* lo g) const {
1638 const SkCoincidentSpans* coin = fHead;
1639 if (!coin) {
1640 return;
1641 }
1642 do {
1643 // most commonly, concidence are one span long; check for that first
1644 int intervals = coin->spanCount();
1645 if (intervals = 1) {
1646 #if DEBUG_COINCIDENCE_VERBOSE
1647 // SkASSERT(!coin->debugExpand(nullptr, nullptr));
1648 #endif
1649 continue;
1650 }
1651 coin->debugExpand(id, log);
1652 if (coin->spanCount() <= 0) {
1653 return;
1654 }
1655 // check to see if every span in coin has a mate in opp
1656 const SkOpSpan* start = coin->coinPtTStart()->span()->upCast();
1657 bool flipped = coin->flipped();
1658 const SkOpSpanBase* oppStartBase = coin->oppPtTStart()->span();
1659 const SkOpSpan* oppStart = flipped ? oppStartBase->prev() : oppStartBase ->upCast();
1660 SkDebugf("", start, oppStart);
1661 } while ((coin = coin->next()));
1662 return;
1663 }
1664
1665 // Commented-out lines keep this in sync with expand()
1666 // expand the range by checking adjacent spans for coincidence
1348 bool SkOpCoincidence::debugExpand(const char* id, SkPathOpsDebug::GlitchLog* log ) const { 1667 bool SkOpCoincidence::debugExpand(const char* id, SkPathOpsDebug::GlitchLog* log ) const {
1349 const SkCoincidentSpans* coin = fHead; 1668 const SkCoincidentSpans* coin = fHead;
1350 if (!coin) { 1669 if (!coin) {
1351 return false; 1670 return false;
1352 } 1671 }
1353 bool expanded = false; 1672 bool expanded = false;
1354 do { 1673 do {
1355 const SkOpSpan* start = coin->fCoinPtTStart->span()->upCast(); 1674 if (coin->debugExpand(id, log)) {
1356 const SkOpSpanBase* end = coin->fCoinPtTEnd->span(); 1675 // check to see if multiple spans expanded so they are now identical
1357 const SkOpSegment* segment = coin->fCoinPtTStart->segment(); 1676 const SkCoincidentSpans* test = fHead;
1358 const SkOpSegment* oppSegment = coin->fOppPtTStart->segment(); 1677 do {
1359 const SkOpSpan* prev = start->prev(); 1678 if (coin == test) {
1360 if (prev && prev->debugContains(oppSegment)) { 1679 continue;
1361 double midT = (prev->t() + start->t()) / 2; 1680 }
1362 if (segment->isClose(midT, oppSegment)) { 1681 if (coin->coinPtTStart() == test->coinPtTStart()
1363 log->record(kExpandCoin_Glitch, id, coin, prev); 1682 && coin->oppPtTStart() == test->oppPtTStart()) {
1364 } 1683 if (log) log->record(kExpandCoin_Glitch, id, fHead, test->co inPtTStart());
1365 } 1684 break;
1366 SkOpSpanBase* next = end->final() ? nullptr : end->upCast()->next(); 1685 }
1367 if (next && next->debugContains(oppSegment)) { 1686 } while ((test = test->next()));
1368 double midT = (end->t() + next->t()) / 2; 1687 expanded = true;
1369 if (segment->isClose(midT, oppSegment)) { 1688 }
1370 log->record(kExpandCoin_Glitch, id, coin, next); 1689 } while ((coin = coin->next()));
1371 }
1372 }
1373 } while ((coin = coin->fNext));
1374 return expanded; 1690 return expanded;
1375 } 1691 }
1376 1692
1377 void SkOpCoincidence::debugFixAligned(const char* id, SkPathOpsDebug::GlitchLog* log) const { 1693 // Commented-out lines keep this in sync with removeCollapsed()
1694 void SkOpCoincidence::debugRemoveCollapsed(const char* id, SkPathOpsDebug::Glitc hLog* log) const {
1378 const SkCoincidentSpans* coin = fHead; 1695 const SkCoincidentSpans* coin = fHead;
1379 if (!coin) { 1696 if (!coin) {
1380 return; 1697 return;
1381 } 1698 }
1382 do { 1699 // SkCoincidentSpans** priorPtr = &fHead;
1383 if (coin->fCoinPtTStart->deleted()) { 1700 do {
1384 log->record(kDeletedCoin_Glitch, id, coin, coin->fCoinPtTStart); 1701 if (coin->coinPtTStart() == coin->coinPtTEnd()) {
1385 } 1702 return;
1386 if (coin->fCoinPtTEnd->deleted()) { 1703 }
1387 log->record(kDeletedCoin_Glitch, id, coin, coin->fCoinPtTEnd); 1704 if (coin->oppPtTStart() == coin->oppPtTEnd()) {
1388 } 1705 return;
1389 if (coin->fOppPtTStart->deleted()) { 1706 }
1390 log->record(kDeletedCoin_Glitch, id, coin, coin->fOppPtTStart); 1707 if (coin->coinPtTStart()->collapsed(coin->coinPtTEnd())) {
1391 } 1708 log->record(kCollapsedCoin_Glitch, id, coin);
1392 if (coin->fOppPtTEnd->deleted()) { 1709 // continue;
1393 log->record(kDeletedCoin_Glitch, id, coin, coin->fOppPtTEnd); 1710 }
1394 } 1711 if (coin->oppPtTStart()->collapsed(coin->oppPtTEnd())) {
1395 } while ((coin = coin->fNext)); 1712 log->record(kCollapsedCoin_Glitch, id, coin, coin);
1396 coin = fHead; 1713 // continue;
1397 do { 1714 }
1398 if (coin->fCoinPtTStart->collapsed(coin->fCoinPtTEnd)) { 1715 // priorPtr = &coin->nextPtr();
1399 log->record(kCollapsedCoin_Glitch, id, coin, coin->fCoinPtTStart); 1716 } while ((coin = coin->next()));
1400 } 1717 return;
1401 if (coin->fOppPtTStart->collapsed(coin->fOppPtTEnd)) { 1718 }
1402 log->record(kCollapsedCoin_Glitch, id, coin, coin->fOppPtTStart); 1719
1403 } 1720 // Commented-out lines keep this in sync with mark()
1404 } while ((coin = coin->fNext)); 1721 /* this sets up the coincidence links in the segments when the coincidence cross es multiple spans */
1405 }
1406
1407 void SkOpCoincidence::debugMark(const char* id, SkPathOpsDebug::GlitchLog* log) const { 1722 void SkOpCoincidence::debugMark(const char* id, SkPathOpsDebug::GlitchLog* log) const {
1408 const SkCoincidentSpans* coin = fHead; 1723 const SkCoincidentSpans* coin = fHead;
1409 if (!coin) { 1724 if (!coin) {
1410 return; 1725 return;
1411 } 1726 }
1412 do { 1727 do {
1413 const SkOpSpanBase* end = coin->fCoinPtTEnd->span(); 1728 const SkOpSpan* start = coin->coinPtTStartWritable()->span()->upCast();
1414 const SkOpSpanBase* oldEnd = end; 1729 // SkASSERT(start->deleted());
1415 const SkOpSpan* start = coin->fCoinPtTStart->span()->debugStarter(&end); 1730 const SkOpSpanBase* end = coin->coinPtTEndWritable()->span();
1416 const SkOpSpanBase* oEnd = coin->fOppPtTEnd->span(); 1731 // SkASSERT(end->deleted());
1417 const SkOpSpanBase* oOldEnd = oEnd; 1732 const SkOpSpanBase* oStart = coin->oppPtTStartWritable()->span();
1418 const SkOpSpanBase* oStart = coin->fOppPtTStart->span()->debugStarter(&o End); 1733 // SkASSERT(oStart->deleted());
1419 bool flipped = (end == oldEnd) != (oEnd == oOldEnd); 1734 const SkOpSpanBase* oEnd = coin->oppPtTEndWritable()->span();
1735 // SkASSERT(oEnd->deleted());
1736 bool flipped = coin->flipped();
1420 if (flipped) { 1737 if (flipped) {
1421 SkTSwap(oStart, oEnd); 1738 SkTSwap(oStart, oEnd);
1422 } 1739 }
1740 /* coin and opp spans may not match up. Mark the ends, and then let the interior
1741 get marked as many times as the spans allow */
1742 start->debugInsertCoincidence(id, log, oStart->upCast());
1743 end->debugInsertCoinEnd(id, log, oEnd);
1744 const SkOpSegment* segment = start->segment();
1745 const SkOpSegment* oSegment = oStart->segment();
1423 const SkOpSpanBase* next = start; 1746 const SkOpSpanBase* next = start;
1424 const SkOpSpanBase* oNext = oStart; 1747 const SkOpSpanBase* oNext = oStart;
1748 while ((next = next->upCast()->next()) != end) {
1749 if (next->upCast()->debugInsertCoincidence(id, log, oSegment, flippe d), false) {
1750 return;
1751 }
1752 }
1753 while ((oNext = oNext->upCast()->next()) != oEnd) {
1754 if (oNext->upCast()->debugInsertCoincidence(id, log, segment, flippe d), false) {
1755 return;
1756 }
1757 }
1758 } while ((coin = coin->next()));
1759 return;
1760 }
1761 #endif
1762
1763 #if DEBUG_COINCIDENCE_VERBOSE
1764 // Commented-out lines keep this in sync with markCollapsed()
1765 void SkOpCoincidence::debugMarkCollapsed(const char* id, SkPathOpsDebug::GlitchL og* log, const SkCoincidentSpans* coin, const SkOpPtT* test) const {
1766 while (coin) {
1767 if (coin->collapsed(test)) {
1768 if (zero_or_one(coin->coinPtTStart()->fT) && zero_or_one(coin->coinP tTEnd()->fT)) {
1769 log->record(kCollapsedCoin_Glitch, id, coin);
1770 }
1771 if (zero_or_one(coin->oppPtTStart()->fT) && zero_or_one(coin->oppPtT End()->fT)) {
1772 log->record(kCollapsedCoin_Glitch, id, coin);
1773 }
1774 }
1775 coin = coin->next();
1776 }
1777 }
1778
1779 // Commented-out lines keep this in sync with markCollapsed()
1780 void SkOpCoincidence::debugMarkCollapsed(const char* id, SkPathOpsDebug::GlitchL og* log, const SkOpPtT* test) const {
1781 this->debugMarkCollapsed(id, log, fHead, test);
1782 this->debugMarkCollapsed(id, log, fTop, test);
1783 }
1784 #endif
1785
1786 void SkCoincidentSpans::debugShow() const {
1787 SkDebugf("%s - id=%d t=%1.9g tEnd=%1.9g\n", __FUNCTION__,
1788 coinPtTStart()->segment()->debugID(),
1789 coinPtTStart()->fT, coinPtTEnd()->fT);
1790 SkDebugf("%s + id=%d t=%1.9g tEnd=%1.9g\n", __FUNCTION__,
1791 oppPtTStart()->segment()->debugID(),
1792 oppPtTStart()->fT, oppPtTEnd()->fT);
1793 }
1794
1795 void SkOpCoincidence::debugShowCoincidence() const {
1796 #if DEBUG_COINCIDENCE
1797 const SkCoincidentSpans* span = fHead;
1798 while (span) {
1799 span->debugShow();
1800 span = span->next();
1801 }
1802 #endif
1803 }
1804
1805 #if DEBUG_COINCIDENCE
1806 static void DebugValidate(const SkOpSpanBase* next, const SkOpSpanBase* end,
1807 double oStart, double oEnd, const SkOpSegment* oSegment,
1808 const char* id, SkPathOpsDebug::GlitchLog* log) {
1809 SkASSERT(next != end);
1810 SkASSERT(!next->contains(end) || log);
1811 if (next->t() > end->t()) {
1812 SkTSwap(next, end);
1813 }
1814 do {
1815 const SkOpPtT* ptT = next->ptT();
1816 int index = 0;
1817 bool somethingBetween;
1425 do { 1818 do {
1426 next = next->upCast()->next(); 1819 ++index;
1427 oNext = flipped ? oNext->prev() : oNext->upCast()->next(); 1820 ptT = ptT->next();
1428 if (next == end || oNext == oEnd) { 1821 const SkOpPtT* checkPtT = next->ptT();
1822 if (ptT == checkPtT) {
1429 break; 1823 break;
1430 } 1824 }
1431 if (!next->containsCoinEnd(oNext)) { 1825 bool looped = false;
1432 log->record(kMarkCoinEnd_Glitch, id, next, oNext); 1826 for (int check = 0; check < index; ++check) {
1433 } 1827 if ((looped = checkPtT == ptT)) {
1434 const SkOpSpan* nextSpan = next->upCast(); 1828 break;
1435 const SkOpSpan* oNextSpan = oNext->upCast(); 1829 }
1436 if (!nextSpan->containsCoincidence(oNextSpan)) { 1830 checkPtT = checkPtT->next();
1437 log->record(kMarkCoinInsert_Glitch, id, nextSpan, oNextSpan); 1831 }
1438 } 1832 if (looped) {
1833 SkASSERT(0);
1834 break;
1835 }
1836 if (ptT->deleted()) {
1837 continue;
1838 }
1839 if (ptT->segment() != oSegment) {
1840 continue;
1841 }
1842 somethingBetween |= between(oStart, ptT->fT, oEnd);
1439 } while (true); 1843 } while (true);
1440 } while ((coin = coin->fNext)); 1844 SkASSERT(somethingBetween);
1441 } 1845 } while (next != end && (next = next->upCast()->next()));
1442 #endif 1846 }
1443 1847
1444 void SkOpCoincidence::debugShowCoincidence() const { 1848 static void DebugCheckOverlap(const SkCoincidentSpans* test, const SkCoincidentS pans* list,
1445 SkCoincidentSpans* span = fHead; 1849 const char* id, SkPathOpsDebug::GlitchLog* log) {
1446 while (span) { 1850 if (!list) {
1447 SkDebugf("%s - id=%d t=%1.9g tEnd=%1.9g\n", __FUNCTION__, 1851 return;
1448 span->fCoinPtTStart->segment()->debugID(), 1852 }
1449 span->fCoinPtTStart->fT, span->fCoinPtTEnd->fT); 1853 const SkOpSegment* coinSeg = test->coinPtTStart()->segment();
1450 SkDebugf("%s + id=%d t=%1.9g tEnd=%1.9g\n", __FUNCTION__, 1854 SkASSERT(coinSeg == test->coinPtTEnd()->segment());
1451 span->fOppPtTStart->segment()->debugID(), 1855 const SkOpSegment* oppSeg = test->oppPtTStart()->segment();
1452 span->fOppPtTStart->fT, span->fOppPtTEnd->fT); 1856 SkASSERT(oppSeg == test->oppPtTEnd()->segment());
1453 span = span->fNext; 1857 SkASSERT(coinSeg != test->oppPtTStart()->segment());
1454 } 1858 SkDEBUGCODE(double tcs = test->coinPtTStart()->fT);
1455 } 1859 SkASSERT(between(0, tcs, 1));
1456 1860 SkDEBUGCODE(double tce = test->coinPtTEnd()->fT);
1861 SkASSERT(between(0, tce, 1));
1862 SkASSERT(tcs < tce);
1863 double tos = test->oppPtTStart()->fT;
1864 SkASSERT(between(0, tos, 1));
1865 double toe = test->oppPtTEnd()->fT;
1866 SkASSERT(between(0, toe, 1));
1867 SkASSERT(tos != toe);
1868 if (tos > toe) {
1869 SkTSwap(tos, toe);
1870 }
1871 do {
1872 double lcs, lce, los, loe;
1873 if (coinSeg == list->coinPtTStart()->segment()) {
1874 if (oppSeg != list->oppPtTStart()->segment()) {
1875 continue;
1876 }
1877 lcs = list->coinPtTStart()->fT;
1878 lce = list->coinPtTEnd()->fT;
1879 los = list->oppPtTStart()->fT;
1880 loe = list->oppPtTEnd()->fT;
1881 if (los > loe) {
1882 SkTSwap(los, loe);
1883 }
1884 } else if (coinSeg == list->oppPtTStart()->segment()) {
1885 if (oppSeg != list->coinPtTStart()->segment()) {
1886 continue;
1887 }
1888 lcs = list->oppPtTStart()->fT;
1889 lce = list->oppPtTEnd()->fT;
1890 if (lcs > lce) {
1891 SkTSwap(lcs, lce);
1892 }
1893 los = list->coinPtTStart()->fT;
1894 loe = list->coinPtTEnd()->fT;
1895 } else {
1896 continue;
1897 }
1898 SkASSERT(tce < lcs || lce < tcs);
1899 SkASSERT(toe < los || loe < tos);
1900 } while ((list = list->next()));
1901 }
1902
1903
1904 static void DebugCheckOverlapTop(const SkCoincidentSpans* head, const SkCoincide ntSpans* opt,
1905 const char* id, SkPathOpsDebug::GlitchLog* log) {
1906 // check for overlapping coincident spans
1907 const SkCoincidentSpans* test = head;
1908 while (test) {
1909 const SkCoincidentSpans* next = test->next();
1910 DebugCheckOverlap(test, next, id, log);
1911 DebugCheckOverlap(test, opt, id, log);
1912 test = next;
1913 }
1914 }
1915
1916 #if DEBUG_COINCIDENCE_VERBOSE
1917 void SkOpCoincidence::debugCheckOverlap(const char* id, SkPathOpsDebug::GlitchLo g* log) const {
1918 DebugCheckOverlapTop(fHead, fTop, id, log);
1919 DebugCheckOverlapTop(fTop, nullptr, id, log);
1920 }
1921 #endif
1922
1923 static void DebugValidate(const SkCoincidentSpans* head, const SkCoincidentSpans * opt,
1924 const char* id, SkPathOpsDebug::GlitchLog* log) {
1925 // look for pts inside coincident spans that are not inside the opposite spa ns
1926 const SkCoincidentSpans* coin = head;
1927 while (coin) {
1928 SkASSERT(SkOpCoincidence::Ordered(coin->coinPtTStart()->segment(),
1929 coin->oppPtTStart()->segment()));
1930 SkASSERT(coin->coinPtTStart()->span()->ptT() == coin->coinPtTStart());
1931 SkASSERT(coin->coinPtTEnd()->span()->ptT() == coin->coinPtTEnd());
1932 SkASSERT(coin->oppPtTStart()->span()->ptT() == coin->oppPtTStart());
1933 SkASSERT(coin->oppPtTEnd()->span()->ptT() == coin->oppPtTEnd());
1934 DebugValidate(coin->coinPtTStart()->span(), coin->coinPtTEnd()->span(),
1935 coin->oppPtTStart()->fT, coin->oppPtTEnd()->fT, coin->oppPtTStar t()->segment(),
1936 id, log);
1937 DebugValidate(coin->oppPtTStart()->span(), coin->oppPtTEnd()->span(),
1938 coin->coinPtTStart()->fT, coin->coinPtTEnd()->fT, coin->coinPtTS tart()->segment(),
1939 id, log);
1940 coin = coin->next();
1941 }
1942 DebugCheckOverlapTop(head, opt, id, log);
1943 }
1944 #endif
1945
1946 void SkOpCoincidence::debugValidate() const {
1457 #if DEBUG_COINCIDENCE 1947 #if DEBUG_COINCIDENCE
1948 // if (fGlobalState->debugCheckHealth()) {
1949 // return;
1950 // }
1951 DebugValidate(fHead, fTop, nullptr, nullptr);
1952 DebugValidate(fTop, nullptr, nullptr, nullptr);
1953 #endif
1954 }
1955
1956 #if DEBUG_COINCIDENCE_VERBOSE
1957 void SkOpCoincidence::debugCheckValid(const char* id, SkPathOpsDebug::GlitchLog* log) const {
1958 DebugValidate(fHead, fTop, id, log);
1959 DebugValidate(fTop, nullptr, id, log);
1960 }
1961 #endif
1962
1963 #if DEBUG_COINCIDENCE_VERBOSE
1458 void SkOpContour::debugCheckHealth(const char* id, SkPathOpsDebug::GlitchLog* lo g) const { 1964 void SkOpContour::debugCheckHealth(const char* id, SkPathOpsDebug::GlitchLog* lo g) const {
1459 const SkOpSegment* segment = &fHead; 1965 const SkOpSegment* segment = &fHead;
1460 do { 1966 do {
1461 segment->debugCheckHealth(id, log); 1967 segment->debugCheckHealth(id, log);
1462 } while ((segment = segment->next())); 1968 } while ((segment = segment->next()));
1463 } 1969 }
1464 1970
1465 void SkOpContour::debugMissingCoincidence(const char* id, SkPathOpsDebug::Glitch Log* log, 1971 // commmented-out lines keep this aligned with missingCoincidence()
1466 const SkOpCoincidence* coincidence) const { 1972 void SkOpContour::debugMissingCoincidence(const char* id, SkPathOpsDebug::Glitch Log* log) const {
1973 // SkASSERT(fCount > 0);
1467 const SkOpSegment* segment = &fHead; 1974 const SkOpSegment* segment = &fHead;
1975 // bool result = false;
1468 do { 1976 do {
1469 segment->debugMissingCoincidence(id, log, coincidence); 1977 if (fState->angleCoincidence()) {
1470 } while ((segment = segment->next())); 1978 // #if DEBUG_ANGLE
1979 // segment->debugCheckAngleCoin();
1980 // #endif
1981 } else if (segment->debugMissingCoincidence(id, log), false) {
1982 // result = true;
1983 // see FIXME in missingCoincidence()
1984 //
1985 //
1986 //
1987 // continue;
1988 }
1989 segment = segment->next();
1990 } while (segment);
1991 return;
1471 } 1992 }
1472 #endif 1993 #endif
1473 1994
1474 void SkOpSegment::debugValidate() const { 1995 void SkOpSegment::debugValidate() const {
1996 #if DEBUG_COINCIDENCE
1997 if (this->globalState()->debugCheckHealth()) {
1998 return;
1999 }
2000 #endif
1475 #if DEBUG_VALIDATE 2001 #if DEBUG_VALIDATE
1476 const SkOpSpanBase* span = &fHead; 2002 const SkOpSpanBase* span = &fHead;
1477 double lastT = -1; 2003 double lastT = -1;
1478 const SkOpSpanBase* prev = nullptr; 2004 const SkOpSpanBase* prev = nullptr;
1479 int count = 0; 2005 int count = 0;
1480 int done = 0; 2006 int done = 0;
1481 do { 2007 do {
1482 if (!span->final()) { 2008 if (!span->final()) {
1483 ++count; 2009 ++count;
1484 done += span->upCast()->done() ? 1 : 0; 2010 done += span->upCast()->done() ? 1 : 0;
1485 } 2011 }
1486 SkASSERT(span->segment() == this); 2012 SkASSERT(span->segment() == this);
1487 SkASSERT(!prev || prev->upCast()->next() == span); 2013 SkASSERT(!prev || prev->upCast()->next() == span);
1488 SkASSERT(!prev || prev == span->prev()); 2014 SkASSERT(!prev || prev == span->prev());
1489 prev = span; 2015 prev = span;
1490 double t = span->ptT()->fT; 2016 double t = span->ptT()->fT;
1491 SkASSERT(lastT < t); 2017 SkASSERT(lastT < t);
1492 lastT = t; 2018 lastT = t;
1493 span->debugValidate(); 2019 span->debugValidate();
1494 } while (!span->final() && (span = span->upCast()->next())); 2020 } while (!span->final() && (span = span->upCast()->next()));
1495 SkASSERT(count == fCount); 2021 SkASSERT(count == fCount);
1496 SkASSERT(done == fDoneCount); 2022 SkASSERT(done == fDoneCount);
1497 SkASSERT(count >= fDoneCount); 2023 SkASSERT(count >= fDoneCount);
1498 SkASSERT(span->final()); 2024 SkASSERT(span->final());
1499 span->debugValidate(); 2025 span->debugValidate();
1500 #endif 2026 #endif
1501 } 2027 }
1502 2028
1503 bool SkOpSpanBase::debugAlignedEnd(double t, const SkPoint& pt) const { 2029 #if DEBUG_COINCIDENCE_VERBOSE
1504 SkASSERT(zero_or_one(t)); 2030 // Commented-out lines keep this in sync with addOppAndMerge()
1505 const SkOpSegment* segment = this->segment(); 2031 // If the added points envelop adjacent spans, merge them in.
1506 SkASSERT(t ? segment->lastPt() == pt : segment->pts()[0] == pt); 2032 void SkOpSpanBase::debugAddOppAndMerge(const char* id, SkPathOpsDebug::GlitchLog * log, const SkOpSpanBase* opp, bool* spanDeleted, bool* oppDeleted) const {
1507 if (!debugAlignedInner()) { 2033 if (this->ptT()->debugAddOpp(opp->ptT())) {
1508 return false; 2034 this->debugCheckForCollapsedCoincidence(id, log);
1509 } 2035 }
1510 if ((t ? segment->lastPt() : segment->pts()[0]) != pt) { 2036 // compute bounds of points in span
1511 return false; 2037 SkPathOpsBounds bounds;
2038 bounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin);
2039 const SkOpPtT* head = this->ptT();
2040 const SkOpPtT* nextPt = head;
2041 do {
2042 bounds.add(nextPt->fPt);
2043 } while ((nextPt = nextPt->next()) != head);
2044 if (!bounds.width() && !bounds.height()) {
2045 return;
1512 } 2046 }
1513 const SkOpPtT* ptT = &this->fPtT; 2047 this->debugMergeContained(id, log, bounds, spanDeleted);
1514 SkASSERT(t == ptT->fT); 2048 opp->debugMergeContained(id, log, bounds, oppDeleted);
1515 SkASSERT(pt == ptT->fPt); 2049 }
1516 const SkOpPtT* test = ptT, * stopPtT = ptT; 2050
1517 while ((test = test->next()) != stopPtT) { 2051 // Commented-out lines keep this in sync with checkForCollapsedCoincidence()
1518 const SkOpSegment* other = test->segment(); 2052 void SkOpSpanBase::debugCheckForCollapsedCoincidence(const char* id, SkPathOpsDe bug::GlitchLog* log) const {
1519 if (other == this->segment()) { 2053 const SkOpCoincidence* coins = this->globalState()->coincidence();
2054 if (coins->isEmpty()) {
2055 return;
2056 }
2057 // the insert above may have put both ends of a coincident run in the same span
2058 // for each coincident ptT in loop; see if its opposite in is also in the loop
2059 // this implementation is the motivation for marking that a ptT is referenced by a coincident span
2060 const SkOpPtT* head = this->ptT();
2061 const SkOpPtT* test = head;
2062 do {
2063 if (!test->coincident()) {
1520 continue; 2064 continue;
1521 } 2065 }
1522 if (!zero_or_one(test->fT)) { 2066 coins->debugMarkCollapsed(id, log, test);
1523 continue; 2067 } while ((test = test->next()) != head);
1524 }
1525 if ((test->fT ? other->lastPt() : other->pts()[0]) != pt) {
1526 return false;
1527 }
1528 }
1529 return this->fAligned;
1530 } 2068 }
1531 2069 #endif
1532 bool SkOpSpanBase::debugAlignedInner() const {
1533 // force the spans to share points and t values
1534 const SkOpPtT* ptT = &this->fPtT, * stopPtT = ptT;
1535 const SkPoint& pt = ptT->fPt;
1536 do {
1537 if (ptT->fPt != pt) {
1538 return false;
1539 }
1540 const SkOpSpanBase* span = ptT->span();
1541 const SkOpPtT* test = ptT;
1542 do {
1543 if ((test = test->next()) == stopPtT) {
1544 break;
1545 }
1546 if (span == test->span() && !span->segment()->ptsDisjoint(*ptT, *tes t)) {
1547 return false;
1548 }
1549 } while (true);
1550 } while ((ptT = ptT->next()) != stopPtT);
1551 return true;
1552 }
1553 2070
1554 bool SkOpSpanBase::debugCoinEndLoopCheck() const { 2071 bool SkOpSpanBase::debugCoinEndLoopCheck() const {
1555 int loop = 0; 2072 int loop = 0;
1556 const SkOpSpanBase* next = this; 2073 const SkOpSpanBase* next = this;
1557 SkOpSpanBase* nextCoin; 2074 SkOpSpanBase* nextCoin;
1558 do { 2075 do {
1559 nextCoin = next->fCoinEnd; 2076 nextCoin = next->fCoinEnd;
1560 SkASSERT(nextCoin == this || nextCoin->fCoinEnd != nextCoin); 2077 SkASSERT(nextCoin == this || nextCoin->fCoinEnd != nextCoin);
1561 for (int check = 1; check < loop - 1; ++check) { 2078 for (int check = 1; check < loop - 1; ++check) {
1562 const SkOpSpanBase* checkCoin = this->fCoinEnd; 2079 const SkOpSpanBase* checkCoin = this->fCoinEnd;
1563 const SkOpSpanBase* innerCoin = checkCoin; 2080 const SkOpSpanBase* innerCoin = checkCoin;
1564 for (int inner = check + 1; inner < loop; ++inner) { 2081 for (int inner = check + 1; inner < loop; ++inner) {
1565 innerCoin = innerCoin->fCoinEnd; 2082 innerCoin = innerCoin->fCoinEnd;
1566 if (checkCoin == innerCoin) { 2083 if (checkCoin == innerCoin) {
1567 SkDebugf("*** bad coincident end loop ***\n"); 2084 SkDebugf("*** bad coincident end loop ***\n");
1568 return false; 2085 return false;
1569 } 2086 }
1570 } 2087 }
1571 } 2088 }
1572 ++loop; 2089 ++loop;
1573 } while ((next = nextCoin) && next != this); 2090 } while ((next = nextCoin) && next != this);
1574 return true; 2091 return true;
1575 } 2092 }
1576 2093
1577 bool SkOpSpanBase::debugContains(const SkOpSegment* segment) const { 2094 #if DEBUG_COINCIDENCE_VERBOSE
1578 const SkOpPtT* start = &fPtT; 2095 // Commented-out lines keep this in sync with insertCoinEnd()
1579 const SkOpPtT* walk = start; 2096 void SkOpSpanBase::debugInsertCoinEnd(const char* id, SkPathOpsDebug::GlitchLog* log, const SkOpSpanBase* coin) const {
1580 while ((walk = walk->next()) != start) { 2097 if (containsCoinEnd(coin)) {
1581 if (walk->segment() == segment) { 2098 // SkASSERT(coin->containsCoinEnd(this));
1582 return true; 2099 return;
2100 }
2101 debugValidate();
2102 // SkASSERT(this != coin);
2103 log->record(kMarkCoinEnd_Glitch, id, this, coin);
2104 // coin->fCoinEnd = this->fCoinEnd;
2105 // this->fCoinEnd = coinNext;
2106 debugValidate();
2107 }
2108
2109 // Commented-out lines keep this in sync with mergeContained()
2110 void SkOpSpanBase::debugMergeContained(const char* id, SkPathOpsDebug::GlitchLog * log, const SkPathOpsBounds& bounds, bool* deleted) const {
2111 // while adjacent spans' points are contained by the bounds, merge them
2112 const SkOpSpanBase* prev = this;
2113 const SkOpSegment* seg = this->segment();
2114 while ((prev = prev->prev()) && bounds.contains(prev->pt()) && !seg->ptsDisj oint(prev, this)) {
2115 if (prev->prev()) {
2116 log->record(kMergeContained_Glitch, id, this, prev);
2117 } else if (this->final()) {
2118 log->record(kMergeContained_Glitch, id, this, prev);
2119 // return;
2120 } else {
2121 log->record(kMergeContained_Glitch, id, prev, this);
1583 } 2122 }
1584 } 2123 }
1585 return false; 2124 const SkOpSpanBase* current = this;
2125 const SkOpSpanBase* next = this;
2126 while (next->upCastable() && (next = next->upCast()->next())
2127 && bounds.contains(next->pt()) && !seg->ptsDisjoint(this, next)) {
2128 if (!current->prev() && next->final()) {
2129 log->record(kMergeContained_Glitch, id, next, current);
2130 current = next;
2131 }
2132 if (current->prev()) {
2133 log->record(kMergeContained_Glitch, id, next, current);
2134 current = next;
2135 } else {
2136 log->record(kMergeContained_Glitch, id, next, current);
2137 current = next;
2138 }
2139 }
2140 #if DEBUG_COINCIDENCE
2141 // this->globalState()->coincidence()->debugValidate();
2142 #endif
1586 } 2143 }
2144 #endif
1587 2145
1588 const SkOpSpan* SkOpSpanBase::debugStarter(SkOpSpanBase const** endPtr) const { 2146 const SkOpSpan* SkOpSpanBase::debugStarter(SkOpSpanBase const** endPtr) const {
1589 const SkOpSpanBase* end = *endPtr; 2147 const SkOpSpanBase* end = *endPtr;
1590 SkASSERT(this->segment() == end->segment()); 2148 SkASSERT(this->segment() == end->segment());
1591 const SkOpSpanBase* result; 2149 const SkOpSpanBase* result;
1592 if (t() < end->t()) { 2150 if (t() < end->t()) {
1593 result = this; 2151 result = this;
1594 } else { 2152 } else {
1595 result = end; 2153 result = end;
1596 *endPtr = this; 2154 *endPtr = this;
1597 } 2155 }
1598 return result->upCast(); 2156 return result->upCast();
1599 } 2157 }
1600 2158
1601 void SkOpSpanBase::debugValidate() const { 2159 void SkOpSpanBase::debugValidate() const {
2160 #if DEBUG_COINCIDENCE
2161 if (this->globalState()->debugCheckHealth()) {
2162 return;
2163 }
2164 #endif
1602 #if DEBUG_VALIDATE 2165 #if DEBUG_VALIDATE
1603 const SkOpPtT* ptT = &fPtT; 2166 const SkOpPtT* ptT = &fPtT;
1604 SkASSERT(ptT->span() == this); 2167 SkASSERT(ptT->span() == this);
1605 do { 2168 do {
1606 // SkASSERT(SkDPoint::RoughlyEqual(fPtT.fPt, ptT->fPt)); 2169 // SkASSERT(SkDPoint::RoughlyEqual(fPtT.fPt, ptT->fPt));
1607 ptT->debugValidate(); 2170 ptT->debugValidate();
1608 ptT = ptT->next(); 2171 ptT = ptT->next();
1609 } while (ptT != &fPtT); 2172 } while (ptT != &fPtT);
1610 SkASSERT(this->debugCoinEndLoopCheck()); 2173 SkASSERT(this->debugCoinEndLoopCheck());
1611 if (!this->final()) { 2174 if (!this->final()) {
(...skipping 24 matching lines...) Expand all
1636 SkDebugf("*** bad coincident loop ***\n"); 2199 SkDebugf("*** bad coincident loop ***\n");
1637 return false; 2200 return false;
1638 } 2201 }
1639 } 2202 }
1640 } 2203 }
1641 ++loop; 2204 ++loop;
1642 } while ((next = nextCoin) && next != this); 2205 } while ((next = nextCoin) && next != this);
1643 return true; 2206 return true;
1644 } 2207 }
1645 2208
2209 #if DEBUG_COINCIDENCE_VERBOSE
2210 // Commented-out lines keep this in sync with insertCoincidence() in header
2211 void SkOpSpan::debugInsertCoincidence(const char* id, SkPathOpsDebug::GlitchLog* log, const SkOpSpan* coin) const {
2212 if (containsCoincidence(coin)) {
2213 // SkASSERT(coin->containsCoincidence(this));
2214 return;
2215 }
2216 debugValidate();
2217 // SkASSERT(this != coin);
2218 log->record(kMarkCoinStart_Glitch, id, this, coin);
2219 // coin->fCoincident = this->fCoincident;
2220 // this->fCoincident = coinNext;
2221 debugValidate();
2222 }
2223
2224 // Commented-out lines keep this in sync with insertCoincidence()
2225 void SkOpSpan::debugInsertCoincidence(const char* id, SkPathOpsDebug::GlitchLog* log, const SkOpSegment* segment, bool flipped) const {
2226 if (this->containsCoincidence(segment)) {
2227 return;
2228 }
2229 const SkOpPtT* next = &fPtT;
2230 while ((next = next->next()) != &fPtT) {
2231 if (next->segment() == segment) {
2232 log->record(kMarkCoinInsert_Glitch, id, flipped ? next->span()->prev () : next->span());
2233 return;
2234 }
2235 }
2236 #if DEBUG_COINCIDENCE
2237 log->record(kMarkCoinMissing_Glitch, id, segment, this);
2238 #endif
2239 }
2240 #endif
2241
1646 // called only by test code 2242 // called only by test code
1647 int SkIntersections::debugCoincidentUsed() const { 2243 int SkIntersections::debugCoincidentUsed() const {
1648 if (!fIsCoincident[0]) { 2244 if (!fIsCoincident[0]) {
1649 SkASSERT(!fIsCoincident[1]); 2245 SkASSERT(!fIsCoincident[1]);
1650 return 0; 2246 return 0;
1651 } 2247 }
1652 int count = 0; 2248 int count = 0;
1653 SkDEBUGCODE(int count2 = 0;) 2249 SkDEBUGCODE(int count2 = 0;)
1654 for (int index = 0; index < fUsed; ++index) { 2250 for (int index = 0; index < fUsed; ++index) {
1655 if (fIsCoincident[0] & (1 << index)) { 2251 if (fIsCoincident[0] & (1 << index)) {
1656 ++count; 2252 ++count;
1657 } 2253 }
1658 #ifdef SK_DEBUG 2254 #ifdef SK_DEBUG
1659 if (fIsCoincident[1] & (1 << index)) { 2255 if (fIsCoincident[1] & (1 << index)) {
1660 ++count2; 2256 ++count2;
1661 } 2257 }
1662 #endif 2258 #endif
1663 } 2259 }
1664 SkASSERT(count == count2); 2260 SkASSERT(count == count2);
1665 return count; 2261 return count;
1666 } 2262 }
1667 2263
1668 #include "SkOpContour.h" 2264 #include "SkOpContour.h"
1669 2265
2266 // Commented-out lines keep this in sync with addOpp()
2267 bool SkOpPtT::debugAddOpp(const SkOpPtT* opp) const {
2268 // find the fOpp ptr to opp
2269 const SkOpPtT* oppPrev = opp->fNext;
2270 if (oppPrev == this) {
2271 return false;
2272 }
2273 while (oppPrev->fNext != opp) {
2274 oppPrev = oppPrev->fNext;
2275 if (oppPrev == this) {
2276 return false;
2277 }
2278 }
2279 // const SkOpPtT* oldNext = this->fNext;
2280 SkASSERT(this != opp);
2281 // this->fNext = opp;
2282 // SkASSERT(oppPrev != oldNext);
2283 // oppPrev->fNext = oldNext;
2284 return true;
2285 }
2286
1670 bool SkOpPtT::debugContains(const SkOpPtT* check) const { 2287 bool SkOpPtT::debugContains(const SkOpPtT* check) const {
1671 SkASSERT(this != check); 2288 SkASSERT(this != check);
1672 const SkOpPtT* ptT = this; 2289 const SkOpPtT* ptT = this;
1673 int links = 0; 2290 int links = 0;
1674 do { 2291 do {
1675 ptT = ptT->next(); 2292 ptT = ptT->next();
1676 if (ptT == check) { 2293 if (ptT == check) {
1677 return true; 2294 return true;
1678 } 2295 }
1679 ++links; 2296 ++links;
(...skipping 49 matching lines...) Expand 10 before | Expand all | Expand 10 after
1729 // -- and it's likely that a large loop count is indicative of a bug som ewhere 2346 // -- and it's likely that a large loop count is indicative of a bug som ewhere
1730 if (++loop > 1000) { 2347 if (++loop > 1000) {
1731 SkDebugf("*** loop count exceeds 1000 ***\n"); 2348 SkDebugf("*** loop count exceeds 1000 ***\n");
1732 return 1000; 2349 return 1000;
1733 } 2350 }
1734 } while ((next = next->fNext) && next != this); 2351 } while ((next = next->fNext) && next != this);
1735 return 0; 2352 return 0;
1736 } 2353 }
1737 2354
1738 void SkOpPtT::debugValidate() const { 2355 void SkOpPtT::debugValidate() const {
2356 #if DEBUG_COINCIDENCE
2357 if (this->globalState()->debugCheckHealth()) {
2358 return;
2359 }
2360 #endif
1739 #if DEBUG_VALIDATE 2361 #if DEBUG_VALIDATE
1740 SkOpGlobalState::Phase phase = contour()->globalState()->phase(); 2362 SkOpGlobalState::Phase phase = contour()->globalState()->phase();
1741 if (phase == SkOpGlobalState::kIntersecting 2363 if (phase == SkOpGlobalState::kIntersecting
1742 || phase == SkOpGlobalState::kFixWinding) { 2364 || phase == SkOpGlobalState::kFixWinding) {
1743 return; 2365 return;
1744 } 2366 }
1745 SkASSERT(fNext); 2367 SkASSERT(fNext);
1746 SkASSERT(fNext != this); 2368 SkASSERT(fNext != this);
1747 SkASSERT(fNext->fNext); 2369 SkASSERT(fNext->fNext);
1748 SkASSERT(debugLoopLimit(false) == 0); 2370 SkASSERT(debugLoopLimit(false) == 0);
(...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after
1845 #endif 2467 #endif
1846 SkPath::FillType fillType = path.getFillType(); 2468 SkPath::FillType fillType = path.getFillType();
1847 SkASSERT(fillType >= SkPath::kWinding_FillType && fillType <= SkPath::kInver seEvenOdd_FillType); 2469 SkASSERT(fillType >= SkPath::kWinding_FillType && fillType <= SkPath::kInver seEvenOdd_FillType);
1848 if (includeDeclaration) { 2470 if (includeDeclaration) {
1849 SkDebugf(" SkPath %s;\n", name); 2471 SkDebugf(" SkPath %s;\n", name);
1850 } 2472 }
1851 SkDebugf(" %s.setFillType(SkPath::%s);\n", name, gFillTypeStr[fillType]); 2473 SkDebugf(" %s.setFillType(SkPath::%s);\n", name, gFillTypeStr[fillType]);
1852 iter.setPath(path); 2474 iter.setPath(path);
1853 showPathContours(iter, name); 2475 showPathContours(iter, name);
1854 } 2476 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698