caryclark@google.com | 07393ca | 2013-04-08 11:47:37 +0000 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2013 Google Inc. |
| 3 | * |
| 4 | * Use of this source code is governed by a BSD-style license that can be |
| 5 | * found in the LICENSE file. |
| 6 | */ |
| 7 | |
| 8 | #include "SkPathOpsDebug.h" |
caryclark@google.com | a5e5592 | 2013-05-07 18:51:31 +0000 | [diff] [blame] | 9 | #include "SkPath.h" |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 10 | #include "SkString.h" |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 11 | #include "SkThread.h" |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 12 | |
| 13 | #if DEBUG_VALIDATE |
| 14 | extern bool FLAGS_runFail; |
| 15 | #endif |
caryclark@google.com | 07393ca | 2013-04-08 11:47:37 +0000 | [diff] [blame] | 16 | |
caryclark | 624637c | 2015-05-11 07:21:27 -0700 | [diff] [blame] | 17 | #if DEBUG_SORT |
| 18 | int SkPathOpsDebug::gSortCountDefault = SK_MaxS32; |
| 19 | int SkPathOpsDebug::gSortCount; |
| 20 | #endif |
| 21 | |
| 22 | #if DEBUG_ACTIVE_OP |
| 23 | const char* SkPathOpsDebug::kPathOpStr[] = {"diff", "sect", "union", "xor"}; |
| 24 | #endif |
| 25 | |
caryclark@google.com | 07393ca | 2013-04-08 11:47:37 +0000 | [diff] [blame] | 26 | #if defined SK_DEBUG || !FORCE_RELEASE |
| 27 | |
caryclark@google.com | 570863f | 2013-09-16 15:55:01 +0000 | [diff] [blame] | 28 | const char* SkPathOpsDebug::kLVerbStr[] = {"", "line", "quad", "cubic"}; |
commit-bot@chromium.org | 8cb1daa | 2014-04-25 12:59:11 +0000 | [diff] [blame] | 29 | |
| 30 | #if defined(SK_DEBUG) || !FORCE_RELEASE |
commit-bot@chromium.org | fe41b8f | 2014-04-25 14:03:52 +0000 | [diff] [blame] | 31 | int SkPathOpsDebug::gContourID = 0; |
| 32 | int SkPathOpsDebug::gSegmentID = 0; |
commit-bot@chromium.org | 8cb1daa | 2014-04-25 12:59:11 +0000 | [diff] [blame] | 33 | #endif |
caryclark@google.com | 570863f | 2013-09-16 15:55:01 +0000 | [diff] [blame] | 34 | |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 35 | bool SkPathOpsDebug::ChaseContains(const SkTDArray<SkOpSpanBase* >& chaseArray, |
| 36 | const SkOpSpanBase* span) { |
commit-bot@chromium.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 37 | for (int index = 0; index < chaseArray.count(); ++index) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 38 | const SkOpSpanBase* entry = chaseArray[index]; |
commit-bot@chromium.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 39 | if (entry == span) { |
| 40 | return true; |
| 41 | } |
| 42 | } |
| 43 | return false; |
| 44 | } |
| 45 | |
caryclark@google.com | 570863f | 2013-09-16 15:55:01 +0000 | [diff] [blame] | 46 | void SkPathOpsDebug::MathematicaIze(char* str, size_t bufferLen) { |
caryclark@google.com | 07393ca | 2013-04-08 11:47:37 +0000 | [diff] [blame] | 47 | 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.com | 570863f | 2013-09-16 15:55:01 +0000 | [diff] [blame] | 63 | bool SkPathOpsDebug::ValidWind(int wind) { |
caryclark@google.com | 07393ca | 2013-04-08 11:47:37 +0000 | [diff] [blame] | 64 | return wind > SK_MinS32 + 0xFFFF && wind < SK_MaxS32 - 0xFFFF; |
| 65 | } |
| 66 | |
caryclark@google.com | 570863f | 2013-09-16 15:55:01 +0000 | [diff] [blame] | 67 | void SkPathOpsDebug::WindingPrintf(int wind) { |
caryclark@google.com | 07393ca | 2013-04-08 11:47:37 +0000 | [diff] [blame] | 68 | if (wind == SK_MinS32) { |
| 69 | SkDebugf("?"); |
| 70 | } else { |
| 71 | SkDebugf("%d", wind); |
| 72 | } |
| 73 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 74 | #endif // defined SK_DEBUG || !FORCE_RELEASE |
| 75 | |
caryclark@google.com | a5e5592 | 2013-05-07 18:51:31 +0000 | [diff] [blame] | 76 | |
caryclark@google.com | 07e97fc | 2013-07-08 17:17:02 +0000 | [diff] [blame] | 77 | #if DEBUG_SHOW_TEST_NAME |
caryclark@google.com | 570863f | 2013-09-16 15:55:01 +0000 | [diff] [blame] | 78 | void* SkPathOpsDebug::CreateNameStr() { |
caryclark@google.com | 07e97fc | 2013-07-08 17:17:02 +0000 | [diff] [blame] | 79 | return SkNEW_ARRAY(char, DEBUG_FILENAME_STRING_LENGTH); |
| 80 | } |
| 81 | |
caryclark@google.com | 570863f | 2013-09-16 15:55:01 +0000 | [diff] [blame] | 82 | void SkPathOpsDebug::DeleteNameStr(void* v) { |
caryclark@google.com | 07e97fc | 2013-07-08 17:17:02 +0000 | [diff] [blame] | 83 | SkDELETE_ARRAY(reinterpret_cast<char* >(v)); |
| 84 | } |
| 85 | |
caryclark@google.com | 570863f | 2013-09-16 15:55:01 +0000 | [diff] [blame] | 86 | void SkPathOpsDebug::BumpTestName(char* test) { |
caryclark@google.com | 07e97fc | 2013-07-08 17:17:02 +0000 | [diff] [blame] | 87 | char* num = test + strlen(test); |
| 88 | while (num[-1] >= '0' && num[-1] <= '9') { |
| 89 | --num; |
caryclark@google.com | a5e5592 | 2013-05-07 18:51:31 +0000 | [diff] [blame] | 90 | } |
caryclark@google.com | 07e97fc | 2013-07-08 17:17:02 +0000 | [diff] [blame] | 91 | 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.com | a5e5592 | 2013-05-07 18:51:31 +0000 | [diff] [blame] | 100 | } |
| 101 | #endif |
caryclark@google.com | 570863f | 2013-09-16 15:55:01 +0000 | [diff] [blame] | 102 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 103 | static 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.com | a2bbc6e | 2013-11-01 17:36:03 +0000 | [diff] [blame] | 108 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 109 | |
| 110 | static const char* gOpStrs[] = { |
| 111 | "kDifference_SkPathOp", |
| 112 | "kIntersect_SkPathOp", |
| 113 | "kUnion_SkPathOp", |
| 114 | "kXor_PathOp", |
| 115 | "kReverseDifference_SkPathOp", |
| 116 | }; |
| 117 | |
caryclark | 03b03ca | 2015-04-23 09:13:37 -0700 | [diff] [blame] | 118 | const char* SkPathOpsDebug::OpStr(SkPathOp op) { |
| 119 | return gOpStrs[op]; |
| 120 | } |
| 121 | |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 122 | static 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 | |
| 127 | SK_DECLARE_STATIC_MUTEX(gTestMutex); |
| 128 | |
| 129 | void 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.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 137 | |
caryclark | 624637c | 2015-05-11 07:21:27 -0700 | [diff] [blame] | 138 | #include "SkPathOpsCubic.h" |
| 139 | #include "SkPathOpsQuad.h" |
commit-bot@chromium.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 140 | |
caryclark | 624637c | 2015-05-11 07:21:27 -0700 | [diff] [blame] | 141 | SkDCubic 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; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 151 | } |
caryclark | 624637c | 2015-05-11 07:21:27 -0700 | [diff] [blame] | 152 | |
| 153 | #include "SkOpAngle.h" |
| 154 | #include "SkOpCoincidence.h" |
| 155 | #include "SkOpSegment.h" |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 156 | |
| 157 | SkOpAngle* 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 | |
| 170 | void SkOpSegment::debugReset() { |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 171 | this->init(this->fPts, this->fWeight, this->contour(), this->verb()); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 172 | } |
| 173 | |
| 174 | #if DEBUG_ACTIVE_SPANS |
| 175 | void 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 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 187 | if (lastId == this->debugID() && lastT == span->t()) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 188 | continue; |
| 189 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 190 | lastId = this->debugID(); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 191 | lastT = span->t(); |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 192 | SkDebugf("%s id=%d", __FUNCTION__, this->debugID()); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 193 | 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 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 197 | if (SkPath::kConic_Verb == fVerb) { |
| 198 | SkDebugf(" %1.9gf", fWeight); |
| 199 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 200 | 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()); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 203 | if (span->windSum() == SK_MinS32) { |
caryclark | 624637c | 2015-05-11 07:21:27 -0700 | [diff] [blame] | 204 | SkDebugf(" windSum=?"); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 205 | } else { |
caryclark | 624637c | 2015-05-11 07:21:27 -0700 | [diff] [blame] | 206 | SkDebugf(" windSum=%d", span->windSum()); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 207 | } |
caryclark | 624637c | 2015-05-11 07:21:27 -0700 | [diff] [blame] | 208 | 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 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 217 | SkDebugf("\n"); |
| 218 | } while ((span = span->next()->upCastable())); |
| 219 | } |
| 220 | #endif |
| 221 | |
| 222 | #if DEBUG_MARK_DONE |
| 223 | void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int winding) { |
| 224 | const SkPoint& pt = span->ptT()->fPt; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 225 | SkDebugf("%s id=%d", fun, this->debugID()); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 226 | 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 | |
| 246 | void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int winding, |
| 247 | int oppWinding) { |
| 248 | const SkPoint& pt = span->ptT()->fPt; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 249 | SkDebugf("%s id=%d", fun, this->debugID()); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 250 | 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 |
| 285 | SkString 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; |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 296 | 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; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 301 | 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 | |
caryclark | 624637c | 2015-05-11 07:21:27 -0700 | [diff] [blame] | 312 | #if DEBUG_SORT |
commit-bot@chromium.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 313 | void SkOpAngle::debugLoop() const { |
caryclark | e4097e3 | 2014-06-18 07:24:19 -0700 | [diff] [blame] | 314 | const SkOpAngle* first = this; |
| 315 | const SkOpAngle* next = this; |
| 316 | do { |
| 317 | next->dumpOne(true); |
caryclark | 19eb3b2 | 2014-07-18 05:08:14 -0700 | [diff] [blame] | 318 | SkDebugf("\n"); |
caryclark | e4097e3 | 2014-06-18 07:24:19 -0700 | [diff] [blame] | 319 | next = next->fNext; |
| 320 | } while (next && next != first); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 321 | next = first; |
| 322 | do { |
| 323 | next->debugValidate(); |
| 324 | next = next->fNext; |
| 325 | } while (next && next != first); |
commit-bot@chromium.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 326 | } |
| 327 | #endif |
| 328 | |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 329 | void SkOpAngle::debugValidate() const { |
commit-bot@chromium.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 330 | #if DEBUG_VALIDATE |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 331 | 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; |
caryclark | 624637c | 2015-05-11 07:21:27 -0700 | [diff] [blame] | 354 | wind += next->debugSign() * (op ? minSpan->oppValue() : minSpan->windValue()); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 355 | if (useXor) { |
| 356 | wind &= 1; |
| 357 | } |
| 358 | useXor = op ? isXor : oppXor; |
| 359 | SkASSERT(lastOppXor == -1 || lastOppXor == (int) useXor); |
| 360 | lastOppXor = (int) useXor; |
caryclark | 624637c | 2015-05-11 07:21:27 -0700 | [diff] [blame] | 361 | opp += next->debugSign() * (op ? minSpan->windValue() : minSpan->oppValue()); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 362 | if (useXor) { |
| 363 | opp &= 1; |
| 364 | } |
| 365 | next = next->fNext; |
| 366 | } while (next && next != first); |
caryclark | 182b499 | 2015-05-14 05:45:54 -0700 | [diff] [blame] | 367 | SkASSERT(wind == 0 || !FLAGS_runFail); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 368 | SkASSERT(opp == 0 || !FLAGS_runFail); |
| 369 | #endif |
| 370 | } |
| 371 | |
commit-bot@chromium.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 372 | void SkOpAngle::debugValidateNext() const { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 373 | #if !FORCE_RELEASE |
commit-bot@chromium.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 374 | const SkOpAngle* first = this; |
| 375 | const SkOpAngle* next = first; |
| 376 | SkTDArray<const SkOpAngle*>(angles); |
| 377 | do { |
caryclark | dac1d17 | 2014-06-17 05:15:38 -0700 | [diff] [blame] | 378 | // SK_ALWAYSBREAK(next->fSegment->debugContains(next)); |
commit-bot@chromium.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 379 | angles.push(next); |
| 380 | next = next->next(); |
| 381 | if (next == first) { |
| 382 | break; |
| 383 | } |
commit-bot@chromium.org | 45d1d1d | 2014-04-30 18:24:16 +0000 | [diff] [blame] | 384 | SK_ALWAYSBREAK(!angles.contains(next)); |
commit-bot@chromium.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 385 | if (!next) { |
| 386 | return; |
| 387 | } |
| 388 | } while (true); |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 389 | #endif |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 390 | } |
reed | 0dc4dd6 | 2015-03-24 13:55:33 -0700 | [diff] [blame] | 391 | |
caryclark | 624637c | 2015-05-11 07:21:27 -0700 | [diff] [blame] | 392 | void 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.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 405 | void SkOpSegment::debugValidate() const { |
| 406 | #if DEBUG_VALIDATE |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 407 | const SkOpSpanBase* span = &fHead; |
| 408 | double lastT = -1; |
| 409 | const SkOpSpanBase* prev = NULL; |
| 410 | int count = 0; |
commit-bot@chromium.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 411 | int done = 0; |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 412 | 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); |
caryclark | 08bc848 | 2015-04-24 09:08:57 -0700 | [diff] [blame] | 428 | SkASSERT(count >= fDoneCount); |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 429 | SkASSERT(span->final()); |
| 430 | span->debugValidate(); |
commit-bot@chromium.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 431 | #endif |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 432 | } |
| 433 | |
| 434 | bool 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.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 450 | } |
| 451 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 452 | ++loop; |
| 453 | } while ((next = nextCoin) && next != this); |
| 454 | return true; |
| 455 | } |
| 456 | |
| 457 | void 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.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 469 | } |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 470 | if (fFromAngle) { |
| 471 | fFromAngle->debugValidate(); |
| 472 | } |
| 473 | if (!this->final() && this->upCast()->toAngle()) { |
| 474 | this->upCast()->toAngle()->debugValidate(); |
| 475 | } |
| 476 | #endif |
| 477 | } |
| 478 | |
| 479 | bool 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 | |
caryclark | 624637c | 2015-05-11 07:21:27 -0700 | [diff] [blame] | 502 | // called only by test code |
| 503 | int 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 | |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 524 | #include "SkOpContour.h" |
| 525 | |
| 526 | int 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 | |
| 548 | void SkOpPtT::debugValidate() const { |
| 549 | #if DEBUG_VALIDATE |
caryclark | 4e1a4c9 | 2015-05-18 12:56:57 -0700 | [diff] [blame^] | 550 | SkOpGlobalState::Phase phase = contour()->globalState()->phase(); |
| 551 | if (phase == SkOpGlobalState::kIntersecting |
| 552 | || phase == SkOpGlobalState::kFixWinding) { |
caryclark | 5435929 | 2015-03-26 07:52:43 -0700 | [diff] [blame] | 553 | return; |
| 554 | } |
| 555 | SkASSERT(fNext); |
| 556 | SkASSERT(fNext != this); |
| 557 | SkASSERT(fNext->fNext); |
| 558 | SkASSERT(debugLoopLimit(false) == 0); |
commit-bot@chromium.org | 4431e77 | 2014-04-14 17:08:59 +0000 | [diff] [blame] | 559 | #endif |
| 560 | } |
caryclark | 1049f12 | 2015-04-20 08:31:59 -0700 | [diff] [blame] | 561 | |
| 562 | static 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 | |
| 578 | static 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 | |
| 589 | static 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 | |
| 629 | static const char* gFillTypeStr[] = { |
| 630 | "kWinding_FillType", |
| 631 | "kEvenOdd_FillType", |
| 632 | "kInverseWinding_FillType", |
| 633 | "kInverseEvenOdd_FillType" |
| 634 | }; |
| 635 | |
| 636 | void 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 | } |