blob: 627a7c9f4023ef81a182505d7538d30abd25f2e5 [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
2 * Copyright 2013 Google Inc.
3 *
4 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
6 */
7
8#include "SkPathOpsDebug.h"
caryclark@google.coma5e55922013-05-07 18:51:31 +00009#include "SkPath.h"
caryclark54359292015-03-26 07:52:43 -070010#include "SkString.h"
caryclark1049f122015-04-20 08:31:59 -070011#include "SkThread.h"
caryclark54359292015-03-26 07:52:43 -070012
13#if DEBUG_VALIDATE
14extern bool FLAGS_runFail;
15#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +000016
caryclark624637c2015-05-11 07:21:27 -070017#if DEBUG_SORT
18int SkPathOpsDebug::gSortCountDefault = SK_MaxS32;
19int SkPathOpsDebug::gSortCount;
20#endif
21
22#if DEBUG_ACTIVE_OP
23const char* SkPathOpsDebug::kPathOpStr[] = {"diff", "sect", "union", "xor"};
24#endif
25
caryclark@google.com07393ca2013-04-08 11:47:37 +000026#if defined SK_DEBUG || !FORCE_RELEASE
27
caryclark@google.com570863f2013-09-16 15:55:01 +000028const char* SkPathOpsDebug::kLVerbStr[] = {"", "line", "quad", "cubic"};
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +000029
30#if defined(SK_DEBUG) || !FORCE_RELEASE
commit-bot@chromium.orgfe41b8f2014-04-25 14:03:52 +000031int SkPathOpsDebug::gContourID = 0;
32int SkPathOpsDebug::gSegmentID = 0;
commit-bot@chromium.org8cb1daa2014-04-25 12:59:11 +000033#endif
caryclark@google.com570863f2013-09-16 15:55:01 +000034
caryclark54359292015-03-26 07:52:43 -070035bool SkPathOpsDebug::ChaseContains(const SkTDArray<SkOpSpanBase* >& chaseArray,
36 const SkOpSpanBase* span) {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000037 for (int index = 0; index < chaseArray.count(); ++index) {
caryclark54359292015-03-26 07:52:43 -070038 const SkOpSpanBase* entry = chaseArray[index];
commit-bot@chromium.org4431e772014-04-14 17:08:59 +000039 if (entry == span) {
40 return true;
41 }
42 }
43 return false;
44}
45
caryclark@google.com570863f2013-09-16 15:55:01 +000046void SkPathOpsDebug::MathematicaIze(char* str, size_t bufferLen) {
caryclark@google.com07393ca2013-04-08 11:47:37 +000047 size_t len = strlen(str);
48 bool num = false;
49 for (size_t idx = 0; idx < len; ++idx) {
50 if (num && str[idx] == 'e') {
51 if (len + 2 >= bufferLen) {
52 return;
53 }
54 memmove(&str[idx + 2], &str[idx + 1], len - idx);
55 str[idx] = '*';
56 str[idx + 1] = '^';
57 ++len;
58 }
59 num = str[idx] >= '0' && str[idx] <= '9';
60 }
61}
62
caryclark@google.com570863f2013-09-16 15:55:01 +000063bool SkPathOpsDebug::ValidWind(int wind) {
caryclark@google.com07393ca2013-04-08 11:47:37 +000064 return wind > SK_MinS32 + 0xFFFF && wind < SK_MaxS32 - 0xFFFF;
65}
66
caryclark@google.com570863f2013-09-16 15:55:01 +000067void SkPathOpsDebug::WindingPrintf(int wind) {
caryclark@google.com07393ca2013-04-08 11:47:37 +000068 if (wind == SK_MinS32) {
69 SkDebugf("?");
70 } else {
71 SkDebugf("%d", wind);
72 }
73}
caryclark54359292015-03-26 07:52:43 -070074#endif // defined SK_DEBUG || !FORCE_RELEASE
75
caryclark@google.coma5e55922013-05-07 18:51:31 +000076
caryclark@google.com07e97fc2013-07-08 17:17:02 +000077#if DEBUG_SHOW_TEST_NAME
caryclark@google.com570863f2013-09-16 15:55:01 +000078void* SkPathOpsDebug::CreateNameStr() {
caryclark@google.com07e97fc2013-07-08 17:17:02 +000079 return SkNEW_ARRAY(char, DEBUG_FILENAME_STRING_LENGTH);
80}
81
caryclark@google.com570863f2013-09-16 15:55:01 +000082void SkPathOpsDebug::DeleteNameStr(void* v) {
caryclark@google.com07e97fc2013-07-08 17:17:02 +000083 SkDELETE_ARRAY(reinterpret_cast<char* >(v));
84}
85
caryclark@google.com570863f2013-09-16 15:55:01 +000086void SkPathOpsDebug::BumpTestName(char* test) {
caryclark@google.com07e97fc2013-07-08 17:17:02 +000087 char* num = test + strlen(test);
88 while (num[-1] >= '0' && num[-1] <= '9') {
89 --num;
caryclark@google.coma5e55922013-05-07 18:51:31 +000090 }
caryclark@google.com07e97fc2013-07-08 17:17:02 +000091 if (num[0] == '\0') {
92 return;
93 }
94 int dec = atoi(num);
95 if (dec == 0) {
96 return;
97 }
98 ++dec;
99 SK_SNPRINTF(num, DEBUG_FILENAME_STRING_LENGTH - (num - test), "%d", dec);
caryclark@google.coma5e55922013-05-07 18:51:31 +0000100}
101#endif
caryclark@google.com570863f2013-09-16 15:55:01 +0000102
caryclark1049f122015-04-20 08:31:59 -0700103static void show_function_header(const char* functionName) {
104 SkDebugf("\nstatic void %s(skiatest::Reporter* reporter, const char* filename) {\n", functionName);
105 if (strcmp("skphealth_com76", functionName) == 0) {
106 SkDebugf("found it\n");
107 }
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000108}
caryclark1049f122015-04-20 08:31:59 -0700109
110static const char* gOpStrs[] = {
111 "kDifference_SkPathOp",
112 "kIntersect_SkPathOp",
113 "kUnion_SkPathOp",
114 "kXor_PathOp",
115 "kReverseDifference_SkPathOp",
116};
117
caryclark03b03ca2015-04-23 09:13:37 -0700118const char* SkPathOpsDebug::OpStr(SkPathOp op) {
119 return gOpStrs[op];
120}
121
caryclark1049f122015-04-20 08:31:59 -0700122static void show_op(SkPathOp op, const char* pathOne, const char* pathTwo) {
123 SkDebugf(" testPathOp(reporter, %s, %s, %s, filename);\n", pathOne, pathTwo, gOpStrs[op]);
124 SkDebugf("}\n");
125}
126
127SK_DECLARE_STATIC_MUTEX(gTestMutex);
128
129void SkPathOpsDebug::ShowPath(const SkPath& a, const SkPath& b, SkPathOp shapeOp,
130 const char* testName) {
131 SkAutoMutexAcquire ac(gTestMutex);
132 show_function_header(testName);
133 ShowOnePath(a, "path", true);
134 ShowOnePath(b, "pathB", true);
135 show_op(shapeOp, "path", "pathB");
136}
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000137
caryclark624637c2015-05-11 07:21:27 -0700138#include "SkPathOpsCubic.h"
139#include "SkPathOpsQuad.h"
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000140
caryclark624637c2015-05-11 07:21:27 -0700141SkDCubic SkDQuad::debugToCubic() const {
142 SkDCubic cubic;
143 cubic[0] = fPts[0];
144 cubic[2] = fPts[1];
145 cubic[3] = fPts[2];
146 cubic[1].fX = (cubic[0].fX + cubic[2].fX * 2) / 3;
147 cubic[1].fY = (cubic[0].fY + cubic[2].fY * 2) / 3;
148 cubic[2].fX = (cubic[3].fX + cubic[2].fX * 2) / 3;
149 cubic[2].fY = (cubic[3].fY + cubic[2].fY * 2) / 3;
150 return cubic;
caryclark54359292015-03-26 07:52:43 -0700151}
caryclark624637c2015-05-11 07:21:27 -0700152
153#include "SkOpAngle.h"
154#include "SkOpCoincidence.h"
155#include "SkOpSegment.h"
caryclark54359292015-03-26 07:52:43 -0700156
157SkOpAngle* SkOpSegment::debugLastAngle() {
158 SkOpAngle* result = NULL;
159 SkOpSpan* span = this->head();
160 do {
161 if (span->toAngle()) {
162 SkASSERT(!result);
163 result = span->toAngle();
164 }
165 } while ((span = span->next()->upCastable()));
166 SkASSERT(result);
167 return result;
168}
169
170void SkOpSegment::debugReset() {
caryclark1049f122015-04-20 08:31:59 -0700171 this->init(this->fPts, this->fWeight, this->contour(), this->verb());
caryclark54359292015-03-26 07:52:43 -0700172}
173
174#if DEBUG_ACTIVE_SPANS
175void SkOpSegment::debugShowActiveSpans() const {
176 debugValidate();
177 if (done()) {
178 return;
179 }
180 int lastId = -1;
181 double lastT = -1;
182 const SkOpSpan* span = &fHead;
183 do {
184 if (span->done()) {
185 continue;
186 }
caryclark1049f122015-04-20 08:31:59 -0700187 if (lastId == this->debugID() && lastT == span->t()) {
caryclark54359292015-03-26 07:52:43 -0700188 continue;
189 }
caryclark1049f122015-04-20 08:31:59 -0700190 lastId = this->debugID();
caryclark54359292015-03-26 07:52:43 -0700191 lastT = span->t();
caryclark1049f122015-04-20 08:31:59 -0700192 SkDebugf("%s id=%d", __FUNCTION__, this->debugID());
caryclark54359292015-03-26 07:52:43 -0700193 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
194 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
195 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
196 }
caryclark1049f122015-04-20 08:31:59 -0700197 if (SkPath::kConic_Verb == fVerb) {
198 SkDebugf(" %1.9gf", fWeight);
199 }
caryclark54359292015-03-26 07:52:43 -0700200 const SkOpPtT* ptT = span->ptT();
201 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", ptT->fT, ptT->fPt.fX, ptT->fPt.fY);
202 SkDebugf(" tEnd=%1.9g", span->next()->t());
caryclark54359292015-03-26 07:52:43 -0700203 if (span->windSum() == SK_MinS32) {
caryclark624637c2015-05-11 07:21:27 -0700204 SkDebugf(" windSum=?");
caryclark54359292015-03-26 07:52:43 -0700205 } else {
caryclark624637c2015-05-11 07:21:27 -0700206 SkDebugf(" windSum=%d", span->windSum());
caryclark54359292015-03-26 07:52:43 -0700207 }
caryclark624637c2015-05-11 07:21:27 -0700208 if (span->oppValue() && span->oppSum() == SK_MinS32) {
209 SkDebugf(" oppSum=?");
210 } else if (span->oppValue() || span->oppSum() != SK_MinS32) {
211 SkDebugf(" oppSum=%d", span->oppSum());
212 }
213 SkDebugf(" windValue=%d", span->windValue());
214 if (span->oppValue() || span->oppSum() != SK_MinS32) {
215 SkDebugf(" oppValue=%d", span->oppValue());
216 }
caryclark54359292015-03-26 07:52:43 -0700217 SkDebugf("\n");
218 } while ((span = span->next()->upCastable()));
219}
220#endif
221
222#if DEBUG_MARK_DONE
223void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int winding) {
224 const SkPoint& pt = span->ptT()->fPt;
caryclark1049f122015-04-20 08:31:59 -0700225 SkDebugf("%s id=%d", fun, this->debugID());
caryclark54359292015-03-26 07:52:43 -0700226 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
227 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
228 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
229 }
230 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=",
231 span->t(), span->debugID(), pt.fX, pt.fY, span->next()->t());
232 if (winding == SK_MinS32) {
233 SkDebugf("?");
234 } else {
235 SkDebugf("%d", winding);
236 }
237 SkDebugf(" windSum=");
238 if (span->windSum() == SK_MinS32) {
239 SkDebugf("?");
240 } else {
241 SkDebugf("%d", span->windSum());
242 }
243 SkDebugf(" windValue=%d\n", span->windValue());
244}
245
246void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int winding,
247 int oppWinding) {
248 const SkPoint& pt = span->ptT()->fPt;
caryclark1049f122015-04-20 08:31:59 -0700249 SkDebugf("%s id=%d", fun, this->debugID());
caryclark54359292015-03-26 07:52:43 -0700250 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY);
251 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) {
252 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY);
253 }
254 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=",
255 span->t(), span->debugID(), pt.fX, pt.fY, span->next()->t(), winding, oppWinding);
256 if (winding == SK_MinS32) {
257 SkDebugf("?");
258 } else {
259 SkDebugf("%d", winding);
260 }
261 SkDebugf(" newOppSum=");
262 if (oppWinding == SK_MinS32) {
263 SkDebugf("?");
264 } else {
265 SkDebugf("%d", oppWinding);
266 }
267 SkDebugf(" oppSum=");
268 if (span->oppSum() == SK_MinS32) {
269 SkDebugf("?");
270 } else {
271 SkDebugf("%d", span->oppSum());
272 }
273 SkDebugf(" windSum=");
274 if (span->windSum() == SK_MinS32) {
275 SkDebugf("?");
276 } else {
277 SkDebugf("%d", span->windSum());
278 }
279 SkDebugf(" windValue=%d oppValue=%d\n", span->windValue(), span->oppValue());
280}
281
282#endif
283
284#if DEBUG_ANGLE
285SkString SkOpAngle::debugPart() const {
286 SkString result;
287 switch (this->segment()->verb()) {
288 case SkPath::kLine_Verb:
289 result.printf(LINE_DEBUG_STR " id=%d", LINE_DEBUG_DATA(fCurvePart),
290 this->segment()->debugID());
291 break;
292 case SkPath::kQuad_Verb:
293 result.printf(QUAD_DEBUG_STR " id=%d", QUAD_DEBUG_DATA(fCurvePart),
294 this->segment()->debugID());
295 break;
caryclark1049f122015-04-20 08:31:59 -0700296 case SkPath::kConic_Verb:
297 result.printf(CONIC_DEBUG_STR " id=%d",
298 CONIC_DEBUG_DATA(fCurvePart, fCurvePart.fConic.fWeight),
299 this->segment()->debugID());
300 break;
caryclark54359292015-03-26 07:52:43 -0700301 case SkPath::kCubic_Verb:
302 result.printf(CUBIC_DEBUG_STR " id=%d", CUBIC_DEBUG_DATA(fCurvePart),
303 this->segment()->debugID());
304 break;
305 default:
306 SkASSERT(0);
307 }
308 return result;
309}
310#endif
311
caryclark624637c2015-05-11 07:21:27 -0700312#if DEBUG_SORT
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000313void SkOpAngle::debugLoop() const {
caryclarke4097e32014-06-18 07:24:19 -0700314 const SkOpAngle* first = this;
315 const SkOpAngle* next = this;
316 do {
317 next->dumpOne(true);
caryclark19eb3b22014-07-18 05:08:14 -0700318 SkDebugf("\n");
caryclarke4097e32014-06-18 07:24:19 -0700319 next = next->fNext;
320 } while (next && next != first);
caryclark54359292015-03-26 07:52:43 -0700321 next = first;
322 do {
323 next->debugValidate();
324 next = next->fNext;
325 } while (next && next != first);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000326}
327#endif
328
caryclark54359292015-03-26 07:52:43 -0700329void SkOpAngle::debugValidate() const {
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000330#if DEBUG_VALIDATE
caryclark54359292015-03-26 07:52:43 -0700331 const SkOpAngle* first = this;
332 const SkOpAngle* next = this;
333 int wind = 0;
334 int opp = 0;
335 int lastXor = -1;
336 int lastOppXor = -1;
337 do {
338 if (next->unorderable()) {
339 return;
340 }
341 const SkOpSpan* minSpan = next->start()->starter(next->end());
342 if (minSpan->windValue() == SK_MinS32) {
343 return;
344 }
345 bool op = next->segment()->operand();
346 bool isXor = next->segment()->isXor();
347 bool oppXor = next->segment()->oppXor();
348 SkASSERT(!DEBUG_LIMIT_WIND_SUM || between(0, minSpan->windValue(), DEBUG_LIMIT_WIND_SUM));
349 SkASSERT(!DEBUG_LIMIT_WIND_SUM
350 || between(-DEBUG_LIMIT_WIND_SUM, minSpan->oppValue(), DEBUG_LIMIT_WIND_SUM));
351 bool useXor = op ? oppXor : isXor;
352 SkASSERT(lastXor == -1 || lastXor == (int) useXor);
353 lastXor = (int) useXor;
caryclark624637c2015-05-11 07:21:27 -0700354 wind += next->debugSign() * (op ? minSpan->oppValue() : minSpan->windValue());
caryclark54359292015-03-26 07:52:43 -0700355 if (useXor) {
356 wind &= 1;
357 }
358 useXor = op ? isXor : oppXor;
359 SkASSERT(lastOppXor == -1 || lastOppXor == (int) useXor);
360 lastOppXor = (int) useXor;
caryclark624637c2015-05-11 07:21:27 -0700361 opp += next->debugSign() * (op ? minSpan->windValue() : minSpan->oppValue());
caryclark54359292015-03-26 07:52:43 -0700362 if (useXor) {
363 opp &= 1;
364 }
365 next = next->fNext;
366 } while (next && next != first);
caryclark182b4992015-05-14 05:45:54 -0700367 SkASSERT(wind == 0 || !FLAGS_runFail);
caryclark54359292015-03-26 07:52:43 -0700368 SkASSERT(opp == 0 || !FLAGS_runFail);
369#endif
370}
371
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000372void SkOpAngle::debugValidateNext() const {
caryclark54359292015-03-26 07:52:43 -0700373#if !FORCE_RELEASE
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000374 const SkOpAngle* first = this;
375 const SkOpAngle* next = first;
376 SkTDArray<const SkOpAngle*>(angles);
377 do {
caryclarkdac1d172014-06-17 05:15:38 -0700378// SK_ALWAYSBREAK(next->fSegment->debugContains(next));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000379 angles.push(next);
380 next = next->next();
381 if (next == first) {
382 break;
383 }
commit-bot@chromium.org45d1d1d2014-04-30 18:24:16 +0000384 SK_ALWAYSBREAK(!angles.contains(next));
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000385 if (!next) {
386 return;
387 }
388 } while (true);
reed0dc4dd62015-03-24 13:55:33 -0700389#endif
reed0dc4dd62015-03-24 13:55:33 -0700390}
reed0dc4dd62015-03-24 13:55:33 -0700391
caryclark624637c2015-05-11 07:21:27 -0700392void SkOpCoincidence::debugShowCoincidence() const {
393 SkCoincidentSpans* span = fHead;
394 while (span) {
395 SkDebugf("%s - id=%d t=%1.9g tEnd=%1.9g\n", __FUNCTION__,
396 span->fCoinPtTStart->segment()->debugID(),
397 span->fCoinPtTStart->fT, span->fCoinPtTEnd->fT);
398 SkDebugf("%s + id=%d t=%1.9g tEnd=%1.9g\n", __FUNCTION__,
399 span->fOppPtTStart->segment()->debugID(),
400 span->fOppPtTStart->fT, span->fOppPtTEnd->fT);
401 span = span->fNext;
402 }
403}
404
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000405void SkOpSegment::debugValidate() const {
406#if DEBUG_VALIDATE
caryclark54359292015-03-26 07:52:43 -0700407 const SkOpSpanBase* span = &fHead;
408 double lastT = -1;
409 const SkOpSpanBase* prev = NULL;
410 int count = 0;
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000411 int done = 0;
caryclark54359292015-03-26 07:52:43 -0700412 do {
413 if (!span->final()) {
414 ++count;
415 done += span->upCast()->done() ? 1 : 0;
416 }
417 SkASSERT(span->segment() == this);
418 SkASSERT(!prev || prev->upCast()->next() == span);
419 SkASSERT(!prev || prev == span->prev());
420 prev = span;
421 double t = span->ptT()->fT;
422 SkASSERT(lastT < t);
423 lastT = t;
424 span->debugValidate();
425 } while (!span->final() && (span = span->upCast()->next()));
426 SkASSERT(count == fCount);
427 SkASSERT(done == fDoneCount);
caryclark08bc8482015-04-24 09:08:57 -0700428 SkASSERT(count >= fDoneCount);
caryclark54359292015-03-26 07:52:43 -0700429 SkASSERT(span->final());
430 span->debugValidate();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000431#endif
caryclark54359292015-03-26 07:52:43 -0700432}
433
434bool SkOpSpanBase::debugCoinEndLoopCheck() const {
435 int loop = 0;
436 const SkOpSpanBase* next = this;
437 SkOpSpanBase* nextCoin;
438 do {
439 nextCoin = next->fCoinEnd;
440 SkASSERT(nextCoin == this || nextCoin->fCoinEnd != nextCoin);
441 for (int check = 1; check < loop - 1; ++check) {
442 const SkOpSpanBase* checkCoin = this->fCoinEnd;
443 const SkOpSpanBase* innerCoin = checkCoin;
444 for (int inner = check + 1; inner < loop; ++inner) {
445 innerCoin = innerCoin->fCoinEnd;
446 if (checkCoin == innerCoin) {
447 SkDebugf("*** bad coincident end loop ***\n");
448 return false;
449 }
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000450 }
451 }
caryclark54359292015-03-26 07:52:43 -0700452 ++loop;
453 } while ((next = nextCoin) && next != this);
454 return true;
455}
456
457void SkOpSpanBase::debugValidate() const {
458#if DEBUG_VALIDATE
459 const SkOpPtT* ptT = &fPtT;
460 SkASSERT(ptT->span() == this);
461 do {
462// SkASSERT(SkDPoint::RoughlyEqual(fPtT.fPt, ptT->fPt));
463 ptT->debugValidate();
464 ptT = ptT->next();
465 } while (ptT != &fPtT);
466 SkASSERT(this->debugCoinEndLoopCheck());
467 if (!this->final()) {
468 SkASSERT(this->upCast()->debugCoinLoopCheck());
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000469 }
caryclark54359292015-03-26 07:52:43 -0700470 if (fFromAngle) {
471 fFromAngle->debugValidate();
472 }
473 if (!this->final() && this->upCast()->toAngle()) {
474 this->upCast()->toAngle()->debugValidate();
475 }
476#endif
477}
478
479bool SkOpSpan::debugCoinLoopCheck() const {
480 int loop = 0;
481 const SkOpSpan* next = this;
482 SkOpSpan* nextCoin;
483 do {
484 nextCoin = next->fCoincident;
485 SkASSERT(nextCoin == this || nextCoin->fCoincident != nextCoin);
486 for (int check = 1; check < loop - 1; ++check) {
487 const SkOpSpan* checkCoin = this->fCoincident;
488 const SkOpSpan* innerCoin = checkCoin;
489 for (int inner = check + 1; inner < loop; ++inner) {
490 innerCoin = innerCoin->fCoincident;
491 if (checkCoin == innerCoin) {
492 SkDebugf("*** bad coincident loop ***\n");
493 return false;
494 }
495 }
496 }
497 ++loop;
498 } while ((next = nextCoin) && next != this);
499 return true;
500}
501
caryclark624637c2015-05-11 07:21:27 -0700502// called only by test code
503int SkIntersections::debugCoincidentUsed() const {
504 if (!fIsCoincident[0]) {
505 SkASSERT(!fIsCoincident[1]);
506 return 0;
507 }
508 int count = 0;
509 SkDEBUGCODE(int count2 = 0;)
510 for (int index = 0; index < fUsed; ++index) {
511 if (fIsCoincident[0] & (1 << index)) {
512 ++count;
513 }
514#ifdef SK_DEBUG
515 if (fIsCoincident[1] & (1 << index)) {
516 ++count2;
517 }
518#endif
519 }
520 SkASSERT(count == count2);
521 return count;
522}
523
caryclark54359292015-03-26 07:52:43 -0700524#include "SkOpContour.h"
525
526int SkOpPtT::debugLoopLimit(bool report) const {
527 int loop = 0;
528 const SkOpPtT* next = this;
529 do {
530 for (int check = 1; check < loop - 1; ++check) {
531 const SkOpPtT* checkPtT = this->fNext;
532 const SkOpPtT* innerPtT = checkPtT;
533 for (int inner = check + 1; inner < loop; ++inner) {
534 innerPtT = innerPtT->fNext;
535 if (checkPtT == innerPtT) {
536 if (report) {
537 SkDebugf("*** bad ptT loop ***\n");
538 }
539 return loop;
540 }
541 }
542 }
543 ++loop;
544 } while ((next = next->fNext) && next != this);
545 return 0;
546}
547
548void SkOpPtT::debugValidate() const {
549#if DEBUG_VALIDATE
caryclark4e1a4c92015-05-18 12:56:57 -0700550 SkOpGlobalState::Phase phase = contour()->globalState()->phase();
551 if (phase == SkOpGlobalState::kIntersecting
552 || phase == SkOpGlobalState::kFixWinding) {
caryclark54359292015-03-26 07:52:43 -0700553 return;
554 }
555 SkASSERT(fNext);
556 SkASSERT(fNext != this);
557 SkASSERT(fNext->fNext);
558 SkASSERT(debugLoopLimit(false) == 0);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000559#endif
560}
caryclark1049f122015-04-20 08:31:59 -0700561
562static void output_scalar(SkScalar num) {
563 if (num == (int) num) {
564 SkDebugf("%d", (int) num);
565 } else {
566 SkString str;
567 str.printf("%1.9g", num);
568 int width = (int) str.size();
569 const char* cStr = str.c_str();
570 while (cStr[width - 1] == '0') {
571 --width;
572 }
573 str.resize(width);
574 SkDebugf("%sf", str.c_str());
575 }
576}
577
578static void output_points(const SkPoint* pts, int count) {
579 for (int index = 0; index < count; ++index) {
580 output_scalar(pts[index].fX);
581 SkDebugf(", ");
582 output_scalar(pts[index].fY);
583 if (index + 1 < count) {
584 SkDebugf(", ");
585 }
586 }
587}
588
589static void showPathContours(SkPath::RawIter& iter, const char* pathName) {
590 uint8_t verb;
591 SkPoint pts[4];
592 while ((verb = iter.next(pts)) != SkPath::kDone_Verb) {
593 switch (verb) {
594 case SkPath::kMove_Verb:
595 SkDebugf(" %s.moveTo(", pathName);
596 output_points(&pts[0], 1);
597 SkDebugf(");\n");
598 continue;
599 case SkPath::kLine_Verb:
600 SkDebugf(" %s.lineTo(", pathName);
601 output_points(&pts[1], 1);
602 SkDebugf(");\n");
603 break;
604 case SkPath::kQuad_Verb:
605 SkDebugf(" %s.quadTo(", pathName);
606 output_points(&pts[1], 2);
607 SkDebugf(");\n");
608 break;
609 case SkPath::kConic_Verb:
610 SkDebugf(" %s.conicTo(", pathName);
611 output_points(&pts[1], 2);
612 SkDebugf(", %1.9gf);\n", iter.conicWeight());
613 break;
614 case SkPath::kCubic_Verb:
615 SkDebugf(" %s.cubicTo(", pathName);
616 output_points(&pts[1], 3);
617 SkDebugf(");\n");
618 break;
619 case SkPath::kClose_Verb:
620 SkDebugf(" %s.close();\n", pathName);
621 break;
622 default:
623 SkDEBUGFAIL("bad verb");
624 return;
625 }
626 }
627}
628
629static const char* gFillTypeStr[] = {
630 "kWinding_FillType",
631 "kEvenOdd_FillType",
632 "kInverseWinding_FillType",
633 "kInverseEvenOdd_FillType"
634};
635
636void SkPathOpsDebug::ShowOnePath(const SkPath& path, const char* name, bool includeDeclaration) {
637 SkPath::RawIter iter(path);
638#define SUPPORT_RECT_CONTOUR_DETECTION 0
639#if SUPPORT_RECT_CONTOUR_DETECTION
640 int rectCount = path.isRectContours() ? path.rectContours(NULL, NULL) : 0;
641 if (rectCount > 0) {
642 SkTDArray<SkRect> rects;
643 SkTDArray<SkPath::Direction> directions;
644 rects.setCount(rectCount);
645 directions.setCount(rectCount);
646 path.rectContours(rects.begin(), directions.begin());
647 for (int contour = 0; contour < rectCount; ++contour) {
648 const SkRect& rect = rects[contour];
649 SkDebugf("path.addRect(%1.9g, %1.9g, %1.9g, %1.9g, %s);\n", rect.fLeft, rect.fTop,
650 rect.fRight, rect.fBottom, directions[contour] == SkPath::kCCW_Direction
651 ? "SkPath::kCCW_Direction" : "SkPath::kCW_Direction");
652 }
653 return;
654 }
655#endif
656 SkPath::FillType fillType = path.getFillType();
657 SkASSERT(fillType >= SkPath::kWinding_FillType && fillType <= SkPath::kInverseEvenOdd_FillType);
658 if (includeDeclaration) {
659 SkDebugf(" SkPath %s;\n", name);
660 }
661 SkDebugf(" %s.setFillType(SkPath::%s);\n", name, gFillTypeStr[fillType]);
662 iter.setPath(path);
663 showPathContours(iter, name);
664}