| OLD | NEW |
| 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 "SkPathOpsDebug.h" | 8 #include "SkPathOpsDebug.h" |
| 9 #include "SkPath.h" | 9 #include "SkPath.h" |
| 10 #if DEBUG_ANGLE |
| 11 #include "SkString.h" |
| 12 #endif |
| 13 |
| 14 #if DEBUG_VALIDATE |
| 15 extern bool FLAGS_runFail; |
| 16 #endif |
| 10 | 17 |
| 11 #if defined SK_DEBUG || !FORCE_RELEASE | 18 #if defined SK_DEBUG || !FORCE_RELEASE |
| 12 | 19 |
| 13 const char* SkPathOpsDebug::kLVerbStr[] = {"", "line", "quad", "cubic"}; | 20 const char* SkPathOpsDebug::kLVerbStr[] = {"", "line", "quad", "cubic"}; |
| 14 | 21 |
| 15 #if defined(SK_DEBUG) || !FORCE_RELEASE | 22 #if defined(SK_DEBUG) || !FORCE_RELEASE |
| 16 int SkPathOpsDebug::gContourID = 0; | 23 int SkPathOpsDebug::gContourID = 0; |
| 17 int SkPathOpsDebug::gSegmentID = 0; | 24 int SkPathOpsDebug::gSegmentID = 0; |
| 18 #endif | 25 #endif |
| 19 | 26 |
| 20 #if DEBUG_SORT || DEBUG_SWAP_TOP | 27 #if DEBUG_SORT || DEBUG_SWAP_TOP |
| 21 int SkPathOpsDebug::gSortCountDefault = SK_MaxS32; | 28 int SkPathOpsDebug::gSortCountDefault = SK_MaxS32; |
| 22 int SkPathOpsDebug::gSortCount; | 29 int SkPathOpsDebug::gSortCount; |
| 23 #endif | 30 #endif |
| 24 | 31 |
| 25 #if DEBUG_ACTIVE_OP | 32 #if DEBUG_ACTIVE_OP |
| 26 const char* SkPathOpsDebug::kPathOpStr[] = {"diff", "sect", "union", "xor"}; | 33 const char* SkPathOpsDebug::kPathOpStr[] = {"diff", "sect", "union", "xor"}; |
| 27 #endif | 34 #endif |
| 28 | 35 |
| 29 bool SkPathOpsDebug::ChaseContains(const SkTDArray<SkOpSpan *>& chaseArray, | 36 bool SkPathOpsDebug::ChaseContains(const SkTDArray<SkOpSpanBase* >& chaseArray, |
| 30 const SkOpSpan* span) { | 37 const SkOpSpanBase* span) { |
| 31 for (int index = 0; index < chaseArray.count(); ++index) { | 38 for (int index = 0; index < chaseArray.count(); ++index) { |
| 32 const SkOpSpan* entry = chaseArray[index]; | 39 const SkOpSpanBase* entry = chaseArray[index]; |
| 33 if (entry == span) { | 40 if (entry == span) { |
| 34 return true; | 41 return true; |
| 35 } | 42 } |
| 36 } | 43 } |
| 37 return false; | 44 return false; |
| 38 } | 45 } |
| 39 | 46 |
| 40 void SkPathOpsDebug::MathematicaIze(char* str, size_t bufferLen) { | 47 void SkPathOpsDebug::MathematicaIze(char* str, size_t bufferLen) { |
| 41 size_t len = strlen(str); | 48 size_t len = strlen(str); |
| 42 bool num = false; | 49 bool num = false; |
| (...skipping 15 matching lines...) Expand all Loading... |
| 58 return wind > SK_MinS32 + 0xFFFF && wind < SK_MaxS32 - 0xFFFF; | 65 return wind > SK_MinS32 + 0xFFFF && wind < SK_MaxS32 - 0xFFFF; |
| 59 } | 66 } |
| 60 | 67 |
| 61 void SkPathOpsDebug::WindingPrintf(int wind) { | 68 void SkPathOpsDebug::WindingPrintf(int wind) { |
| 62 if (wind == SK_MinS32) { | 69 if (wind == SK_MinS32) { |
| 63 SkDebugf("?"); | 70 SkDebugf("?"); |
| 64 } else { | 71 } else { |
| 65 SkDebugf("%d", wind); | 72 SkDebugf("%d", wind); |
| 66 } | 73 } |
| 67 } | 74 } |
| 75 #endif // defined SK_DEBUG || !FORCE_RELEASE |
| 76 |
| 68 | 77 |
| 69 #if DEBUG_SHOW_TEST_NAME | 78 #if DEBUG_SHOW_TEST_NAME |
| 70 void* SkPathOpsDebug::CreateNameStr() { | 79 void* SkPathOpsDebug::CreateNameStr() { |
| 71 return SkNEW_ARRAY(char, DEBUG_FILENAME_STRING_LENGTH); | 80 return SkNEW_ARRAY(char, DEBUG_FILENAME_STRING_LENGTH); |
| 72 } | 81 } |
| 73 | 82 |
| 74 void SkPathOpsDebug::DeleteNameStr(void* v) { | 83 void SkPathOpsDebug::DeleteNameStr(void* v) { |
| 75 SkDELETE_ARRAY(reinterpret_cast<char* >(v)); | 84 SkDELETE_ARRAY(reinterpret_cast<char* >(v)); |
| 76 } | 85 } |
| 77 | 86 |
| (...skipping 12 matching lines...) Expand all Loading... |
| 90 ++dec; | 99 ++dec; |
| 91 SK_SNPRINTF(num, DEBUG_FILENAME_STRING_LENGTH - (num - test), "%d", dec); | 100 SK_SNPRINTF(num, DEBUG_FILENAME_STRING_LENGTH - (num - test), "%d", dec); |
| 92 } | 101 } |
| 93 #endif | 102 #endif |
| 94 | 103 |
| 95 #if !DEBUG_SHOW_TEST_NAME // enable when building without extended test | 104 #if !DEBUG_SHOW_TEST_NAME // enable when building without extended test |
| 96 void SkPathOpsDebug::ShowPath(const SkPath& one, const SkPath& two, SkPathOp op,
const char* name) { | 105 void SkPathOpsDebug::ShowPath(const SkPath& one, const SkPath& two, SkPathOp op,
const char* name) { |
| 97 } | 106 } |
| 98 #endif | 107 #endif |
| 99 | 108 |
| 100 #endif // defined SK_DEBUG || !FORCE_RELEASE | |
| 101 | |
| 102 #include "SkOpAngle.h" | 109 #include "SkOpAngle.h" |
| 103 #include "SkOpSegment.h" | 110 #include "SkOpSegment.h" |
| 104 | 111 |
| 112 #if DEBUG_SWAP_TOP |
| 113 int SkOpSegment::debugInflections(const SkOpSpanBase* start, const SkOpSpanBase*
end) const { |
| 114 if (fVerb != SkPath::kCubic_Verb) { |
| 115 return false; |
| 116 } |
| 117 SkDCubic dst = SkDCubic::SubDivide(fPts, start->t(), end->t()); |
| 118 double inflections[2]; |
| 119 return dst.findInflections(inflections); |
| 120 } |
| 121 #endif |
| 122 |
| 123 SkOpAngle* SkOpSegment::debugLastAngle() { |
| 124 SkOpAngle* result = NULL; |
| 125 SkOpSpan* span = this->head(); |
| 126 do { |
| 127 if (span->toAngle()) { |
| 128 SkASSERT(!result); |
| 129 result = span->toAngle(); |
| 130 } |
| 131 } while ((span = span->next()->upCastable())); |
| 132 SkASSERT(result); |
| 133 return result; |
| 134 } |
| 135 |
| 136 void SkOpSegment::debugReset() { |
| 137 this->init(this->fPts, this->contour(), this->verb()); |
| 138 } |
| 139 |
| 140 #if DEBUG_ACTIVE_SPANS |
| 141 void SkOpSegment::debugShowActiveSpans() const { |
| 142 debugValidate(); |
| 143 if (done()) { |
| 144 return; |
| 145 } |
| 146 int lastId = -1; |
| 147 double lastT = -1; |
| 148 const SkOpSpan* span = &fHead; |
| 149 do { |
| 150 if (span->done()) { |
| 151 continue; |
| 152 } |
| 153 if (lastId == fID && lastT == span->t()) { |
| 154 continue; |
| 155 } |
| 156 lastId = fID; |
| 157 lastT = span->t(); |
| 158 SkDebugf("%s id=%d", __FUNCTION__, fID); |
| 159 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); |
| 160 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { |
| 161 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); |
| 162 } |
| 163 const SkOpPtT* ptT = span->ptT(); |
| 164 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", ptT->fT, ptT->fPt.fX, ptT->fPt.fY); |
| 165 SkDebugf(" tEnd=%1.9g", span->next()->t()); |
| 166 SkDebugf(" windSum="); |
| 167 if (span->windSum() == SK_MinS32) { |
| 168 SkDebugf("?"); |
| 169 } else { |
| 170 SkDebugf("%d", span->windSum()); |
| 171 } |
| 172 SkDebugf(" windValue=%d oppValue=%d", span->windValue(), span->oppValue(
)); |
| 173 SkDebugf("\n"); |
| 174 } while ((span = span->next()->upCastable())); |
| 175 } |
| 176 #endif |
| 177 |
| 178 #if DEBUG_MARK_DONE |
| 179 void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int
winding) { |
| 180 const SkPoint& pt = span->ptT()->fPt; |
| 181 SkDebugf("%s id=%d", fun, fID); |
| 182 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); |
| 183 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { |
| 184 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); |
| 185 } |
| 186 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=", |
| 187 span->t(), span->debugID(), pt.fX, pt.fY, span->next()->t()); |
| 188 if (winding == SK_MinS32) { |
| 189 SkDebugf("?"); |
| 190 } else { |
| 191 SkDebugf("%d", winding); |
| 192 } |
| 193 SkDebugf(" windSum="); |
| 194 if (span->windSum() == SK_MinS32) { |
| 195 SkDebugf("?"); |
| 196 } else { |
| 197 SkDebugf("%d", span->windSum()); |
| 198 } |
| 199 SkDebugf(" windValue=%d\n", span->windValue()); |
| 200 } |
| 201 |
| 202 void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan* span, int
winding, |
| 203 int oppWinding) { |
| 204 const SkPoint& pt = span->ptT()->fPt; |
| 205 SkDebugf("%s id=%d", fun, fID); |
| 206 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); |
| 207 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { |
| 208 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); |
| 209 } |
| 210 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=", |
| 211 span->t(), span->debugID(), pt.fX, pt.fY, span->next()->t(), winding
, oppWinding); |
| 212 if (winding == SK_MinS32) { |
| 213 SkDebugf("?"); |
| 214 } else { |
| 215 SkDebugf("%d", winding); |
| 216 } |
| 217 SkDebugf(" newOppSum="); |
| 218 if (oppWinding == SK_MinS32) { |
| 219 SkDebugf("?"); |
| 220 } else { |
| 221 SkDebugf("%d", oppWinding); |
| 222 } |
| 223 SkDebugf(" oppSum="); |
| 224 if (span->oppSum() == SK_MinS32) { |
| 225 SkDebugf("?"); |
| 226 } else { |
| 227 SkDebugf("%d", span->oppSum()); |
| 228 } |
| 229 SkDebugf(" windSum="); |
| 230 if (span->windSum() == SK_MinS32) { |
| 231 SkDebugf("?"); |
| 232 } else { |
| 233 SkDebugf("%d", span->windSum()); |
| 234 } |
| 235 SkDebugf(" windValue=%d oppValue=%d\n", span->windValue(), span->oppValue())
; |
| 236 } |
| 237 |
| 238 #endif |
| 239 |
| 240 #if DEBUG_ANGLE |
| 241 SkString SkOpAngle::debugPart() const { |
| 242 SkString result; |
| 243 switch (this->segment()->verb()) { |
| 244 case SkPath::kLine_Verb: |
| 245 result.printf(LINE_DEBUG_STR " id=%d", LINE_DEBUG_DATA(fCurvePart), |
| 246 this->segment()->debugID()); |
| 247 break; |
| 248 case SkPath::kQuad_Verb: |
| 249 result.printf(QUAD_DEBUG_STR " id=%d", QUAD_DEBUG_DATA(fCurvePart), |
| 250 this->segment()->debugID()); |
| 251 break; |
| 252 case SkPath::kCubic_Verb: |
| 253 result.printf(CUBIC_DEBUG_STR " id=%d", CUBIC_DEBUG_DATA(fCurvePart)
, |
| 254 this->segment()->debugID()); |
| 255 break; |
| 256 default: |
| 257 SkASSERT(0); |
| 258 } |
| 259 return result; |
| 260 } |
| 261 #endif |
| 262 |
| 105 #if DEBUG_SORT | 263 #if DEBUG_SORT |
| 106 void SkOpAngle::debugLoop() const { | 264 void SkOpAngle::debugLoop() const { |
| 107 const SkOpAngle* first = this; | 265 const SkOpAngle* first = this; |
| 108 const SkOpAngle* next = this; | 266 const SkOpAngle* next = this; |
| 109 do { | 267 do { |
| 110 next->dumpOne(true); | 268 next->dumpOne(true); |
| 111 SkDebugf("\n"); | 269 SkDebugf("\n"); |
| 112 next = next->fNext; | 270 next = next->fNext; |
| 113 } while (next && next != first); | 271 } while (next && next != first); |
| 114 } | 272 next = first; |
| 115 #endif | 273 do { |
| 116 | 274 next->debugValidate(); |
| 117 #if DEBUG_ANGLE | 275 next = next->fNext; |
| 118 void SkOpAngle::debugSameAs(const SkOpAngle* compare) const { | 276 } while (next && next != first); |
| 119 SK_ALWAYSBREAK(fSegment == compare->fSegment); | 277 } |
| 120 const SkOpSpan& startSpan = fSegment->span(fStart); | 278 #endif |
| 121 const SkOpSpan& oStartSpan = fSegment->span(compare->fStart); | 279 |
| 122 SK_ALWAYSBREAK(startSpan.fToAngle == oStartSpan.fToAngle); | 280 void SkOpAngle::debugValidate() const { |
| 123 SK_ALWAYSBREAK(startSpan.fFromAngle == oStartSpan.fFromAngle); | |
| 124 const SkOpSpan& endSpan = fSegment->span(fEnd); | |
| 125 const SkOpSpan& oEndSpan = fSegment->span(compare->fEnd); | |
| 126 SK_ALWAYSBREAK(endSpan.fToAngle == oEndSpan.fToAngle); | |
| 127 SK_ALWAYSBREAK(endSpan.fFromAngle == oEndSpan.fFromAngle); | |
| 128 } | |
| 129 #endif | |
| 130 | |
| 131 #if DEBUG_VALIDATE | 281 #if DEBUG_VALIDATE |
| 282 const SkOpAngle* first = this; |
| 283 const SkOpAngle* next = this; |
| 284 int wind = 0; |
| 285 int opp = 0; |
| 286 int lastXor = -1; |
| 287 int lastOppXor = -1; |
| 288 do { |
| 289 if (next->unorderable()) { |
| 290 return; |
| 291 } |
| 292 const SkOpSpan* minSpan = next->start()->starter(next->end()); |
| 293 if (minSpan->windValue() == SK_MinS32) { |
| 294 return; |
| 295 } |
| 296 bool op = next->segment()->operand(); |
| 297 bool isXor = next->segment()->isXor(); |
| 298 bool oppXor = next->segment()->oppXor(); |
| 299 SkASSERT(!DEBUG_LIMIT_WIND_SUM || between(0, minSpan->windValue(), DEBUG
_LIMIT_WIND_SUM)); |
| 300 SkASSERT(!DEBUG_LIMIT_WIND_SUM |
| 301 || between(-DEBUG_LIMIT_WIND_SUM, minSpan->oppValue(), DEBUG_LIM
IT_WIND_SUM)); |
| 302 bool useXor = op ? oppXor : isXor; |
| 303 SkASSERT(lastXor == -1 || lastXor == (int) useXor); |
| 304 lastXor = (int) useXor; |
| 305 wind += next->sign() * (op ? minSpan->oppValue() : minSpan->windValue())
; |
| 306 if (useXor) { |
| 307 wind &= 1; |
| 308 } |
| 309 useXor = op ? isXor : oppXor; |
| 310 SkASSERT(lastOppXor == -1 || lastOppXor == (int) useXor); |
| 311 lastOppXor = (int) useXor; |
| 312 opp += next->sign() * (op ? minSpan->windValue() : minSpan->oppValue()); |
| 313 if (useXor) { |
| 314 opp &= 1; |
| 315 } |
| 316 next = next->fNext; |
| 317 } while (next && next != first); |
| 318 SkASSERT(wind == 0); |
| 319 SkASSERT(opp == 0 || !FLAGS_runFail); |
| 320 #endif |
| 321 } |
| 322 |
| 132 void SkOpAngle::debugValidateNext() const { | 323 void SkOpAngle::debugValidateNext() const { |
| 324 #if !FORCE_RELEASE |
| 133 const SkOpAngle* first = this; | 325 const SkOpAngle* first = this; |
| 134 const SkOpAngle* next = first; | 326 const SkOpAngle* next = first; |
| 135 SkTDArray<const SkOpAngle*>(angles); | 327 SkTDArray<const SkOpAngle*>(angles); |
| 136 do { | 328 do { |
| 137 // SK_ALWAYSBREAK(next->fSegment->debugContains(next)); | 329 // SK_ALWAYSBREAK(next->fSegment->debugContains(next)); |
| 138 angles.push(next); | 330 angles.push(next); |
| 139 next = next->next(); | 331 next = next->next(); |
| 140 if (next == first) { | 332 if (next == first) { |
| 141 break; | 333 break; |
| 142 } | 334 } |
| 143 SK_ALWAYSBREAK(!angles.contains(next)); | 335 SK_ALWAYSBREAK(!angles.contains(next)); |
| 144 if (!next) { | 336 if (!next) { |
| 145 return; | 337 return; |
| 146 } | 338 } |
| 147 } while (true); | 339 } while (true); |
| 148 } | 340 #endif |
| 149 | 341 } |
| 150 void SkOpAngle::debugValidateLoop() const { | 342 |
| 151 const SkOpAngle* first = this; | 343 void SkOpSegment::debugValidate() const { |
| 152 const SkOpAngle* next = first; | 344 #if DEBUG_VALIDATE |
| 153 SK_ALWAYSBREAK(first->next() != first); | 345 const SkOpSpanBase* span = &fHead; |
| 154 int signSum = 0; | 346 double lastT = -1; |
| 155 int oppSum = 0; | 347 const SkOpSpanBase* prev = NULL; |
| 156 bool firstOperand = fSegment->operand(); | 348 int count = 0; |
| 157 bool unorderable = false; | 349 int done = 0; |
| 158 do { | 350 do { |
| 159 unorderable |= next->fUnorderable; | 351 if (!span->final()) { |
| 160 const SkOpSegment* segment = next->fSegment; | 352 ++count; |
| 161 bool operandsMatch = firstOperand == segment->operand(); | 353 done += span->upCast()->done() ? 1 : 0; |
| 162 signSum += operandsMatch ? segment->spanSign(next) : segment->oppSign(ne
xt); | 354 } |
| 163 oppSum += operandsMatch ? segment->oppSign(next) : segment->spanSign(nex
t); | 355 SkASSERT(span->segment() == this); |
| 164 const SkOpSpan& span = segment->span(SkMin32(next->fStart, next->fEnd)); | 356 SkASSERT(!prev || prev->upCast()->next() == span); |
| 165 if (segment->_xor()) { | 357 SkASSERT(!prev || prev == span->prev()); |
| 166 // SK_ALWAYSBREAK(span.fWindValue == 1); | 358 prev = span; |
| 167 // SK_ALWAYSBREAK(span.fWindSum == SK_MinS32 || span.fWindSum == 1); | 359 double t = span->ptT()->fT; |
| 168 } | 360 SkASSERT(lastT < t); |
| 169 if (segment->oppXor()) { | 361 lastT = t; |
| 170 SK_ALWAYSBREAK(span.fOppValue == 0 || abs(span.fOppValue) == 1); | 362 span->debugValidate(); |
| 171 // SK_ALWAYSBREAK(span.fOppSum == SK_MinS32 || span.fOppSum == 0 || a
bs(span.fOppSum) == 1); | 363 } while (!span->final() && (span = span->upCast()->next())); |
| 172 } | 364 SkASSERT(count == fCount); |
| 173 next = next->next(); | 365 SkASSERT(done == fDoneCount); |
| 174 if (!next) { | 366 SkASSERT(span->final()); |
| 175 return; | 367 span->debugValidate(); |
| 176 } | 368 #endif |
| 177 } while (next != first); | 369 } |
| 178 if (unorderable) { | 370 |
| 179 return; | 371 bool SkOpSpanBase::debugCoinEndLoopCheck() const { |
| 180 } | 372 int loop = 0; |
| 181 SK_ALWAYSBREAK(!signSum || fSegment->_xor()); | 373 const SkOpSpanBase* next = this; |
| 182 SK_ALWAYSBREAK(!oppSum || fSegment->oppXor()); | 374 SkOpSpanBase* nextCoin; |
| 183 int lastWinding; | 375 do { |
| 184 int lastOppWinding; | 376 nextCoin = next->fCoinEnd; |
| 185 int winding; | 377 SkASSERT(nextCoin == this || nextCoin->fCoinEnd != nextCoin); |
| 186 int oppWinding; | 378 for (int check = 1; check < loop - 1; ++check) { |
| 187 do { | 379 const SkOpSpanBase* checkCoin = this->fCoinEnd; |
| 188 const SkOpSegment* segment = next->fSegment; | 380 const SkOpSpanBase* innerCoin = checkCoin; |
| 189 const SkOpSpan& span = segment->span(SkMin32(next->fStart, next->fEnd)); | 381 for (int inner = check + 1; inner < loop; ++inner) { |
| 190 winding = span.fWindSum; | 382 innerCoin = innerCoin->fCoinEnd; |
| 191 if (winding != SK_MinS32) { | 383 if (checkCoin == innerCoin) { |
| 192 // SK_ALWAYSBREAK(winding != 0); | 384 SkDebugf("*** bad coincident end loop ***\n"); |
| 193 SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(winding)); | 385 return false; |
| 194 lastWinding = winding; | |
| 195 int diffWinding = segment->spanSign(next); | |
| 196 if (!segment->_xor()) { | |
| 197 SK_ALWAYSBREAK(diffWinding != 0); | |
| 198 bool sameSign = (winding > 0) == (diffWinding > 0); | |
| 199 winding -= sameSign ? diffWinding : -diffWinding; | |
| 200 SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(winding)); | |
| 201 SK_ALWAYSBREAK(abs(winding) <= abs(lastWinding)); | |
| 202 if (!sameSign) { | |
| 203 SkTSwap(winding, lastWinding); | |
| 204 } | 386 } |
| 205 } | 387 } |
| 206 lastOppWinding = oppWinding = span.fOppSum; | 388 } |
| 207 if (oppWinding != SK_MinS32 && !segment->oppXor()) { | 389 ++loop; |
| 208 int oppDiffWinding = segment->oppSign(next); | 390 } while ((next = nextCoin) && next != this); |
| 209 // SK_ALWAYSBREAK(abs(oppDiffWinding) <= abs(diffWinding) || segm
ent->_xor()); | 391 return true; |
| 210 if (oppDiffWinding) { | 392 } |
| 211 bool oppSameSign = (oppWinding > 0) == (oppDiffWinding > 0); | 393 |
| 212 oppWinding -= oppSameSign ? oppDiffWinding : -oppDiffWinding
; | 394 void SkOpSpanBase::debugValidate() const { |
| 213 SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(oppWinding)); | 395 #if DEBUG_VALIDATE |
| 214 SK_ALWAYSBREAK(abs(oppWinding) <= abs(lastOppWinding)); | 396 const SkOpPtT* ptT = &fPtT; |
| 215 if (!oppSameSign) { | 397 SkASSERT(ptT->span() == this); |
| 216 SkTSwap(oppWinding, lastOppWinding); | 398 do { |
| 217 } | 399 // SkASSERT(SkDPoint::RoughlyEqual(fPtT.fPt, ptT->fPt)); |
| 400 ptT->debugValidate(); |
| 401 ptT = ptT->next(); |
| 402 } while (ptT != &fPtT); |
| 403 SkASSERT(this->debugCoinEndLoopCheck()); |
| 404 if (!this->final()) { |
| 405 SkASSERT(this->upCast()->debugCoinLoopCheck()); |
| 406 } |
| 407 if (fFromAngle) { |
| 408 fFromAngle->debugValidate(); |
| 409 } |
| 410 if (!this->final() && this->upCast()->toAngle()) { |
| 411 this->upCast()->toAngle()->debugValidate(); |
| 412 } |
| 413 #endif |
| 414 } |
| 415 |
| 416 bool SkOpSpan::debugCoinLoopCheck() const { |
| 417 int loop = 0; |
| 418 const SkOpSpan* next = this; |
| 419 SkOpSpan* nextCoin; |
| 420 do { |
| 421 nextCoin = next->fCoincident; |
| 422 SkASSERT(nextCoin == this || nextCoin->fCoincident != nextCoin); |
| 423 for (int check = 1; check < loop - 1; ++check) { |
| 424 const SkOpSpan* checkCoin = this->fCoincident; |
| 425 const SkOpSpan* innerCoin = checkCoin; |
| 426 for (int inner = check + 1; inner < loop; ++inner) { |
| 427 innerCoin = innerCoin->fCoincident; |
| 428 if (checkCoin == innerCoin) { |
| 429 SkDebugf("*** bad coincident loop ***\n"); |
| 430 return false; |
| 218 } | 431 } |
| 219 } | 432 } |
| 220 firstOperand = segment->operand(); | 433 } |
| 221 break; | 434 ++loop; |
| 222 } | 435 } while ((next = nextCoin) && next != this); |
| 223 SK_ALWAYSBREAK(span.fOppSum == SK_MinS32); | 436 return true; |
| 224 next = next->next(); | 437 } |
| 225 } while (next != first); | 438 |
| 226 if (winding == SK_MinS32) { | 439 #include "SkOpContour.h" |
| 227 return; | 440 |
| 228 } | 441 int SkOpPtT::debugLoopLimit(bool report) const { |
| 229 SK_ALWAYSBREAK(oppWinding == SK_MinS32 || SkPathOpsDebug::ValidWind(oppWindi
ng)); | 442 int loop = 0; |
| 230 first = next; | 443 const SkOpPtT* next = this; |
| 231 next = next->next(); | 444 do { |
| 232 do { | 445 for (int check = 1; check < loop - 1; ++check) { |
| 233 const SkOpSegment* segment = next->fSegment; | 446 const SkOpPtT* checkPtT = this->fNext; |
| 234 lastWinding = winding; | 447 const SkOpPtT* innerPtT = checkPtT; |
| 235 lastOppWinding = oppWinding; | 448 for (int inner = check + 1; inner < loop; ++inner) { |
| 236 bool operandsMatch = firstOperand == segment->operand(); | 449 innerPtT = innerPtT->fNext; |
| 237 if (operandsMatch) { | 450 if (checkPtT == innerPtT) { |
| 238 if (!segment->_xor()) { | 451 if (report) { |
| 239 winding -= segment->spanSign(next); | 452 SkDebugf("*** bad ptT loop ***\n"); |
| 240 SK_ALWAYSBREAK(winding != lastWinding); | 453 } |
| 241 SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(winding)); | 454 return loop; |
| 242 } | |
| 243 if (!segment->oppXor()) { | |
| 244 int oppDiffWinding = segment->oppSign(next); | |
| 245 if (oppWinding != SK_MinS32) { | |
| 246 oppWinding -= oppDiffWinding; | |
| 247 SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(oppWinding)); | |
| 248 } else { | |
| 249 SK_ALWAYSBREAK(oppDiffWinding == 0); | |
| 250 } | 455 } |
| 251 } | 456 } |
| 252 } else { | 457 } |
| 253 if (!segment->oppXor()) { | 458 ++loop; |
| 254 winding -= segment->oppSign(next); | 459 } while ((next = next->fNext) && next != this); |
| 255 SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(winding)); | 460 return 0; |
| 256 } | 461 } |
| 257 if (!segment->_xor()) { | 462 |
| 258 oppWinding -= segment->spanSign(next); | 463 void SkOpPtT::debugValidate() const { |
| 259 SK_ALWAYSBREAK(oppWinding != lastOppWinding); | 464 #if DEBUG_VALIDATE |
| 260 SK_ALWAYSBREAK(SkPathOpsDebug::ValidWind(oppWinding)); | 465 if (contour()->globalState()->phase() == SkOpGlobalState::kIntersecting) { |
| 261 } | |
| 262 } | |
| 263 bool useInner = SkOpSegment::UseInnerWinding(lastWinding, winding); | |
| 264 int sumWinding = useInner ? winding : lastWinding; | |
| 265 bool oppUseInner = SkOpSegment::UseInnerWinding(lastOppWinding, oppWindi
ng); | |
| 266 int oppSumWinding = oppUseInner ? oppWinding : lastOppWinding; | |
| 267 if (!operandsMatch) { | |
| 268 SkTSwap(useInner, oppUseInner); | |
| 269 SkTSwap(sumWinding, oppSumWinding); | |
| 270 } | |
| 271 const SkOpSpan& span = segment->span(SkMin32(next->fStart, next->fEnd)); | |
| 272 if (winding == -lastWinding) { | |
| 273 if (span.fWindSum != SK_MinS32) { | |
| 274 SkDebugf("%s useInner=%d spanSign=%d lastWinding=%d winding=%d w
indSum=%d\n", | |
| 275 __FUNCTION__, | |
| 276 useInner, segment->spanSign(next), lastWinding, winding,
span.fWindSum); | |
| 277 } | |
| 278 } | |
| 279 if (oppWinding != SK_MinS32) { | |
| 280 if (span.fOppSum != SK_MinS32) { | |
| 281 SK_ALWAYSBREAK(span.fOppSum == oppSumWinding || segment->oppXor(
) || segment->_xor()); | |
| 282 } | |
| 283 } else { | |
| 284 SK_ALWAYSBREAK(!firstOperand); | |
| 285 SK_ALWAYSBREAK(!segment->operand()); | |
| 286 SK_ALWAYSBREAK(!span.fOppValue); | |
| 287 } | |
| 288 next = next->next(); | |
| 289 } while (next != first); | |
| 290 } | |
| 291 #endif | |
| 292 | |
| 293 #if DEBUG_SWAP_TOP | |
| 294 bool SkOpSegment::controlsContainedByEnds(int tStart, int tEnd) const { | |
| 295 if (fVerb != SkPath::kCubic_Verb) { | |
| 296 return false; | |
| 297 } | |
| 298 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); | |
| 299 return dst.controlsContainedByEnds(); | |
| 300 } | |
| 301 #endif | |
| 302 | |
| 303 #if DEBUG_CONCIDENT | |
| 304 // SK_ALWAYSBREAK if pair has not already been added | |
| 305 void SkOpSegment::debugAddTPair(double t, const SkOpSegment& other, double other
T) const { | |
| 306 for (int i = 0; i < fTs.count(); ++i) { | |
| 307 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == other
T) { | |
| 308 return; | |
| 309 } | |
| 310 } | |
| 311 SK_ALWAYSBREAK(0); | |
| 312 } | |
| 313 #endif | |
| 314 | |
| 315 #if DEBUG_ANGLE | |
| 316 void SkOpSegment::debugCheckPointsEqualish(int tStart, int tEnd) const { | |
| 317 const SkPoint& basePt = fTs[tStart].fPt; | |
| 318 while (++tStart < tEnd) { | |
| 319 const SkPoint& cmpPt = fTs[tStart].fPt; | |
| 320 SK_ALWAYSBREAK(SkDPoint::ApproximatelyEqual(basePt, cmpPt)); | |
| 321 } | |
| 322 } | |
| 323 #endif | |
| 324 | |
| 325 #if DEBUG_SWAP_TOP | |
| 326 int SkOpSegment::debugInflections(int tStart, int tEnd) const { | |
| 327 if (fVerb != SkPath::kCubic_Verb) { | |
| 328 return false; | |
| 329 } | |
| 330 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); | |
| 331 double inflections[2]; | |
| 332 return dst.findInflections(inflections); | |
| 333 } | |
| 334 #endif | |
| 335 | |
| 336 const SkOpAngle* SkOpSegment::debugLastAngle() const { | |
| 337 const SkOpAngle* result = NULL; | |
| 338 for (int index = 0; index < count(); ++index) { | |
| 339 const SkOpSpan& span = this->span(index); | |
| 340 if (span.fToAngle) { | |
| 341 SkASSERT(!result); | |
| 342 result = span.fToAngle; | |
| 343 } | |
| 344 } | |
| 345 SkASSERT(result); | |
| 346 return result; | |
| 347 } | |
| 348 | |
| 349 void SkOpSegment::debugReset() { | |
| 350 fTs.reset(); | |
| 351 fAngles.reset(); | |
| 352 } | |
| 353 | |
| 354 #if DEBUG_CONCIDENT | |
| 355 void SkOpSegment::debugShowTs(const char* prefix) const { | |
| 356 SkDebugf("%s %s id=%d", __FUNCTION__, prefix, fID); | |
| 357 int lastWind = -1; | |
| 358 int lastOpp = -1; | |
| 359 double lastT = -1; | |
| 360 int i; | |
| 361 for (i = 0; i < fTs.count(); ++i) { | |
| 362 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue | |
| 363 || lastOpp != fTs[i].fOppValue; | |
| 364 if (change && lastWind >= 0) { | |
| 365 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]", | |
| 366 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp); | |
| 367 } | |
| 368 if (change) { | |
| 369 SkDebugf(" [o=%d", fTs[i].fOther->fID); | |
| 370 lastWind = fTs[i].fWindValue; | |
| 371 lastOpp = fTs[i].fOppValue; | |
| 372 lastT = fTs[i].fT; | |
| 373 } else { | |
| 374 SkDebugf(",%d", fTs[i].fOther->fID); | |
| 375 } | |
| 376 } | |
| 377 if (i <= 0) { | |
| 378 return; | 466 return; |
| 379 } | 467 } |
| 380 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]", | 468 SkASSERT(fNext); |
| 381 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp); | 469 SkASSERT(fNext != this); |
| 382 if (fOperand) { | 470 SkASSERT(fNext->fNext); |
| 383 SkDebugf(" operand"); | 471 SkASSERT(debugLoopLimit(false) == 0); |
| 384 } | 472 #endif |
| 385 if (done()) { | 473 } |
| 386 SkDebugf(" done"); | |
| 387 } | |
| 388 SkDebugf("\n"); | |
| 389 } | |
| 390 #endif | |
| 391 | |
| 392 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY | |
| 393 void SkOpSegment::debugShowActiveSpans() const { | |
| 394 debugValidate(); | |
| 395 if (done()) { | |
| 396 return; | |
| 397 } | |
| 398 #if DEBUG_ACTIVE_SPANS_SHORT_FORM | |
| 399 int lastId = -1; | |
| 400 double lastT = -1; | |
| 401 #endif | |
| 402 for (int i = 0; i < fTs.count(); ++i) { | |
| 403 if (fTs[i].fDone) { | |
| 404 continue; | |
| 405 } | |
| 406 SK_ALWAYSBREAK(i < fTs.count() - 1); | |
| 407 #if DEBUG_ACTIVE_SPANS_SHORT_FORM | |
| 408 if (lastId == fID && lastT == fTs[i].fT) { | |
| 409 continue; | |
| 410 } | |
| 411 lastId = fID; | |
| 412 lastT = fTs[i].fT; | |
| 413 #endif | |
| 414 SkDebugf("%s id=%d", __FUNCTION__, fID); | |
| 415 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | |
| 416 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | |
| 417 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | |
| 418 } | |
| 419 const SkOpSpan* span = &fTs[i]; | |
| 420 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", span->fT, xAtT(span), yAtT(span)); | |
| 421 int iEnd = i + 1; | |
| 422 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT))
{ | |
| 423 ++iEnd; | |
| 424 } | |
| 425 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT); | |
| 426 const SkOpSegment* other = fTs[i].fOther; | |
| 427 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=", | |
| 428 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex); | |
| 429 if (fTs[i].fWindSum == SK_MinS32) { | |
| 430 SkDebugf("?"); | |
| 431 } else { | |
| 432 SkDebugf("%d", fTs[i].fWindSum); | |
| 433 } | |
| 434 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppVa
lue); | |
| 435 } | |
| 436 } | |
| 437 #endif | |
| 438 | |
| 439 #if DEBUG_MARK_DONE || DEBUG_UNSORTABLE | |
| 440 void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int
winding) { | |
| 441 const SkPoint& pt = xyAtT(&span); | |
| 442 SkDebugf("%s id=%d", fun, fID); | |
| 443 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | |
| 444 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | |
| 445 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | |
| 446 } | |
| 447 SK_ALWAYSBREAK(&span == &span.fOther->fTs[span.fOtherIndex].fOther-> | |
| 448 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]); | |
| 449 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d windSum=", | |
| 450 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.f
Y, | |
| 451 (&span)[1].fT, winding); | |
| 452 if (span.fWindSum == SK_MinS32) { | |
| 453 SkDebugf("?"); | |
| 454 } else { | |
| 455 SkDebugf("%d", span.fWindSum); | |
| 456 } | |
| 457 SkDebugf(" windValue=%d\n", span.fWindValue); | |
| 458 } | |
| 459 | |
| 460 void SkOpSegment::debugShowNewWinding(const char* fun, const SkOpSpan& span, int
winding, | |
| 461 int oppWinding) { | |
| 462 const SkPoint& pt = xyAtT(&span); | |
| 463 SkDebugf("%s id=%d", fun, fID); | |
| 464 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); | |
| 465 for (int vIndex = 1; vIndex <= SkPathOpsVerbToPoints(fVerb); ++vIndex) { | |
| 466 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); | |
| 467 } | |
| 468 SK_ALWAYSBREAK(&span == &span.fOther->fTs[span.fOtherIndex].fOther-> | |
| 469 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]); | |
| 470 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) tEnd=%1.9g newWindSum=%d newOppSum=%d
oppSum=", | |
| 471 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.f
Y, | |
| 472 (&span)[1].fT, winding, oppWinding); | |
| 473 if (span.fOppSum == SK_MinS32) { | |
| 474 SkDebugf("?"); | |
| 475 } else { | |
| 476 SkDebugf("%d", span.fOppSum); | |
| 477 } | |
| 478 SkDebugf(" windSum="); | |
| 479 if (span.fWindSum == SK_MinS32) { | |
| 480 SkDebugf("?"); | |
| 481 } else { | |
| 482 SkDebugf("%d", span.fWindSum); | |
| 483 } | |
| 484 SkDebugf(" windValue=%d oppValue=%d\n", span.fWindValue, span.fOppValue); | |
| 485 } | |
| 486 #endif | |
| 487 | |
| 488 #if DEBUG_SHOW_WINDING | |
| 489 int SkOpSegment::debugShowWindingValues(int slotCount, int ofInterest) const { | |
| 490 if (!(1 << fID & ofInterest)) { | |
| 491 return 0; | |
| 492 } | |
| 493 int sum = 0; | |
| 494 SkTArray<char, true> slots(slotCount * 2); | |
| 495 memset(slots.begin(), ' ', slotCount * 2); | |
| 496 for (int i = 0; i < fTs.count(); ++i) { | |
| 497 // if (!(1 << fTs[i].fOther->fID & ofInterest)) { | |
| 498 // continue; | |
| 499 // } | |
| 500 sum += fTs[i].fWindValue; | |
| 501 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue); | |
| 502 sum += fTs[i].fOppValue; | |
| 503 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue); | |
| 504 } | |
| 505 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begi
n(), slotCount, | |
| 506 slots.begin() + slotCount); | |
| 507 return sum; | |
| 508 } | |
| 509 #endif | |
| 510 | |
| 511 void SkOpSegment::debugValidate() const { | |
| 512 #if DEBUG_VALIDATE | |
| 513 int count = fTs.count(); | |
| 514 SK_ALWAYSBREAK(count >= 2); | |
| 515 SK_ALWAYSBREAK(fTs[0].fT == 0); | |
| 516 SK_ALWAYSBREAK(fTs[count - 1].fT == 1); | |
| 517 int done = 0; | |
| 518 double t = -1; | |
| 519 const SkOpSpan* last = NULL; | |
| 520 bool tinyTFound = false; | |
| 521 bool hasLoop = false; | |
| 522 for (int i = 0; i < count; ++i) { | |
| 523 const SkOpSpan& span = fTs[i]; | |
| 524 SK_ALWAYSBREAK(t <= span.fT); | |
| 525 t = span.fT; | |
| 526 int otherIndex = span.fOtherIndex; | |
| 527 const SkOpSegment* other = span.fOther; | |
| 528 SK_ALWAYSBREAK(other != this || fVerb == SkPath::kCubic_Verb); | |
| 529 const SkOpSpan& otherSpan = other->fTs[otherIndex]; | |
| 530 SK_ALWAYSBREAK(otherSpan.fPt == span.fPt); | |
| 531 SK_ALWAYSBREAK(otherSpan.fOtherT == t); | |
| 532 SK_ALWAYSBREAK(&fTs[i] == &otherSpan.fOther->fTs[otherSpan.fOtherIndex])
; | |
| 533 done += span.fDone; | |
| 534 if (last) { | |
| 535 SK_ALWAYSBREAK(last->fT != span.fT || last->fOther != span.fOther); | |
| 536 bool tsEqual = last->fT == span.fT; | |
| 537 bool tsPreciselyEqual = precisely_equal(last->fT, span.fT); | |
| 538 SK_ALWAYSBREAK(!tsEqual || tsPreciselyEqual); | |
| 539 bool pointsEqual = last->fPt == span.fPt; | |
| 540 bool pointsNearlyEqual = AlmostEqualUlps(last->fPt, span.fPt); | |
| 541 #if 0 // bufferOverflow test triggers this | |
| 542 SK_ALWAYSBREAK(!tsPreciselyEqual || pointsNearlyEqual); | |
| 543 #endif | |
| 544 // SK_ALWAYSBREAK(!last->fTiny || !tsPreciselyEqual || span.fTiny ||
tinyTFound); | |
| 545 SK_ALWAYSBREAK(last->fTiny || tsPreciselyEqual || !pointsEqual || ha
sLoop); | |
| 546 SK_ALWAYSBREAK(!last->fTiny || pointsEqual); | |
| 547 SK_ALWAYSBREAK(!last->fTiny || last->fDone); | |
| 548 SK_ALWAYSBREAK(!last->fSmall || pointsNearlyEqual); | |
| 549 SK_ALWAYSBREAK(!last->fSmall || last->fDone); | |
| 550 // SK_ALWAYSBREAK(!last->fSmall || last->fTiny); | |
| 551 // SK_ALWAYSBREAK(last->fTiny || !pointsEqual || last->fDone == span.
fDone); | |
| 552 if (last->fTiny) { | |
| 553 tinyTFound |= !tsPreciselyEqual; | |
| 554 } else { | |
| 555 tinyTFound = false; | |
| 556 } | |
| 557 } | |
| 558 last = &span; | |
| 559 hasLoop |= last->fLoop; | |
| 560 } | |
| 561 SK_ALWAYSBREAK(done == fDoneSpans); | |
| 562 // if (fAngles.count() ) { | |
| 563 // fAngles.begin()->debugValidateLoop(); | |
| 564 // } | |
| 565 #endif | |
| 566 } | |
| OLD | NEW |