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