1 /* 2 * Copyright 2014 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 "SkChunkAlloc.h" 9 #include "SkPathOpsBounds.h" 10 #include "SkPathOpsRect.h" 11 #include "SkIntersections.h" 12 #include "SkTSort.h" 13 14 #ifdef SK_DEBUG 15 typedef uint8_t SkOpDebugBool; 16 #else 17 typedef bool SkOpDebugBool; 18 #endif 19 20 /* TCurve and OppCurve are one of { SkDQuadratic, SkDConic, SkDCubic } */ 21 template<typename TCurve, typename OppCurve> 22 class SkTCoincident { 23 public: 24 SkTCoincident() { 25 this->init(); 26 } 27 28 void debugInit() { 29 #ifdef SK_DEBUG 30 this->fPerpPt.fX = this->fPerpPt.fY = SK_ScalarNaN; 31 this->fPerpT = SK_ScalarNaN; 32 this->fCoincident = 0xFF; 33 #endif 34 } 35 36 char dumpIsCoincidentStr() const; 37 void dump() const; 38 39 bool isCoincident() const { 40 SkASSERT(!!fCoincident == fCoincident); 41 return SkToBool(fCoincident); 42 } 43 44 void init() { 45 fPerpT = -1; 46 fCoincident = false; 47 fPerpPt.fX = fPerpPt.fY = SK_ScalarNaN; 48 } 49 50 void markCoincident() { 51 if (!fCoincident) { 52 fPerpT = -1; 53 } 54 fCoincident = true; 55 } 56 57 const SkDPoint& perpPt() const { 58 return fPerpPt; 59 } 60 61 double perpT() const { 62 return fPerpT; 63 } 64 65 void setPerp(const TCurve& c1, double t, const SkDPoint& cPt, const OppCurve& ); 66 67 private: 68 SkDPoint fPerpPt; 69 double fPerpT; // perpendicular intersection on opposite curve 70 SkOpDebugBool fCoincident; 71 }; 72 73 template<typename TCurve, typename OppCurve> class SkTSect; 74 template<typename TCurve, typename OppCurve> class SkTSpan; 75 76 template<typename TCurve, typename OppCurve> 77 struct SkTSpanBounded { 78 SkTSpan<TCurve, OppCurve>* fBounded; 79 SkTSpanBounded* fNext; 80 }; 81 82 /* Curve is either TCurve or SkDCubic */ 83 template<typename TCurve, typename OppCurve> 84 class SkTSpan { 85 public: 86 void addBounded(SkTSpan<OppCurve, TCurve>* , SkChunkAlloc* ); 87 double closestBoundedT(const SkDPoint& pt) const; 88 bool contains(double t) const; 89 90 void debugInit() { 91 TCurve dummy; 92 dummy.debugInit(); 93 init(dummy); 94 initBounds(dummy); 95 fCoinStart.init(); 96 fCoinEnd.init(); 97 } 98 99 const SkTSect<OppCurve, TCurve>* debugOpp() const; 100 const SkTSpan* debugSpan(int ) const; 101 const SkTSpan* debugT(double t) const; 102 #ifdef SK_DEBUG 103 bool debugIsBefore(const SkTSpan* span) const; 104 #endif 105 void dump() const; 106 void dumpAll() const; 107 void dumpBounded(int id) const; 108 void dumpBounds() const; 109 void dumpCoin() const; 110 111 double endT() const { 112 return fEndT; 113 } 114 115 SkTSpan<OppCurve, TCurve>* findOppSpan(const SkTSpan<OppCurve, TCurve>* opp) const; 116 117 SkTSpan<OppCurve, TCurve>* findOppT(double t) const { 118 SkTSpan<OppCurve, TCurve>* result = oppT(t); 119 SkASSERT(result); 120 return result; 121 } 122 123 bool hasOppT(double t) const { 124 return SkToBool(oppT(t)); 125 } 126 127 int hullsIntersect(SkTSpan<OppCurve, TCurve>* span, bool* start, bool* oppStart); 128 void init(const TCurve& ); 129 void initBounds(const TCurve& ); 130 131 bool isBounded() const { 132 return fBounded != nullptr; 133 } 134 135 bool linearsIntersect(SkTSpan<OppCurve, TCurve>* span); 136 double linearT(const SkDPoint& ) const; 137 138 void markCoincident() { 139 fCoinStart.markCoincident(); 140 fCoinEnd.markCoincident(); 141 } 142 143 const SkTSpan* next() const { 144 return fNext; 145 } 146 147 bool onlyEndPointsInCommon(const SkTSpan<OppCurve, TCurve>* opp, bool* start, 148 bool* oppStart, bool* ptsInCommon); 149 150 const TCurve& part() const { 151 return fPart; 152 } 153 154 bool removeAllBounded(); 155 bool removeBounded(const SkTSpan<OppCurve, TCurve>* opp); 156 157 void reset() { 158 fBounded = nullptr; 159 } 160 161 void resetBounds(const TCurve& curve) { 162 fIsLinear = fIsLine = false; 163 initBounds(curve); 164 } 165 166 bool split(SkTSpan* work, SkChunkAlloc* heap) { 167 return splitAt(work, (work->fStartT + work->fEndT) * 0.5, heap); 168 } 169 170 bool splitAt(SkTSpan* work, double t, SkChunkAlloc* heap); 171 172 double startT() const { 173 return fStartT; 174 } 175 176 private: 177 178 // implementation is for testing only 179 int debugID() const { 180 return PATH_OPS_DEBUG_T_SECT_RELEASE(fID, -1); 181 } 182 183 void dumpID() const; 184 185 int hullCheck(const SkTSpan<OppCurve, TCurve>* opp, bool* start, bool* oppStart); 186 int linearIntersects(const OppCurve& ) const; 187 SkTSpan<OppCurve, TCurve>* oppT(double t) const; 188 189 void validate() const; 190 void validateBounded() const; 191 void validatePerpT(double oppT) const; 192 void validatePerpPt(double t, const SkDPoint& ) const; 193 194 TCurve fPart; 195 SkTCoincident<TCurve, OppCurve> fCoinStart; 196 SkTCoincident<TCurve, OppCurve> fCoinEnd; 197 SkTSpanBounded<OppCurve, TCurve>* fBounded; 198 SkTSpan* fPrev; 199 SkTSpan* fNext; 200 SkDRect fBounds; 201 double fStartT; 202 double fEndT; 203 double fBoundsMax; 204 SkOpDebugBool fCollapsed; 205 SkOpDebugBool fHasPerp; 206 SkOpDebugBool fIsLinear; 207 SkOpDebugBool fIsLine; 208 SkOpDebugBool fDeleted; 209 SkDEBUGCODE_(SkTSect<TCurve, OppCurve>* fDebugSect); 210 PATH_OPS_DEBUG_T_SECT_CODE(int fID); 211 friend class SkTSect<TCurve, OppCurve>; 212 friend class SkTSect<OppCurve, TCurve>; 213 friend class SkTSpan<OppCurve, TCurve>; 214 }; 215 216 template<typename TCurve, typename OppCurve> 217 class SkTSect { 218 public: 219 SkTSect(const TCurve& c PATH_OPS_DEBUG_T_SECT_PARAMS(int id)); 220 static void BinarySearch(SkTSect* sect1, SkTSect<OppCurve, TCurve>* sect2, 221 SkIntersections* intersections); 222 223 // for testing only 224 bool debugHasBounded(const SkTSpan<OppCurve, TCurve>* ) const; 225 226 const SkTSect<OppCurve, TCurve>* debugOpp() const { 227 return SkDEBUGRELEASE(fOppSect, nullptr); 228 } 229 230 const SkTSpan<TCurve, OppCurve>* debugSpan(int id) const; 231 const SkTSpan<TCurve, OppCurve>* debugT(double t) const; 232 void dump() const; 233 void dumpBoth(SkTSect<OppCurve, TCurve>* ) const; 234 void dumpBounded(int id) const; 235 void dumpBounds() const; 236 void dumpCoin() const; 237 void dumpCoinCurves() const; 238 void dumpCurves() const; 239 240 private: 241 enum { 242 kZeroS1Set = 1, 243 kOneS1Set = 2, 244 kZeroS2Set = 4, 245 kOneS2Set = 8 246 }; 247 248 SkTSpan<TCurve, OppCurve>* addFollowing(SkTSpan<TCurve, OppCurve>* prior); 249 void addForPerp(SkTSpan<OppCurve, TCurve>* span, double t); 250 SkTSpan<TCurve, OppCurve>* addOne(); 251 252 SkTSpan<TCurve, OppCurve>* addSplitAt(SkTSpan<TCurve, OppCurve>* span, double t) { 253 SkTSpan<TCurve, OppCurve>* result = this->addOne(); 254 result->splitAt(span, t, &fHeap); 255 result->initBounds(fCurve); 256 span->initBounds(fCurve); 257 return result; 258 } 259 260 bool binarySearchCoin(SkTSect<OppCurve, TCurve>* , double tStart, double tStep, double* t, 261 double* oppT); 262 SkTSpan<TCurve, OppCurve>* boundsMax() const; 263 void coincidentCheck(SkTSect<OppCurve, TCurve>* sect2); 264 void coincidentForce(SkTSect<OppCurve, TCurve>* sect2, double start1s, double start1e); 265 bool coincidentHasT(double t); 266 int collapsed() const; 267 void computePerpendiculars(SkTSect<OppCurve, TCurve>* sect2, SkTSpan<TCurve, OppCurve>* first, 268 SkTSpan<TCurve, OppCurve>* last); 269 int countConsecutiveSpans(SkTSpan<TCurve, OppCurve>* first, 270 SkTSpan<TCurve, OppCurve>** last) const; 271 272 int debugID() const { 273 return PATH_OPS_DEBUG_T_SECT_RELEASE(fID, -1); 274 } 275 276 void deleteEmptySpans(); 277 void dumpCommon(const SkTSpan<TCurve, OppCurve>* ) const; 278 void dumpCommonCurves(const SkTSpan<TCurve, OppCurve>* ) const; 279 static int EndsEqual(const SkTSect* sect1, const SkTSect<OppCurve, TCurve>* sect2, 280 SkIntersections* ); 281 SkTSpan<TCurve, OppCurve>* extractCoincident(SkTSect<OppCurve, TCurve>* sect2, 282 SkTSpan<TCurve, OppCurve>* first, 283 SkTSpan<TCurve, OppCurve>* last); 284 SkTSpan<TCurve, OppCurve>* findCoincidentRun(SkTSpan<TCurve, OppCurve>* first, 285 SkTSpan<TCurve, OppCurve>** lastPtr); 286 int intersects(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp, 287 SkTSpan<OppCurve, TCurve>* oppSpan, int* oppResult); 288 bool isParallel(const SkDLine& thisLine, const SkTSect<OppCurve, TCurve>* opp) const; 289 int linesIntersect(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp, 290 SkTSpan<OppCurve, TCurve>* oppSpan, SkIntersections* ); 291 void markSpanGone(SkTSpan<TCurve, OppCurve>* span); 292 bool matchedDirection(double t, const SkTSect<OppCurve, TCurve>* sect2, double t2) const; 293 void matchedDirCheck(double t, const SkTSect<OppCurve, TCurve>* sect2, double t2, 294 bool* calcMatched, bool* oppMatched) const; 295 void mergeCoincidence(SkTSect<OppCurve, TCurve>* sect2); 296 SkTSpan<TCurve, OppCurve>* prev(SkTSpan<TCurve, OppCurve>* ) const; 297 void removeByPerpendicular(SkTSect<OppCurve, TCurve>* opp); 298 void recoverCollapsed(); 299 void removeCoincident(SkTSpan<TCurve, OppCurve>* span, bool isBetween); 300 void removeAllBut(const SkTSpan<OppCurve, TCurve>* keep, SkTSpan<TCurve, OppCurve>* span, 301 SkTSect<OppCurve, TCurve>* opp); 302 void removeSpan(SkTSpan<TCurve, OppCurve>* span); 303 void removeSpanRange(SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last); 304 void removeSpans(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp); 305 SkTSpan<TCurve, OppCurve>* spanAtT(double t, SkTSpan<TCurve, OppCurve>** priorSpan); 306 SkTSpan<TCurve, OppCurve>* tail(); 307 void trim(SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp); 308 void unlinkSpan(SkTSpan<TCurve, OppCurve>* span); 309 bool updateBounded(SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last, 310 SkTSpan<OppCurve, TCurve>* oppFirst); 311 void validate() const; 312 void validateBounded() const; 313 314 const TCurve& fCurve; 315 SkChunkAlloc fHeap; 316 SkTSpan<TCurve, OppCurve>* fHead; 317 SkTSpan<TCurve, OppCurve>* fCoincident; 318 SkTSpan<TCurve, OppCurve>* fDeleted; 319 int fActiveCount; 320 SkDEBUGCODE_(SkTSect<OppCurve, TCurve>* fOppSect); 321 PATH_OPS_DEBUG_T_SECT_CODE(int fID); 322 PATH_OPS_DEBUG_T_SECT_CODE(int fDebugCount); 323 #if DEBUG_T_SECT 324 int fDebugAllocatedCount; 325 #endif 326 friend class SkTSpan<TCurve, OppCurve>; 327 friend class SkTSpan<OppCurve, TCurve>; 328 friend class SkTSect<OppCurve, TCurve>; 329 }; 330 331 #define COINCIDENT_SPAN_COUNT 9 332 333 template<typename TCurve, typename OppCurve> 334 void SkTCoincident<TCurve, OppCurve>::setPerp(const TCurve& c1, double t, 335 const SkDPoint& cPt, const OppCurve& c2) { 336 SkDVector dxdy = c1.dxdyAtT(t); 337 SkDLine perp = {{ cPt, {cPt.fX + dxdy.fY, cPt.fY - dxdy.fX} }}; 338 SkIntersections i; 339 int used = i.intersectRay(c2, perp); 340 // only keep closest 341 if (used == 0 || used == 3) { 342 this->init(); 343 return; 344 } 345 fPerpT = i[0][0]; 346 fPerpPt = i.pt(0); 347 SkASSERT(used <= 2); 348 if (used == 2) { 349 double distSq = (fPerpPt - cPt).lengthSquared(); 350 double dist2Sq = (i.pt(1) - cPt).lengthSquared(); 351 if (dist2Sq < distSq) { 352 fPerpT = i[0][1]; 353 fPerpPt = i.pt(1); 354 } 355 } 356 #if DEBUG_T_SECT 357 SkDebugf("setPerp t=%1.9g cPt=(%1.9g,%1.9g) %s oppT=%1.9g fPerpPt=(%1.9g,%1.9g)\n", 358 t, cPt.fX, cPt.fY, 359 cPt.approximatelyEqual(fPerpPt) ? "==" : "!=", fPerpT, fPerpPt.fX, fPerpPt.fY); 360 #endif 361 fCoincident = cPt.approximatelyEqual(fPerpPt); 362 #if DEBUG_T_SECT 363 if (fCoincident) { 364 SkDebugf(""); // allow setting breakpoint 365 } 366 #endif 367 } 368 369 template<typename TCurve, typename OppCurve> 370 void SkTSpan<TCurve, OppCurve>::addBounded(SkTSpan<OppCurve, TCurve>* span, SkChunkAlloc* heap) { 371 SkTSpanBounded<OppCurve, TCurve>* bounded = new (heap->allocThrow( 372 sizeof(SkTSpanBounded<OppCurve, TCurve>)))(SkTSpanBounded<OppCurve, TCurve>); 373 bounded->fBounded = span; 374 bounded->fNext = fBounded; 375 fBounded = bounded; 376 } 377 378 template<typename TCurve, typename OppCurve> 379 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::addFollowing( 380 SkTSpan<TCurve, OppCurve>* prior) { 381 SkTSpan<TCurve, OppCurve>* result = this->addOne(); 382 result->fStartT = prior ? prior->fEndT : 0; 383 SkTSpan<TCurve, OppCurve>* next = prior ? prior->fNext : fHead; 384 result->fEndT = next ? next->fStartT : 1; 385 result->fPrev = prior; 386 result->fNext = next; 387 if (prior) { 388 prior->fNext = result; 389 } else { 390 fHead = result; 391 } 392 if (next) { 393 next->fPrev = result; 394 } 395 result->resetBounds(fCurve); 396 return result; 397 } 398 399 template<typename TCurve, typename OppCurve> 400 void SkTSect<TCurve, OppCurve>::addForPerp(SkTSpan<OppCurve, TCurve>* span, double t) { 401 if (!span->hasOppT(t)) { 402 SkTSpan<TCurve, OppCurve>* priorSpan; 403 SkTSpan<TCurve, OppCurve>* opp = this->spanAtT(t, &priorSpan); 404 if (!opp) { 405 opp = this->addFollowing(priorSpan); 406 #if DEBUG_PERP 407 SkDebugf("%s priorSpan=%d t=%1.9g opp=%d\n", __FUNCTION__, priorSpan ? 408 priorSpan->debugID() : -1, t, opp->debugID()); 409 #endif 410 } 411 #if DEBUG_PERP 412 opp->dump(); SkDebugf("\n"); 413 SkDebugf("%s addBounded span=%d opp=%d\n", __FUNCTION__, priorSpan ? 414 priorSpan->debugID() : -1, opp->debugID()); 415 #endif 416 opp->addBounded(span, &fHeap); 417 span->addBounded(opp, &fHeap); 418 } 419 this->validate(); 420 #if DEBUG_T_SECT 421 span->validatePerpT(t); 422 #endif 423 } 424 425 template<typename TCurve, typename OppCurve> 426 double SkTSpan<TCurve, OppCurve>::closestBoundedT(const SkDPoint& pt) const { 427 double result = -1; 428 double closest = FLT_MAX; 429 const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded; 430 while (testBounded) { 431 const SkTSpan<OppCurve, TCurve>* test = testBounded->fBounded; 432 double startDist = test->fPart[0].distanceSquared(pt); 433 if (closest > startDist) { 434 closest = startDist; 435 result = test->fStartT; 436 } 437 double endDist = test->fPart[OppCurve::kPointLast].distanceSquared(pt); 438 if (closest > endDist) { 439 closest = endDist; 440 result = test->fEndT; 441 } 442 testBounded = testBounded->fNext; 443 } 444 SkASSERT(between(0, result, 1)); 445 return result; 446 } 447 448 #ifdef SK_DEBUG 449 template<typename TCurve, typename OppCurve> 450 bool SkTSpan<TCurve, OppCurve>::debugIsBefore(const SkTSpan* span) const { 451 const SkTSpan* work = this; 452 do { 453 if (span == work) { 454 return true; 455 } 456 } while ((work = work->fNext)); 457 return false; 458 } 459 #endif 460 461 template<typename TCurve, typename OppCurve> 462 bool SkTSpan<TCurve, OppCurve>::contains(double t) const { 463 const SkTSpan* work = this; 464 do { 465 if (between(work->fStartT, t, work->fEndT)) { 466 return true; 467 } 468 } while ((work = work->fNext)); 469 return false; 470 } 471 472 template<typename TCurve, typename OppCurve> 473 const SkTSect<OppCurve, TCurve>* SkTSpan<TCurve, OppCurve>::debugOpp() const { 474 return SkDEBUGRELEASE(fDebugSect->debugOpp(), nullptr); 475 } 476 477 template<typename TCurve, typename OppCurve> 478 SkTSpan<OppCurve, TCurve>* SkTSpan<TCurve, OppCurve>::findOppSpan( 479 const SkTSpan<OppCurve, TCurve>* opp) const { 480 SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded; 481 while (bounded) { 482 SkTSpan<OppCurve, TCurve>* test = bounded->fBounded; 483 if (opp == test) { 484 return test; 485 } 486 bounded = bounded->fNext; 487 } 488 return nullptr; 489 } 490 491 // returns 0 if no hull intersection 492 // 1 if hulls intersect 493 // 2 if hulls only share a common endpoint 494 // -1 if linear and further checking is required 495 template<typename TCurve, typename OppCurve> 496 int SkTSpan<TCurve, OppCurve>::hullCheck(const SkTSpan<OppCurve, TCurve>* opp, 497 bool* start, bool* oppStart) { 498 if (fIsLinear) { 499 return -1; 500 } 501 bool ptsInCommon; 502 if (onlyEndPointsInCommon(opp, start, oppStart, &ptsInCommon)) { 503 SkASSERT(ptsInCommon); 504 return 2; 505 } 506 bool linear; 507 if (fPart.hullIntersects(opp->fPart, &linear)) { 508 if (!linear) { // check set true if linear 509 return 1; 510 } 511 fIsLinear = true; 512 fIsLine = fPart.controlsInside(); 513 return ptsInCommon ? 2 : -1; 514 } else { // hull is not linear; check set true if intersected at the end points 515 return ((int) ptsInCommon) << 1; // 0 or 2 516 } 517 return 0; 518 } 519 520 // OPTIMIZE ? If at_most_end_pts_in_common detects that one quad is near linear, 521 // use line intersection to guess a better split than 0.5 522 // OPTIMIZE Once at_most_end_pts_in_common detects linear, mark span so all future splits are linear 523 template<typename TCurve, typename OppCurve> 524 int SkTSpan<TCurve, OppCurve>::hullsIntersect(SkTSpan<OppCurve, TCurve>* opp, 525 bool* start, bool* oppStart) { 526 if (!fBounds.intersects(opp->fBounds)) { 527 return 0; 528 } 529 int hullSect = this->hullCheck(opp, start, oppStart); 530 if (hullSect >= 0) { 531 return hullSect; 532 } 533 hullSect = opp->hullCheck(this, oppStart, start); 534 if (hullSect >= 0) { 535 return hullSect; 536 } 537 return -1; 538 } 539 540 template<typename TCurve, typename OppCurve> 541 void SkTSpan<TCurve, OppCurve>::init(const TCurve& c) { 542 fPrev = fNext = nullptr; 543 fStartT = 0; 544 fEndT = 1; 545 fBounded = nullptr; 546 resetBounds(c); 547 } 548 549 template<typename TCurve, typename OppCurve> 550 void SkTSpan<TCurve, OppCurve>::initBounds(const TCurve& c) { 551 fPart = c.subDivide(fStartT, fEndT); 552 fBounds.setBounds(fPart); 553 fCoinStart.init(); 554 fCoinEnd.init(); 555 fBoundsMax = SkTMax(fBounds.width(), fBounds.height()); 556 fCollapsed = fPart.collapsed(); 557 fHasPerp = false; 558 fDeleted = false; 559 #if DEBUG_T_SECT 560 if (fCollapsed) { 561 SkDebugf(""); // for convenient breakpoints 562 } 563 #endif 564 } 565 566 template<typename TCurve, typename OppCurve> 567 bool SkTSpan<TCurve, OppCurve>::linearsIntersect(SkTSpan<OppCurve, TCurve>* span) { 568 int result = this->linearIntersects(span->fPart); 569 if (result <= 1) { 570 return SkToBool(result); 571 } 572 SkASSERT(span->fIsLinear); 573 result = span->linearIntersects(this->fPart); 574 // SkASSERT(result <= 1); 575 return SkToBool(result); 576 } 577 578 template<typename TCurve, typename OppCurve> 579 double SkTSpan<TCurve, OppCurve>::linearT(const SkDPoint& pt) const { 580 SkDVector len = fPart[TCurve::kPointLast] - fPart[0]; 581 return fabs(len.fX) > fabs(len.fY) 582 ? (pt.fX - fPart[0].fX) / len.fX 583 : (pt.fY - fPart[0].fY) / len.fY; 584 } 585 586 template<typename TCurve, typename OppCurve> 587 int SkTSpan<TCurve, OppCurve>::linearIntersects(const OppCurve& q2) const { 588 // looks like q1 is near-linear 589 int start = 0, end = TCurve::kPointLast; // the outside points are usually the extremes 590 if (!fPart.controlsInside()) { 591 double dist = 0; // if there's any question, compute distance to find best outsiders 592 for (int outer = 0; outer < TCurve::kPointCount - 1; ++outer) { 593 for (int inner = outer + 1; inner < TCurve::kPointCount; ++inner) { 594 double test = (fPart[outer] - fPart[inner]).lengthSquared(); 595 if (dist > test) { 596 continue; 597 } 598 dist = test; 599 start = outer; 600 end = inner; 601 } 602 } 603 } 604 // see if q2 is on one side of the line formed by the extreme points 605 double origX = fPart[start].fX; 606 double origY = fPart[start].fY; 607 double adj = fPart[end].fX - origX; 608 double opp = fPart[end].fY - origY; 609 double maxPart = SkTMax(fabs(adj), fabs(opp)); 610 double sign = 0; // initialization to shut up warning in release build 611 for (int n = 0; n < OppCurve::kPointCount; ++n) { 612 double dx = q2[n].fY - origY; 613 double dy = q2[n].fX - origX; 614 double maxVal = SkTMax(maxPart, SkTMax(fabs(dx), fabs(dy))); 615 double test = (q2[n].fY - origY) * adj - (q2[n].fX - origX) * opp; 616 if (precisely_zero_when_compared_to(test, maxVal)) { 617 return 1; 618 } 619 if (approximately_zero_when_compared_to(test, maxVal)) { 620 return 3; 621 } 622 if (n == 0) { 623 sign = test; 624 continue; 625 } 626 if (test * sign < 0) { 627 return 1; 628 } 629 } 630 return 0; 631 } 632 633 template<typename TCurve, typename OppCurve> 634 bool SkTSpan<TCurve, OppCurve>::onlyEndPointsInCommon(const SkTSpan<OppCurve, TCurve>* opp, 635 bool* start, bool* oppStart, bool* ptsInCommon) { 636 if (opp->fPart[0] == fPart[0]) { 637 *start = *oppStart = true; 638 } else if (opp->fPart[0] == fPart[TCurve::kPointLast]) { 639 *start = false; 640 *oppStart = true; 641 } else if (opp->fPart[OppCurve::kPointLast] == fPart[0]) { 642 *start = true; 643 *oppStart = false; 644 } else if (opp->fPart[OppCurve::kPointLast] == fPart[TCurve::kPointLast]) { 645 *start = *oppStart = false; 646 } else { 647 *ptsInCommon = false; 648 return false; 649 } 650 *ptsInCommon = true; 651 const SkDPoint* otherPts[TCurve::kPointCount - 1], * oppOtherPts[OppCurve::kPointCount - 1]; 652 int baseIndex = *start ? 0 : TCurve::kPointLast; 653 fPart.otherPts(baseIndex, otherPts); 654 opp->fPart.otherPts(*oppStart ? 0 : OppCurve::kPointLast, oppOtherPts); 655 const SkDPoint& base = fPart[baseIndex]; 656 for (int o1 = 0; o1 < (int) SK_ARRAY_COUNT(otherPts); ++o1) { 657 SkDVector v1 = *otherPts[o1] - base; 658 for (int o2 = 0; o2 < (int) SK_ARRAY_COUNT(oppOtherPts); ++o2) { 659 SkDVector v2 = *oppOtherPts[o2] - base; 660 if (v2.dot(v1) >= 0) { 661 return false; 662 } 663 } 664 } 665 return true; 666 } 667 668 template<typename TCurve, typename OppCurve> 669 SkTSpan<OppCurve, TCurve>* SkTSpan<TCurve, OppCurve>::oppT(double t) const { 670 SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded; 671 while (bounded) { 672 SkTSpan<OppCurve, TCurve>* test = bounded->fBounded; 673 if (between(test->fStartT, t, test->fEndT)) { 674 return test; 675 } 676 bounded = bounded->fNext; 677 } 678 return nullptr; 679 } 680 681 template<typename TCurve, typename OppCurve> 682 bool SkTSpan<TCurve, OppCurve>::removeAllBounded() { 683 bool deleteSpan = false; 684 SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded; 685 while (bounded) { 686 SkTSpan<OppCurve, TCurve>* opp = bounded->fBounded; 687 deleteSpan |= opp->removeBounded(this); 688 bounded = bounded->fNext; 689 } 690 return deleteSpan; 691 } 692 693 template<typename TCurve, typename OppCurve> 694 bool SkTSpan<TCurve, OppCurve>::removeBounded(const SkTSpan<OppCurve, TCurve>* opp) { 695 if (fHasPerp) { 696 bool foundStart = false; 697 bool foundEnd = false; 698 SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded; 699 while (bounded) { 700 SkTSpan<OppCurve, TCurve>* test = bounded->fBounded; 701 if (opp != test) { 702 foundStart |= between(test->fStartT, fCoinStart.perpT(), test->fEndT); 703 foundEnd |= between(test->fStartT, fCoinEnd.perpT(), test->fEndT); 704 } 705 bounded = bounded->fNext; 706 } 707 if (!foundStart || !foundEnd) { 708 fHasPerp = false; 709 fCoinStart.init(); 710 fCoinEnd.init(); 711 } 712 } 713 SkTSpanBounded<OppCurve, TCurve>* bounded = fBounded; 714 SkTSpanBounded<OppCurve, TCurve>* prev = nullptr; 715 while (bounded) { 716 SkTSpanBounded<OppCurve, TCurve>* boundedNext = bounded->fNext; 717 if (opp == bounded->fBounded) { 718 if (prev) { 719 prev->fNext = boundedNext; 720 return false; 721 } else { 722 fBounded = boundedNext; 723 return fBounded == nullptr; 724 } 725 } 726 prev = bounded; 727 bounded = boundedNext; 728 } 729 SkASSERT(0); 730 return false; 731 } 732 733 template<typename TCurve, typename OppCurve> 734 bool SkTSpan<TCurve, OppCurve>::splitAt(SkTSpan* work, double t, SkChunkAlloc* heap) { 735 fStartT = t; 736 fEndT = work->fEndT; 737 if (fStartT == fEndT) { 738 fCollapsed = true; 739 return false; 740 } 741 work->fEndT = t; 742 if (work->fStartT == work->fEndT) { 743 work->fCollapsed = true; 744 return false; 745 } 746 fPrev = work; 747 fNext = work->fNext; 748 fIsLinear = work->fIsLinear; 749 fIsLine = work->fIsLine; 750 751 work->fNext = this; 752 if (fNext) { 753 fNext->fPrev = this; 754 } 755 SkTSpanBounded<OppCurve, TCurve>* bounded = work->fBounded; 756 fBounded = nullptr; 757 while (bounded) { 758 this->addBounded(bounded->fBounded, heap); 759 bounded = bounded->fNext; 760 } 761 bounded = fBounded; 762 while (bounded) { 763 bounded->fBounded->addBounded(this, heap); 764 bounded = bounded->fNext; 765 } 766 return true; 767 } 768 769 template<typename TCurve, typename OppCurve> 770 void SkTSpan<TCurve, OppCurve>::validate() const { 771 #if DEBUG_T_SECT 772 SkASSERT(fNext == nullptr || fNext != fPrev); 773 SkASSERT(fNext == nullptr || this == fNext->fPrev); 774 SkASSERT(fPrev == nullptr || this == fPrev->fNext); 775 SkASSERT(fBounds.width() || fBounds.height() || fCollapsed); 776 SkASSERT(fBoundsMax == SkTMax(fBounds.width(), fBounds.height())); 777 SkASSERT(0 <= fStartT); 778 SkASSERT(fEndT <= 1); 779 SkASSERT(fStartT <= fEndT); 780 SkASSERT(fBounded); 781 this->validateBounded(); 782 if (fHasPerp) { 783 if (fCoinStart.isCoincident()) { 784 validatePerpT(fCoinStart.perpT()); 785 validatePerpPt(fCoinStart.perpT(), fCoinStart.perpPt()); 786 } 787 if (fCoinEnd.isCoincident()) { 788 validatePerpT(fCoinEnd.perpT()); 789 validatePerpPt(fCoinEnd.perpT(), fCoinEnd.perpPt()); 790 } 791 } 792 #endif 793 } 794 795 template<typename TCurve, typename OppCurve> 796 void SkTSpan<TCurve, OppCurve>::validateBounded() const { 797 #if DEBUG_VALIDATE 798 const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded; 799 while (testBounded) { 800 SkDEBUGCODE_(const SkTSpan<OppCurve, TCurve>* overlap = testBounded->fBounded); 801 SkASSERT(!overlap->fDeleted); 802 SkASSERT(((this->debugID() ^ overlap->debugID()) & 1) == 1); 803 SkASSERT(overlap->findOppSpan(this)); 804 testBounded = testBounded->fNext; 805 } 806 #endif 807 } 808 809 template<typename TCurve, typename OppCurve> 810 void SkTSpan<TCurve, OppCurve>::validatePerpT(double oppT) const { 811 const SkTSpanBounded<OppCurve, TCurve>* testBounded = fBounded; 812 while (testBounded) { 813 const SkTSpan<OppCurve, TCurve>* overlap = testBounded->fBounded; 814 if (precisely_between(overlap->fStartT, oppT, overlap->fEndT)) { 815 return; 816 } 817 testBounded = testBounded->fNext; 818 } 819 SkASSERT(0); 820 } 821 822 template<typename TCurve, typename OppCurve> 823 void SkTSpan<TCurve, OppCurve>::validatePerpPt(double t, const SkDPoint& pt) const { 824 SkASSERT(fDebugSect->fOppSect->fCurve.ptAtT(t) == pt); 825 } 826 827 828 template<typename TCurve, typename OppCurve> 829 SkTSect<TCurve, OppCurve>::SkTSect(const TCurve& c PATH_OPS_DEBUG_T_SECT_PARAMS(int id)) 830 : fCurve(c) 831 , fHeap(sizeof(SkTSpan<TCurve, OppCurve>) * 4) 832 , fCoincident(nullptr) 833 , fDeleted(nullptr) 834 , fActiveCount(0) 835 PATH_OPS_DEBUG_T_SECT_PARAMS(fID(id)) 836 PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugCount(0)) 837 PATH_OPS_DEBUG_T_SECT_PARAMS(fDebugAllocatedCount(0)) 838 { 839 fHead = addOne(); 840 fHead->init(c); 841 } 842 843 template<typename TCurve, typename OppCurve> 844 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::addOne() { 845 SkTSpan<TCurve, OppCurve>* result; 846 if (fDeleted) { 847 result = fDeleted; 848 fDeleted = result->fNext; 849 } else { 850 result = new (fHeap.allocThrow(sizeof(SkTSpan<TCurve, OppCurve>)))( 851 SkTSpan<TCurve, OppCurve>); 852 #if DEBUG_T_SECT 853 ++fDebugAllocatedCount; 854 #endif 855 } 856 result->reset(); 857 result->fHasPerp = false; 858 result->fDeleted = false; 859 ++fActiveCount; 860 PATH_OPS_DEBUG_T_SECT_CODE(result->fID = fDebugCount++ * 2 + fID); 861 SkDEBUGCODE(result->fDebugSect = this); 862 #ifdef SK_DEBUG 863 result->fPart.debugInit(); 864 result->fCoinStart.debugInit(); 865 result->fCoinEnd.debugInit(); 866 result->fPrev = result->fNext = nullptr; 867 result->fBounds.debugInit(); 868 result->fStartT = result->fEndT = result->fBoundsMax = SK_ScalarNaN; 869 result->fCollapsed = result->fIsLinear = result->fIsLine = 0xFF; 870 #endif 871 return result; 872 } 873 874 template<typename TCurve, typename OppCurve> 875 bool SkTSect<TCurve, OppCurve>::binarySearchCoin(SkTSect<OppCurve, TCurve>* sect2, double tStart, 876 double tStep, double* resultT, double* oppT) { 877 SkTSpan<TCurve, OppCurve> work; 878 double result = work.fStartT = work.fEndT = tStart; 879 SkDEBUGCODE(work.fDebugSect = this); 880 SkDPoint last = fCurve.ptAtT(tStart); 881 SkDPoint oppPt; 882 bool flip = false; 883 SkDEBUGCODE(bool down = tStep < 0); 884 const OppCurve& opp = sect2->fCurve; 885 do { 886 tStep *= 0.5; 887 work.fStartT += tStep; 888 if (flip) { 889 tStep = -tStep; 890 flip = false; 891 } 892 work.initBounds(fCurve); 893 if (work.fCollapsed) { 894 return false; 895 } 896 if (last.approximatelyEqual(work.fPart[0])) { 897 break; 898 } 899 last = work.fPart[0]; 900 work.fCoinStart.setPerp(fCurve, work.fStartT, last, opp); 901 if (work.fCoinStart.isCoincident()) { 902 #if DEBUG_T_SECT 903 work.validatePerpPt(work.fCoinStart.perpT(), work.fCoinStart.perpPt()); 904 #endif 905 double oppTTest = work.fCoinStart.perpT(); 906 if (sect2->fHead->contains(oppTTest)) { 907 *oppT = oppTTest; 908 oppPt = work.fCoinStart.perpPt(); 909 SkASSERT(down ? result > work.fStartT : result < work.fStartT); 910 result = work.fStartT; 911 continue; 912 } 913 } 914 tStep = -tStep; 915 flip = true; 916 } while (true); 917 if (last.approximatelyEqual(fCurve[0])) { 918 result = 0; 919 } else if (last.approximatelyEqual(fCurve[TCurve::kPointLast])) { 920 result = 1; 921 } 922 if (oppPt.approximatelyEqual(opp[0])) { 923 *oppT = 0; 924 } else if (oppPt.approximatelyEqual(opp[OppCurve::kPointLast])) { 925 *oppT = 1; 926 } 927 *resultT = result; 928 return true; 929 } 930 931 // OPTIMIZE ? keep a sorted list of sizes in the form of a doubly-linked list in quad span 932 // so that each quad sect has a pointer to the largest, and can update it as spans 933 // are split 934 template<typename TCurve, typename OppCurve> 935 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::boundsMax() const { 936 SkTSpan<TCurve, OppCurve>* test = fHead; 937 SkTSpan<TCurve, OppCurve>* largest = fHead; 938 bool lCollapsed = largest->fCollapsed; 939 while ((test = test->fNext)) { 940 bool tCollapsed = test->fCollapsed; 941 if ((lCollapsed && !tCollapsed) || (lCollapsed == tCollapsed && 942 largest->fBoundsMax < test->fBoundsMax)) { 943 largest = test; 944 lCollapsed = test->fCollapsed; 945 } 946 } 947 return largest; 948 } 949 950 template<typename TCurve, typename OppCurve> 951 void SkTSect<TCurve, OppCurve>::coincidentCheck(SkTSect<OppCurve, TCurve>* sect2) { 952 SkTSpan<TCurve, OppCurve>* first = fHead; 953 SkTSpan<TCurve, OppCurve>* last, * next; 954 do { 955 int consecutive = this->countConsecutiveSpans(first, &last); 956 next = last->fNext; 957 if (consecutive < COINCIDENT_SPAN_COUNT) { 958 continue; 959 } 960 this->validate(); 961 sect2->validate(); 962 this->computePerpendiculars(sect2, first, last); 963 this->validate(); 964 sect2->validate(); 965 // check to see if a range of points are on the curve 966 SkTSpan<TCurve, OppCurve>* coinStart = first; 967 do { 968 coinStart = this->extractCoincident(sect2, coinStart, last); 969 } while (coinStart && !last->fDeleted); 970 } while ((first = next)); 971 } 972 973 template<typename TCurve, typename OppCurve> 974 void SkTSect<TCurve, OppCurve>::coincidentForce(SkTSect<OppCurve, TCurve>* sect2, 975 double start1s, double start1e) { 976 SkTSpan<TCurve, OppCurve>* first = fHead; 977 SkTSpan<TCurve, OppCurve>* last = this->tail(); 978 SkTSpan<OppCurve, TCurve>* oppFirst = sect2->fHead; 979 SkTSpan<OppCurve, TCurve>* oppLast = sect2->tail(); 980 bool deleteEmptySpans = this->updateBounded(first, last, oppFirst); 981 deleteEmptySpans |= sect2->updateBounded(oppFirst, oppLast, first); 982 this->removeSpanRange(first, last); 983 sect2->removeSpanRange(oppFirst, oppLast); 984 first->fStartT = start1s; 985 first->fEndT = start1e; 986 first->resetBounds(fCurve); 987 first->fCoinStart.setPerp(fCurve, start1s, fCurve[0], sect2->fCurve); 988 first->fCoinEnd.setPerp(fCurve, start1e, fCurve[TCurve::kPointLast], sect2->fCurve); 989 bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT(); 990 double oppStartT = first->fCoinStart.perpT() == -1 ? 0 : SkTMax(0., first->fCoinStart.perpT()); 991 double oppEndT = first->fCoinEnd.perpT() == -1 ? 1 : SkTMin(1., first->fCoinEnd.perpT()); 992 if (!oppMatched) { 993 SkTSwap(oppStartT, oppEndT); 994 } 995 oppFirst->fStartT = oppStartT; 996 oppFirst->fEndT = oppEndT; 997 oppFirst->resetBounds(sect2->fCurve); 998 this->removeCoincident(first, false); 999 sect2->removeCoincident(oppFirst, true); 1000 if (deleteEmptySpans) { 1001 this->deleteEmptySpans(); 1002 sect2->deleteEmptySpans(); 1003 } 1004 } 1005 1006 template<typename TCurve, typename OppCurve> 1007 bool SkTSect<TCurve, OppCurve>::coincidentHasT(double t) { 1008 SkTSpan<TCurve, OppCurve>* test = fCoincident; 1009 while (test) { 1010 if (between(test->fStartT, t, test->fEndT)) { 1011 return true; 1012 } 1013 test = test->fNext; 1014 } 1015 return false; 1016 } 1017 1018 template<typename TCurve, typename OppCurve> 1019 int SkTSect<TCurve, OppCurve>::collapsed() const { 1020 int result = 0; 1021 const SkTSpan<TCurve, OppCurve>* test = fHead; 1022 while (test) { 1023 if (test->fCollapsed) { 1024 ++result; 1025 } 1026 test = test->next(); 1027 } 1028 return result; 1029 } 1030 1031 template<typename TCurve, typename OppCurve> 1032 void SkTSect<TCurve, OppCurve>::computePerpendiculars(SkTSect<OppCurve, TCurve>* sect2, 1033 SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last) { 1034 const OppCurve& opp = sect2->fCurve; 1035 SkTSpan<TCurve, OppCurve>* work = first; 1036 SkTSpan<TCurve, OppCurve>* prior = nullptr; 1037 do { 1038 if (!work->fHasPerp && !work->fCollapsed) { 1039 if (prior) { 1040 work->fCoinStart = prior->fCoinEnd; 1041 } else { 1042 work->fCoinStart.setPerp(fCurve, work->fStartT, work->fPart[0], opp); 1043 } 1044 if (work->fCoinStart.isCoincident()) { 1045 double perpT = work->fCoinStart.perpT(); 1046 if (sect2->coincidentHasT(perpT)) { 1047 work->fCoinStart.init(); 1048 } else { 1049 sect2->addForPerp(work, perpT); 1050 } 1051 } 1052 work->fCoinEnd.setPerp(fCurve, work->fEndT, work->fPart[TCurve::kPointLast], opp); 1053 if (work->fCoinEnd.isCoincident()) { 1054 double perpT = work->fCoinEnd.perpT(); 1055 if (sect2->coincidentHasT(perpT)) { 1056 work->fCoinEnd.init(); 1057 } else { 1058 sect2->addForPerp(work, perpT); 1059 } 1060 } 1061 work->fHasPerp = true; 1062 } 1063 if (work == last) { 1064 break; 1065 } 1066 prior = work; 1067 work = work->fNext; 1068 SkASSERT(work); 1069 } while (true); 1070 } 1071 1072 template<typename TCurve, typename OppCurve> 1073 int SkTSect<TCurve, OppCurve>::countConsecutiveSpans(SkTSpan<TCurve, OppCurve>* first, 1074 SkTSpan<TCurve, OppCurve>** lastPtr) const { 1075 int consecutive = 1; 1076 SkTSpan<TCurve, OppCurve>* last = first; 1077 do { 1078 SkTSpan<TCurve, OppCurve>* next = last->fNext; 1079 if (!next) { 1080 break; 1081 } 1082 if (next->fStartT > last->fEndT) { 1083 break; 1084 } 1085 ++consecutive; 1086 last = next; 1087 } while (true); 1088 *lastPtr = last; 1089 return consecutive; 1090 } 1091 1092 template<typename TCurve, typename OppCurve> 1093 bool SkTSect<TCurve, OppCurve>::debugHasBounded(const SkTSpan<OppCurve, TCurve>* span) const { 1094 const SkTSpan<TCurve, OppCurve>* test = fHead; 1095 if (!test) { 1096 return false; 1097 } 1098 do { 1099 if (test->findOppSpan(span)) { 1100 return true; 1101 } 1102 } while ((test = test->next())); 1103 return false; 1104 } 1105 1106 template<typename TCurve, typename OppCurve> 1107 void SkTSect<TCurve, OppCurve>::deleteEmptySpans() { 1108 SkTSpan<TCurve, OppCurve>* test; 1109 SkTSpan<TCurve, OppCurve>* next = fHead; 1110 while ((test = next)) { 1111 next = test->fNext; 1112 if (!test->fBounded) { 1113 this->removeSpan(test); 1114 } 1115 } 1116 } 1117 1118 template<typename TCurve, typename OppCurve> 1119 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::extractCoincident( 1120 SkTSect<OppCurve, TCurve>* sect2, 1121 SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>* last) { 1122 first = findCoincidentRun(first, &last); 1123 if (!first) { 1124 return nullptr; 1125 } 1126 // march outwards to find limit of coincidence from here to previous and next spans 1127 double startT = first->fStartT; 1128 double oppStartT SK_INIT_TO_AVOID_WARNING; 1129 double oppEndT SK_INIT_TO_AVOID_WARNING; 1130 SkTSpan<TCurve, OppCurve>* prev = first->fPrev; 1131 SkASSERT(first->fCoinStart.isCoincident()); 1132 SkTSpan<OppCurve, TCurve>* oppFirst = first->findOppT(first->fCoinStart.perpT()); 1133 SkASSERT(last->fCoinEnd.isCoincident()); 1134 bool oppMatched = first->fCoinStart.perpT() < first->fCoinEnd.perpT(); 1135 double coinStart; 1136 SkDEBUGCODE(double coinEnd); 1137 SkTSpan<OppCurve, TCurve>* cutFirst; 1138 if (prev && prev->fEndT == startT 1139 && this->binarySearchCoin(sect2, startT, prev->fStartT - startT, &coinStart, 1140 &oppStartT) 1141 && prev->fStartT < coinStart && coinStart < startT 1142 && (cutFirst = prev->oppT(oppStartT))) { 1143 oppFirst = cutFirst; 1144 first = this->addSplitAt(prev, coinStart); 1145 first->markCoincident(); 1146 prev->fCoinEnd.markCoincident(); 1147 if (oppFirst->fStartT < oppStartT && oppStartT < oppFirst->fEndT) { 1148 SkTSpan<OppCurve, TCurve>* oppHalf = sect2->addSplitAt(oppFirst, oppStartT); 1149 if (oppMatched) { 1150 oppFirst->fCoinEnd.markCoincident(); 1151 oppHalf->markCoincident(); 1152 oppFirst = oppHalf; 1153 } else { 1154 oppFirst->markCoincident(); 1155 oppHalf->fCoinStart.markCoincident(); 1156 } 1157 } 1158 } else { 1159 SkDEBUGCODE(coinStart = first->fStartT); 1160 SkDEBUGCODE(oppStartT = oppMatched ? oppFirst->fStartT : oppFirst->fEndT); 1161 } 1162 // FIXME: incomplete : if we're not at the end, find end of coin 1163 SkTSpan<OppCurve, TCurve>* oppLast; 1164 SkASSERT(last->fCoinEnd.isCoincident()); 1165 oppLast = last->findOppT(last->fCoinEnd.perpT()); 1166 SkDEBUGCODE(coinEnd = last->fEndT); 1167 SkDEBUGCODE(oppEndT = oppMatched ? oppLast->fEndT : oppLast->fStartT); 1168 if (!oppMatched) { 1169 SkTSwap(oppFirst, oppLast); 1170 SkTSwap(oppStartT, oppEndT); 1171 } 1172 SkASSERT(oppStartT < oppEndT); 1173 SkASSERT(coinStart == first->fStartT); 1174 SkASSERT(coinEnd == last->fEndT); 1175 SkASSERT(oppStartT == oppFirst->fStartT); 1176 SkASSERT(oppEndT == oppLast->fEndT); 1177 // reduce coincident runs to single entries 1178 this->validate(); 1179 sect2->validate(); 1180 bool deleteEmptySpans = this->updateBounded(first, last, oppFirst); 1181 deleteEmptySpans |= sect2->updateBounded(oppFirst, oppLast, first); 1182 this->removeSpanRange(first, last); 1183 sect2->removeSpanRange(oppFirst, oppLast); 1184 first->fEndT = last->fEndT; 1185 first->resetBounds(this->fCurve); 1186 first->fCoinStart.setPerp(fCurve, first->fStartT, first->fPart[0], sect2->fCurve); 1187 first->fCoinEnd.setPerp(fCurve, first->fEndT, first->fPart[TCurve::kPointLast], sect2->fCurve); 1188 oppStartT = first->fCoinStart.perpT(); 1189 oppEndT = first->fCoinEnd.perpT(); 1190 if (between(0, oppStartT, 1) && between(0, oppEndT, 1)) { 1191 if (!oppMatched) { 1192 SkTSwap(oppStartT, oppEndT); 1193 } 1194 oppFirst->fStartT = oppStartT; 1195 oppFirst->fEndT = oppEndT; 1196 oppFirst->resetBounds(sect2->fCurve); 1197 } 1198 this->validateBounded(); 1199 sect2->validateBounded(); 1200 last = first->fNext; 1201 this->removeCoincident(first, false); 1202 sect2->removeCoincident(oppFirst, true); 1203 if (deleteEmptySpans) { 1204 this->deleteEmptySpans(); 1205 sect2->deleteEmptySpans(); 1206 } 1207 this->validate(); 1208 sect2->validate(); 1209 return last && !last->fDeleted ? last : nullptr; 1210 } 1211 1212 template<typename TCurve, typename OppCurve> 1213 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::findCoincidentRun( 1214 SkTSpan<TCurve, OppCurve>* first, SkTSpan<TCurve, OppCurve>** lastPtr) { 1215 SkTSpan<TCurve, OppCurve>* work = first; 1216 SkTSpan<TCurve, OppCurve>* lastCandidate = nullptr; 1217 first = nullptr; 1218 // find the first fully coincident span 1219 do { 1220 if (work->fCoinStart.isCoincident()) { 1221 #if DEBUG_T_SECT 1222 work->validatePerpT(work->fCoinStart.perpT()); 1223 work->validatePerpPt(work->fCoinStart.perpT(), work->fCoinStart.perpPt()); 1224 #endif 1225 SkASSERT(work->hasOppT(work->fCoinStart.perpT())); 1226 if (!work->fCoinEnd.isCoincident()) { 1227 break; 1228 } 1229 lastCandidate = work; 1230 if (!first) { 1231 first = work; 1232 } 1233 } else if (first && work->fCollapsed) { 1234 *lastPtr = lastCandidate; 1235 return first; 1236 } else { 1237 lastCandidate = nullptr; 1238 SkASSERT(!first); 1239 } 1240 if (work == *lastPtr) { 1241 return first; 1242 } 1243 work = work->fNext; 1244 SkASSERT(work); 1245 } while (true); 1246 if (lastCandidate) { 1247 *lastPtr = lastCandidate; 1248 } 1249 return first; 1250 } 1251 1252 template<typename TCurve, typename OppCurve> 1253 int SkTSect<TCurve, OppCurve>::intersects(SkTSpan<TCurve, OppCurve>* span, 1254 SkTSect<OppCurve, TCurve>* opp, 1255 SkTSpan<OppCurve, TCurve>* oppSpan, int* oppResult) { 1256 bool spanStart, oppStart; 1257 int hullResult = span->hullsIntersect(oppSpan, &spanStart, &oppStart); 1258 if (hullResult >= 0) { 1259 if (hullResult == 2) { // hulls have one point in common 1260 if (!span->fBounded || !span->fBounded->fNext) { 1261 SkASSERT(!span->fBounded || span->fBounded->fBounded == oppSpan); 1262 if (spanStart) { 1263 span->fEndT = span->fStartT; 1264 } else { 1265 span->fStartT = span->fEndT; 1266 } 1267 } else { 1268 hullResult = 1; 1269 } 1270 if (!oppSpan->fBounded || !oppSpan->fBounded->fNext) { 1271 SkASSERT(!oppSpan->fBounded || oppSpan->fBounded->fBounded == span); 1272 if (oppStart) { 1273 oppSpan->fEndT = oppSpan->fStartT; 1274 } else { 1275 oppSpan->fStartT = oppSpan->fEndT; 1276 } 1277 *oppResult = 2; 1278 } else { 1279 *oppResult = 1; 1280 } 1281 } else { 1282 *oppResult = 1; 1283 } 1284 return hullResult; 1285 } 1286 if (span->fIsLine && oppSpan->fIsLine) { 1287 SkIntersections i; 1288 int sects = this->linesIntersect(span, opp, oppSpan, &i); 1289 if (sects == 2) { 1290 return *oppResult = 1; 1291 } 1292 if (!sects) { 1293 return -1; 1294 } 1295 span->fStartT = span->fEndT = i[0][0]; 1296 oppSpan->fStartT = oppSpan->fEndT = i[1][0]; 1297 return *oppResult = 2; 1298 } 1299 if (span->fIsLinear || oppSpan->fIsLinear) { 1300 return *oppResult = (int) span->linearsIntersect(oppSpan); 1301 } 1302 return *oppResult = 1; 1303 } 1304 1305 template<typename TCurve> 1306 static bool is_parallel(const SkDLine& thisLine, const TCurve& opp) { 1307 if (!opp.IsConic()) { 1308 return false; // FIXME : breaks a lot of stuff now 1309 } 1310 int finds = 0; 1311 SkDLine thisPerp; 1312 thisPerp.fPts[0].fX = thisLine.fPts[1].fX + (thisLine.fPts[1].fY - thisLine.fPts[0].fY); 1313 thisPerp.fPts[0].fY = thisLine.fPts[1].fY + (thisLine.fPts[0].fX - thisLine.fPts[1].fX); 1314 thisPerp.fPts[1] = thisLine.fPts[1]; 1315 SkIntersections perpRayI; 1316 perpRayI.intersectRay(opp, thisPerp); 1317 for (int pIndex = 0; pIndex < perpRayI.used(); ++pIndex) { 1318 finds += perpRayI.pt(pIndex).approximatelyEqual(thisPerp.fPts[1]); 1319 } 1320 thisPerp.fPts[1].fX = thisLine.fPts[0].fX + (thisLine.fPts[1].fY - thisLine.fPts[0].fY); 1321 thisPerp.fPts[1].fY = thisLine.fPts[0].fY + (thisLine.fPts[0].fX - thisLine.fPts[1].fX); 1322 thisPerp.fPts[0] = thisLine.fPts[0]; 1323 perpRayI.intersectRay(opp, thisPerp); 1324 for (int pIndex = 0; pIndex < perpRayI.used(); ++pIndex) { 1325 finds += perpRayI.pt(pIndex).approximatelyEqual(thisPerp.fPts[0]); 1326 } 1327 return finds >= 2; 1328 } 1329 1330 // while the intersection points are sufficiently far apart: 1331 // construct the tangent lines from the intersections 1332 // find the point where the tangent line intersects the opposite curve 1333 template<typename TCurve, typename OppCurve> 1334 int SkTSect<TCurve, OppCurve>::linesIntersect(SkTSpan<TCurve, OppCurve>* span, 1335 SkTSect<OppCurve, TCurve>* opp, 1336 SkTSpan<OppCurve, TCurve>* oppSpan, SkIntersections* i) { 1337 SkIntersections thisRayI, oppRayI; 1338 SkDLine thisLine = {{ span->fPart[0], span->fPart[TCurve::kPointLast] }}; 1339 SkDLine oppLine = {{ oppSpan->fPart[0], oppSpan->fPart[OppCurve::kPointLast] }}; 1340 int loopCount = 0; 1341 double bestDistSq = DBL_MAX; 1342 if (!thisRayI.intersectRay(opp->fCurve, thisLine)) { 1343 return 0; 1344 } 1345 if (!oppRayI.intersectRay(this->fCurve, oppLine)) { 1346 return 0; 1347 } 1348 // if the ends of each line intersect the opposite curve, the lines are coincident 1349 if (thisRayI.used() > 1) { 1350 int ptMatches = 0; 1351 for (int tIndex = 0; tIndex < thisRayI.used(); ++tIndex) { 1352 for (int lIndex = 0; lIndex < (int) SK_ARRAY_COUNT(thisLine.fPts); ++lIndex) { 1353 ptMatches += thisRayI.pt(tIndex).approximatelyEqual(thisLine.fPts[lIndex]); 1354 } 1355 } 1356 if (ptMatches == 2 || is_parallel(thisLine, opp->fCurve)) { 1357 return 2; 1358 } 1359 } 1360 if (oppRayI.used() > 1) { 1361 int ptMatches = 0; 1362 for (int oIndex = 0; oIndex < oppRayI.used(); ++oIndex) { 1363 for (int lIndex = 0; lIndex < (int) SK_ARRAY_COUNT(thisLine.fPts); ++lIndex) { 1364 ptMatches += oppRayI.pt(oIndex).approximatelyEqual(oppLine.fPts[lIndex]); 1365 } 1366 } 1367 if (ptMatches == 2|| is_parallel(oppLine, this->fCurve)) { 1368 return 2; 1369 } 1370 } 1371 do { 1372 // pick the closest pair of points 1373 double closest = DBL_MAX; 1374 int closeIndex SK_INIT_TO_AVOID_WARNING; 1375 int oppCloseIndex SK_INIT_TO_AVOID_WARNING; 1376 for (int index = 0; index < oppRayI.used(); ++index) { 1377 if (!roughly_between(span->fStartT, oppRayI[0][index], span->fEndT)) { 1378 continue; 1379 } 1380 for (int oIndex = 0; oIndex < thisRayI.used(); ++oIndex) { 1381 if (!roughly_between(oppSpan->fStartT, thisRayI[0][oIndex], oppSpan->fEndT)) { 1382 continue; 1383 } 1384 double distSq = thisRayI.pt(index).distanceSquared(oppRayI.pt(oIndex)); 1385 if (closest > distSq) { 1386 closest = distSq; 1387 closeIndex = index; 1388 oppCloseIndex = oIndex; 1389 } 1390 } 1391 } 1392 if (closest == DBL_MAX) { 1393 break; 1394 } 1395 const SkDPoint& oppIPt = thisRayI.pt(oppCloseIndex); 1396 const SkDPoint& iPt = oppRayI.pt(closeIndex); 1397 if (between(span->fStartT, oppRayI[0][closeIndex], span->fEndT) 1398 && between(oppSpan->fStartT, thisRayI[0][oppCloseIndex], oppSpan->fEndT) 1399 && oppIPt.approximatelyEqual(iPt)) { 1400 i->merge(oppRayI, closeIndex, thisRayI, oppCloseIndex); 1401 return i->used(); 1402 } 1403 double distSq = oppIPt.distanceSquared(iPt); 1404 if (bestDistSq < distSq || ++loopCount > 5) { 1405 return 0; 1406 } 1407 bestDistSq = distSq; 1408 double oppStart = oppRayI[0][closeIndex]; 1409 thisLine[0] = fCurve.ptAtT(oppStart); 1410 thisLine[1] = thisLine[0] + fCurve.dxdyAtT(oppStart); 1411 if (!thisRayI.intersectRay(opp->fCurve, thisLine)) { 1412 break; 1413 } 1414 double start = thisRayI[0][oppCloseIndex]; 1415 oppLine[0] = opp->fCurve.ptAtT(start); 1416 oppLine[1] = oppLine[0] + opp->fCurve.dxdyAtT(start); 1417 if (!oppRayI.intersectRay(this->fCurve, oppLine)) { 1418 break; 1419 } 1420 } while (true); 1421 // convergence may fail if the curves are nearly coincident 1422 SkTCoincident<OppCurve, TCurve> oCoinS, oCoinE; 1423 oCoinS.setPerp(opp->fCurve, oppSpan->fStartT, oppSpan->fPart[0], fCurve); 1424 oCoinE.setPerp(opp->fCurve, oppSpan->fEndT, oppSpan->fPart[OppCurve::kPointLast], fCurve); 1425 double tStart = oCoinS.perpT(); 1426 double tEnd = oCoinE.perpT(); 1427 bool swap = tStart > tEnd; 1428 if (swap) { 1429 SkTSwap(tStart, tEnd); 1430 } 1431 tStart = SkTMax(tStart, span->fStartT); 1432 tEnd = SkTMin(tEnd, span->fEndT); 1433 if (tStart > tEnd) { 1434 return 0; 1435 } 1436 SkDVector perpS, perpE; 1437 if (tStart == span->fStartT) { 1438 SkTCoincident<TCurve, OppCurve> coinS; 1439 coinS.setPerp(fCurve, span->fStartT, span->fPart[0], opp->fCurve); 1440 perpS = span->fPart[0] - coinS.perpPt(); 1441 } else if (swap) { 1442 perpS = oCoinE.perpPt() - oppSpan->fPart[OppCurve::kPointLast]; 1443 } else { 1444 perpS = oCoinS.perpPt() - oppSpan->fPart[0]; 1445 } 1446 if (tEnd == span->fEndT) { 1447 SkTCoincident<TCurve, OppCurve> coinE; 1448 coinE.setPerp(fCurve, span->fEndT, span->fPart[TCurve::kPointLast], opp->fCurve); 1449 perpE = span->fPart[TCurve::kPointLast] - coinE.perpPt(); 1450 } else if (swap) { 1451 perpE = oCoinS.perpPt() - oppSpan->fPart[0]; 1452 } else { 1453 perpE = oCoinE.perpPt() - oppSpan->fPart[OppCurve::kPointLast]; 1454 } 1455 if (perpS.dot(perpE) >= 0) { 1456 return 0; 1457 } 1458 SkTCoincident<TCurve, OppCurve> coinW; 1459 double workT = tStart; 1460 double tStep = tEnd - tStart; 1461 SkDPoint workPt; 1462 do { 1463 tStep *= 0.5; 1464 if (precisely_zero(tStep)) { 1465 return 0; 1466 } 1467 workT += tStep; 1468 workPt = fCurve.ptAtT(workT); 1469 coinW.setPerp(fCurve, workT, workPt, opp->fCurve); 1470 if (coinW.perpT() < 0) { 1471 continue; 1472 } 1473 SkDVector perpW = workPt - coinW.perpPt(); 1474 if ((perpS.dot(perpW) >= 0) == (tStep < 0)) { 1475 tStep = -tStep; 1476 } 1477 if (workPt.approximatelyEqual(coinW.perpPt())) { 1478 break; 1479 } 1480 } while (true); 1481 double oppTTest = coinW.perpT(); 1482 if (!opp->fHead->contains(oppTTest)) { 1483 return 0; 1484 } 1485 i->setMax(1); 1486 i->insert(workT, oppTTest, workPt); 1487 return 1; 1488 } 1489 1490 1491 template<typename TCurve, typename OppCurve> 1492 void SkTSect<TCurve, OppCurve>::markSpanGone(SkTSpan<TCurve, OppCurve>* span) { 1493 --fActiveCount; 1494 span->fNext = fDeleted; 1495 fDeleted = span; 1496 SkASSERT(!span->fDeleted); 1497 span->fDeleted = true; 1498 } 1499 1500 template<typename TCurve, typename OppCurve> 1501 bool SkTSect<TCurve, OppCurve>::matchedDirection(double t, const SkTSect<OppCurve, TCurve>* sect2, 1502 double t2) const { 1503 SkDVector dxdy = this->fCurve.dxdyAtT(t); 1504 SkDVector dxdy2 = sect2->fCurve.dxdyAtT(t2); 1505 return dxdy.dot(dxdy2) >= 0; 1506 } 1507 1508 template<typename TCurve, typename OppCurve> 1509 void SkTSect<TCurve, OppCurve>::matchedDirCheck(double t, const SkTSect<OppCurve, TCurve>* sect2, 1510 double t2, bool* calcMatched, bool* oppMatched) const { 1511 if (*calcMatched) { 1512 SkASSERT(*oppMatched == this->matchedDirection(t, sect2, t2)); 1513 } else { 1514 *oppMatched = this->matchedDirection(t, sect2, t2); 1515 *calcMatched = true; 1516 } 1517 } 1518 1519 template<typename TCurve, typename OppCurve> 1520 void SkTSect<TCurve, OppCurve>::mergeCoincidence(SkTSect<OppCurve, TCurve>* sect2) { 1521 double smallLimit = 0; 1522 do { 1523 // find the smallest unprocessed span 1524 SkTSpan<TCurve, OppCurve>* smaller = nullptr; 1525 SkTSpan<TCurve, OppCurve>* test = fCoincident; 1526 do { 1527 if (test->fStartT < smallLimit) { 1528 continue; 1529 } 1530 if (smaller && smaller->fEndT < test->fStartT) { 1531 continue; 1532 } 1533 smaller = test; 1534 } while ((test = test->fNext)); 1535 if (!smaller) { 1536 return; 1537 } 1538 smallLimit = smaller->fEndT; 1539 // find next larger span 1540 SkTSpan<TCurve, OppCurve>* prior = nullptr; 1541 SkTSpan<TCurve, OppCurve>* larger = nullptr; 1542 SkTSpan<TCurve, OppCurve>* largerPrior = nullptr; 1543 test = fCoincident; 1544 do { 1545 if (test->fStartT < smaller->fEndT) { 1546 continue; 1547 } 1548 SkASSERT(test->fStartT != smaller->fEndT); 1549 if (larger && larger->fStartT < test->fStartT) { 1550 continue; 1551 } 1552 largerPrior = prior; 1553 larger = test; 1554 } while ((prior = test), (test = test->fNext)); 1555 if (!larger) { 1556 continue; 1557 } 1558 // check middle t value to see if it is coincident as well 1559 double midT = (smaller->fEndT + larger->fStartT) / 2; 1560 SkDPoint midPt = fCurve.ptAtT(midT); 1561 SkTCoincident<TCurve, OppCurve> coin; 1562 coin.setPerp(fCurve, midT, midPt, sect2->fCurve); 1563 if (coin.isCoincident()) { 1564 smaller->fEndT = larger->fEndT; 1565 smaller->fCoinEnd = larger->fCoinEnd; 1566 if (largerPrior) { 1567 largerPrior->fNext = larger->fNext; 1568 } else { 1569 fCoincident = larger->fNext; 1570 } 1571 } 1572 } while (true); 1573 } 1574 1575 template<typename TCurve, typename OppCurve> 1576 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::prev( 1577 SkTSpan<TCurve, OppCurve>* span) const { 1578 SkTSpan<TCurve, OppCurve>* result = nullptr; 1579 SkTSpan<TCurve, OppCurve>* test = fHead; 1580 while (span != test) { 1581 result = test; 1582 test = test->fNext; 1583 SkASSERT(test); 1584 } 1585 return result; 1586 } 1587 1588 template<typename TCurve, typename OppCurve> 1589 void SkTSect<TCurve, OppCurve>::recoverCollapsed() { 1590 SkTSpan<TCurve, OppCurve>* deleted = fDeleted; 1591 while (deleted) { 1592 SkTSpan<TCurve, OppCurve>* delNext = deleted->fNext; 1593 if (deleted->fCollapsed) { 1594 SkTSpan<TCurve, OppCurve>** spanPtr = &fHead; 1595 while (*spanPtr && (*spanPtr)->fEndT <= deleted->fStartT) { 1596 spanPtr = &(*spanPtr)->fNext; 1597 } 1598 deleted->fNext = *spanPtr; 1599 *spanPtr = deleted; 1600 } 1601 deleted = delNext; 1602 } 1603 } 1604 1605 template<typename TCurve, typename OppCurve> 1606 void SkTSect<TCurve, OppCurve>::removeAllBut(const SkTSpan<OppCurve, TCurve>* keep, 1607 SkTSpan<TCurve, OppCurve>* span, SkTSect<OppCurve, TCurve>* opp) { 1608 const SkTSpanBounded<OppCurve, TCurve>* testBounded = span->fBounded; 1609 while (testBounded) { 1610 SkTSpan<OppCurve, TCurve>* bounded = testBounded->fBounded; 1611 const SkTSpanBounded<OppCurve, TCurve>* next = testBounded->fNext; 1612 // may have been deleted when opp did 'remove all but' 1613 if (bounded != keep && !bounded->fDeleted) { 1614 SkAssertResult(SkDEBUGCODE(!) span->removeBounded(bounded)); 1615 if (bounded->removeBounded(span)) { 1616 opp->removeSpan(bounded); 1617 } 1618 } 1619 testBounded = next; 1620 } 1621 SkASSERT(!span->fDeleted); 1622 SkASSERT(span->findOppSpan(keep)); 1623 SkASSERT(keep->findOppSpan(span)); 1624 } 1625 1626 template<typename TCurve, typename OppCurve> 1627 void SkTSect<TCurve, OppCurve>::removeByPerpendicular(SkTSect<OppCurve, TCurve>* opp) { 1628 SkTSpan<TCurve, OppCurve>* test = fHead; 1629 SkTSpan<TCurve, OppCurve>* next; 1630 do { 1631 next = test->fNext; 1632 if (test->fCoinStart.perpT() < 0 || test->fCoinEnd.perpT() < 0) { 1633 continue; 1634 } 1635 SkDVector startV = test->fCoinStart.perpPt() - test->fPart[0]; 1636 SkDVector endV = test->fCoinEnd.perpPt() - test->fPart[TCurve::kPointLast]; 1637 #if DEBUG_T_SECT 1638 SkDebugf("%s startV=(%1.9g,%1.9g) endV=(%1.9g,%1.9g) dot=%1.9g\n", __FUNCTION__, 1639 startV.fX, startV.fY, endV.fX, endV.fY, startV.dot(endV)); 1640 #endif 1641 if (startV.dot(endV) <= 0) { 1642 continue; 1643 } 1644 this->removeSpans(test, opp); 1645 } while ((test = next)); 1646 } 1647 1648 template<typename TCurve, typename OppCurve> 1649 void SkTSect<TCurve, OppCurve>::removeCoincident(SkTSpan<TCurve, OppCurve>* span, bool isBetween) { 1650 this->unlinkSpan(span); 1651 if (isBetween || between(0, span->fCoinStart.perpT(), 1)) { 1652 --fActiveCount; 1653 span->fNext = fCoincident; 1654 fCoincident = span; 1655 } else { 1656 this->markSpanGone(span); 1657 } 1658 } 1659 1660 template<typename TCurve, typename OppCurve> 1661 void SkTSect<TCurve, OppCurve>::removeSpan(SkTSpan<TCurve, OppCurve>* span) { 1662 this->unlinkSpan(span); 1663 this->markSpanGone(span); 1664 } 1665 1666 template<typename TCurve, typename OppCurve> 1667 void SkTSect<TCurve, OppCurve>::removeSpanRange(SkTSpan<TCurve, OppCurve>* first, 1668 SkTSpan<TCurve, OppCurve>* last) { 1669 if (first == last) { 1670 return; 1671 } 1672 SkTSpan<TCurve, OppCurve>* span = first; 1673 SkASSERT(span); 1674 SkTSpan<TCurve, OppCurve>* final = last->fNext; 1675 SkTSpan<TCurve, OppCurve>* next = span->fNext; 1676 while ((span = next) && span != final) { 1677 next = span->fNext; 1678 this->markSpanGone(span); 1679 } 1680 if (final) { 1681 final->fPrev = first; 1682 } 1683 first->fNext = final; 1684 } 1685 1686 template<typename TCurve, typename OppCurve> 1687 void SkTSect<TCurve, OppCurve>::removeSpans(SkTSpan<TCurve, OppCurve>* span, 1688 SkTSect<OppCurve, TCurve>* opp) { 1689 SkTSpanBounded<OppCurve, TCurve>* bounded = span->fBounded; 1690 while (bounded) { 1691 SkTSpan<OppCurve, TCurve>* spanBounded = bounded->fBounded; 1692 SkTSpanBounded<OppCurve, TCurve>* next = bounded->fNext; 1693 if (span->removeBounded(spanBounded)) { // shuffles last into position 0 1694 this->removeSpan(span); 1695 } 1696 if (spanBounded->removeBounded(span)) { 1697 opp->removeSpan(spanBounded); 1698 } 1699 SkASSERT(!span->fDeleted || !opp->debugHasBounded(span)); 1700 bounded = next; 1701 } 1702 } 1703 1704 template<typename TCurve, typename OppCurve> 1705 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::spanAtT(double t, 1706 SkTSpan<TCurve, OppCurve>** priorSpan) { 1707 SkTSpan<TCurve, OppCurve>* test = fHead; 1708 SkTSpan<TCurve, OppCurve>* prev = nullptr; 1709 while (test && test->fEndT < t) { 1710 prev = test; 1711 test = test->fNext; 1712 } 1713 *priorSpan = prev; 1714 return test && test->fStartT <= t ? test : nullptr; 1715 } 1716 1717 template<typename TCurve, typename OppCurve> 1718 SkTSpan<TCurve, OppCurve>* SkTSect<TCurve, OppCurve>::tail() { 1719 SkTSpan<TCurve, OppCurve>* result = fHead; 1720 SkTSpan<TCurve, OppCurve>* next = fHead; 1721 while ((next = next->fNext)) { 1722 if (next->fEndT > result->fEndT) { 1723 result = next; 1724 } 1725 } 1726 return result; 1727 } 1728 1729 /* Each span has a range of opposite spans it intersects. After the span is split in two, 1730 adjust the range to its new size */ 1731 template<typename TCurve, typename OppCurve> 1732 void SkTSect<TCurve, OppCurve>::trim(SkTSpan<TCurve, OppCurve>* span, 1733 SkTSect<OppCurve, TCurve>* opp) { 1734 span->initBounds(fCurve); 1735 const SkTSpanBounded<OppCurve, TCurve>* testBounded = span->fBounded; 1736 while (testBounded) { 1737 SkTSpan<OppCurve, TCurve>* test = testBounded->fBounded; 1738 const SkTSpanBounded<OppCurve, TCurve>* next = testBounded->fNext; 1739 int oppSects, sects = this->intersects(span, opp, test, &oppSects); 1740 if (sects >= 1) { 1741 if (oppSects == 2) { 1742 test->initBounds(opp->fCurve); 1743 opp->removeAllBut(span, test, this); 1744 } 1745 if (sects == 2) { 1746 span->initBounds(fCurve); 1747 this->removeAllBut(test, span, opp); 1748 return; 1749 } 1750 } else { 1751 if (span->removeBounded(test)) { 1752 this->removeSpan(span); 1753 } 1754 if (test->removeBounded(span)) { 1755 opp->removeSpan(test); 1756 } 1757 } 1758 testBounded = next; 1759 } 1760 } 1761 1762 template<typename TCurve, typename OppCurve> 1763 void SkTSect<TCurve, OppCurve>::unlinkSpan(SkTSpan<TCurve, OppCurve>* span) { 1764 SkTSpan<TCurve, OppCurve>* prev = span->fPrev; 1765 SkTSpan<TCurve, OppCurve>* next = span->fNext; 1766 if (prev) { 1767 prev->fNext = next; 1768 if (next) { 1769 next->fPrev = prev; 1770 } 1771 } else { 1772 fHead = next; 1773 if (next) { 1774 next->fPrev = nullptr; 1775 } 1776 } 1777 } 1778 1779 template<typename TCurve, typename OppCurve> 1780 bool SkTSect<TCurve, OppCurve>::updateBounded(SkTSpan<TCurve, OppCurve>* first, 1781 SkTSpan<TCurve, OppCurve>* last, SkTSpan<OppCurve, TCurve>* oppFirst) { 1782 SkTSpan<TCurve, OppCurve>* test = first; 1783 const SkTSpan<TCurve, OppCurve>* final = last->next(); 1784 bool deleteSpan = false; 1785 do { 1786 deleteSpan |= test->removeAllBounded(); 1787 } while ((test = test->fNext) != final); 1788 first->fBounded = nullptr; 1789 first->addBounded(oppFirst, &fHeap); 1790 // cannot call validate until remove span range is called 1791 return deleteSpan; 1792 } 1793 1794 1795 template<typename TCurve, typename OppCurve> 1796 void SkTSect<TCurve, OppCurve>::validate() const { 1797 #if DEBUG_T_SECT 1798 int count = 0; 1799 if (fHead) { 1800 const SkTSpan<TCurve, OppCurve>* span = fHead; 1801 SkASSERT(!span->fPrev); 1802 SkDEBUGCODE(double last = 0); 1803 do { 1804 span->validate(); 1805 SkASSERT(span->fStartT >= last); 1806 SkDEBUGCODE(last = span->fEndT); 1807 ++count; 1808 } while ((span = span->fNext) != nullptr); 1809 } 1810 SkASSERT(count == fActiveCount); 1811 SkASSERT(fActiveCount <= fDebugAllocatedCount); 1812 int deletedCount = 0; 1813 const SkTSpan<TCurve, OppCurve>* deleted = fDeleted; 1814 while (deleted) { 1815 ++deletedCount; 1816 deleted = deleted->fNext; 1817 } 1818 const SkTSpan<TCurve, OppCurve>* coincident = fCoincident; 1819 while (coincident) { 1820 ++deletedCount; 1821 coincident = coincident->fNext; 1822 } 1823 SkASSERT(fActiveCount + deletedCount == fDebugAllocatedCount); 1824 #endif 1825 } 1826 1827 template<typename TCurve, typename OppCurve> 1828 void SkTSect<TCurve, OppCurve>::validateBounded() const { 1829 #if DEBUG_T_SECT 1830 if (!fHead) { 1831 return; 1832 } 1833 const SkTSpan<TCurve, OppCurve>* span = fHead; 1834 do { 1835 span->validateBounded(); 1836 } while ((span = span->fNext) != nullptr); 1837 #endif 1838 } 1839 1840 template<typename TCurve, typename OppCurve> 1841 int SkTSect<TCurve, OppCurve>::EndsEqual(const SkTSect<TCurve, OppCurve>* sect1, 1842 const SkTSect<OppCurve, TCurve>* sect2, SkIntersections* intersections) { 1843 int zeroOneSet = 0; 1844 if (sect1->fCurve[0] == sect2->fCurve[0]) { 1845 zeroOneSet |= kZeroS1Set | kZeroS2Set; 1846 intersections->insert(0, 0, sect1->fCurve[0]); 1847 } 1848 if (sect1->fCurve[0] == sect2->fCurve[OppCurve::kPointLast]) { 1849 zeroOneSet |= kZeroS1Set | kOneS2Set; 1850 intersections->insert(0, 1, sect1->fCurve[0]); 1851 } 1852 if (sect1->fCurve[TCurve::kPointLast] == sect2->fCurve[0]) { 1853 zeroOneSet |= kOneS1Set | kZeroS2Set; 1854 intersections->insert(1, 0, sect1->fCurve[TCurve::kPointLast]); 1855 } 1856 if (sect1->fCurve[TCurve::kPointLast] == sect2->fCurve[OppCurve::kPointLast]) { 1857 zeroOneSet |= kOneS1Set | kOneS2Set; 1858 intersections->insert(1, 1, sect1->fCurve[TCurve::kPointLast]); 1859 } 1860 // check for zero 1861 if (!(zeroOneSet & (kZeroS1Set | kZeroS2Set)) 1862 && sect1->fCurve[0].approximatelyEqual(sect2->fCurve[0])) { 1863 zeroOneSet |= kZeroS1Set | kZeroS2Set; 1864 intersections->insertNear(0, 0, sect1->fCurve[0], sect2->fCurve[0]); 1865 } 1866 if (!(zeroOneSet & (kZeroS1Set | kOneS2Set)) 1867 && sect1->fCurve[0].approximatelyEqual(sect2->fCurve[OppCurve::kPointLast])) { 1868 zeroOneSet |= kZeroS1Set | kOneS2Set; 1869 intersections->insertNear(0, 1, sect1->fCurve[0], sect2->fCurve[OppCurve::kPointLast]); 1870 } 1871 // check for one 1872 if (!(zeroOneSet & (kOneS1Set | kZeroS2Set)) 1873 && sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[0])) { 1874 zeroOneSet |= kOneS1Set | kZeroS2Set; 1875 intersections->insertNear(1, 0, sect1->fCurve[TCurve::kPointLast], sect2->fCurve[0]); 1876 } 1877 if (!(zeroOneSet & (kOneS1Set | kOneS2Set)) 1878 && sect1->fCurve[TCurve::kPointLast].approximatelyEqual(sect2->fCurve[ 1879 OppCurve::kPointLast])) { 1880 zeroOneSet |= kOneS1Set | kOneS2Set; 1881 intersections->insertNear(1, 1, sect1->fCurve[TCurve::kPointLast], 1882 sect2->fCurve[OppCurve::kPointLast]); 1883 } 1884 return zeroOneSet; 1885 } 1886 1887 template<typename TCurve, typename OppCurve> 1888 struct SkClosestRecord { 1889 bool operator<(const SkClosestRecord& rh) const { 1890 return fClosest < rh.fClosest; 1891 } 1892 1893 void addIntersection(SkIntersections* intersections) const { 1894 double r1t = fC1Index ? fC1Span->endT() : fC1Span->startT(); 1895 double r2t = fC2Index ? fC2Span->endT() : fC2Span->startT(); 1896 intersections->insert(r1t, r2t, fC1Span->part()[fC1Index]); 1897 } 1898 1899 void findEnd(const SkTSpan<TCurve, OppCurve>* span1, const SkTSpan<OppCurve, TCurve>* span2, 1900 int c1Index, int c2Index) { 1901 const TCurve& c1 = span1->part(); 1902 const OppCurve& c2 = span2->part(); 1903 if (!c1[c1Index].approximatelyEqual(c2[c2Index])) { 1904 return; 1905 } 1906 double dist = c1[c1Index].distanceSquared(c2[c2Index]); 1907 if (fClosest < dist) { 1908 return; 1909 } 1910 fC1Span = span1; 1911 fC2Span = span2; 1912 fC1StartT = span1->startT(); 1913 fC1EndT = span1->endT(); 1914 fC2StartT = span2->startT(); 1915 fC2EndT = span2->endT(); 1916 fC1Index = c1Index; 1917 fC2Index = c2Index; 1918 fClosest = dist; 1919 } 1920 1921 bool matesWith(const SkClosestRecord& mate) const { 1922 SkASSERT(fC1Span == mate.fC1Span || fC1Span->endT() <= mate.fC1Span->startT() 1923 || mate.fC1Span->endT() <= fC1Span->startT()); 1924 SkASSERT(fC2Span == mate.fC2Span || fC2Span->endT() <= mate.fC2Span->startT() 1925 || mate.fC2Span->endT() <= fC2Span->startT()); 1926 return fC1Span == mate.fC1Span || fC1Span->endT() == mate.fC1Span->startT() 1927 || fC1Span->startT() == mate.fC1Span->endT() 1928 || fC2Span == mate.fC2Span 1929 || fC2Span->endT() == mate.fC2Span->startT() 1930 || fC2Span->startT() == mate.fC2Span->endT(); 1931 } 1932 1933 void merge(const SkClosestRecord& mate) { 1934 fC1Span = mate.fC1Span; 1935 fC2Span = mate.fC2Span; 1936 fClosest = mate.fClosest; 1937 fC1Index = mate.fC1Index; 1938 fC2Index = mate.fC2Index; 1939 } 1940 1941 void reset() { 1942 fClosest = FLT_MAX; 1943 SkDEBUGCODE(fC1Span = nullptr); 1944 SkDEBUGCODE(fC2Span = nullptr); 1945 SkDEBUGCODE(fC1Index = fC2Index = -1); 1946 } 1947 1948 void update(const SkClosestRecord& mate) { 1949 fC1StartT = SkTMin(fC1StartT, mate.fC1StartT); 1950 fC1EndT = SkTMax(fC1EndT, mate.fC1EndT); 1951 fC2StartT = SkTMin(fC2StartT, mate.fC2StartT); 1952 fC2EndT = SkTMax(fC2EndT, mate.fC2EndT); 1953 } 1954 1955 const SkTSpan<TCurve, OppCurve>* fC1Span; 1956 const SkTSpan<OppCurve, TCurve>* fC2Span; 1957 double fC1StartT; 1958 double fC1EndT; 1959 double fC2StartT; 1960 double fC2EndT; 1961 double fClosest; 1962 int fC1Index; 1963 int fC2Index; 1964 }; 1965 1966 template<typename TCurve, typename OppCurve> 1967 struct SkClosestSect { 1968 SkClosestSect() 1969 : fUsed(0) { 1970 fClosest.push_back().reset(); 1971 } 1972 1973 bool find(const SkTSpan<TCurve, OppCurve>* span1, const SkTSpan<OppCurve, TCurve>* span2) { 1974 SkClosestRecord<TCurve, OppCurve>* record = &fClosest[fUsed]; 1975 record->findEnd(span1, span2, 0, 0); 1976 record->findEnd(span1, span2, 0, OppCurve::kPointLast); 1977 record->findEnd(span1, span2, TCurve::kPointLast, 0); 1978 record->findEnd(span1, span2, TCurve::kPointLast, OppCurve::kPointLast); 1979 if (record->fClosest == FLT_MAX) { 1980 return false; 1981 } 1982 for (int index = 0; index < fUsed; ++index) { 1983 SkClosestRecord<TCurve, OppCurve>* test = &fClosest[index]; 1984 if (test->matesWith(*record)) { 1985 if (test->fClosest > record->fClosest) { 1986 test->merge(*record); 1987 } 1988 test->update(*record); 1989 record->reset(); 1990 return false; 1991 } 1992 } 1993 ++fUsed; 1994 fClosest.push_back().reset(); 1995 return true; 1996 } 1997 1998 void finish(SkIntersections* intersections) const { 1999 SkSTArray<TCurve::kMaxIntersections * 3, 2000 const SkClosestRecord<TCurve, OppCurve>*, true> closestPtrs; 2001 for (int index = 0; index < fUsed; ++index) { 2002 closestPtrs.push_back(&fClosest[index]); 2003 } 2004 SkTQSort<const SkClosestRecord<TCurve, OppCurve> >(closestPtrs.begin(), closestPtrs.end() 2005 - 1); 2006 for (int index = 0; index < fUsed; ++index) { 2007 const SkClosestRecord<TCurve, OppCurve>* test = closestPtrs[index]; 2008 test->addIntersection(intersections); 2009 } 2010 } 2011 2012 // this is oversized so that an extra records can merge into final one 2013 SkSTArray<TCurve::kMaxIntersections * 2, SkClosestRecord<TCurve, OppCurve>, true> fClosest; 2014 int fUsed; 2015 }; 2016 2017 // returns true if the rect is too small to consider 2018 template<typename TCurve, typename OppCurve> 2019 void SkTSect<TCurve, OppCurve>::BinarySearch(SkTSect<TCurve, OppCurve>* sect1, 2020 SkTSect<OppCurve, TCurve>* sect2, SkIntersections* intersections) { 2021 #if DEBUG_T_SECT_DUMP > 1 2022 gDumpTSectNum = 0; 2023 #endif 2024 SkDEBUGCODE(sect1->fOppSect = sect2); 2025 SkDEBUGCODE(sect2->fOppSect = sect1); 2026 intersections->reset(); 2027 intersections->setMax(TCurve::kMaxIntersections + 3); // give extra for slop 2028 SkTSpan<TCurve, OppCurve>* span1 = sect1->fHead; 2029 SkTSpan<OppCurve, TCurve>* span2 = sect2->fHead; 2030 int oppSect, sect = sect1->intersects(span1, sect2, span2, &oppSect); 2031 // SkASSERT(between(0, sect, 2)); 2032 if (!sect) { 2033 return; 2034 } 2035 if (sect == 2 && oppSect == 2) { 2036 (void) EndsEqual(sect1, sect2, intersections); 2037 return; 2038 } 2039 span1->addBounded(span2, §1->fHeap); 2040 span2->addBounded(span1, §2->fHeap); 2041 const int kMaxCoinLoopCount = 8; 2042 int coinLoopCount = kMaxCoinLoopCount; 2043 double start1s SK_INIT_TO_AVOID_WARNING; 2044 double start1e SK_INIT_TO_AVOID_WARNING; 2045 do { 2046 // find the largest bounds 2047 SkTSpan<TCurve, OppCurve>* largest1 = sect1->boundsMax(); 2048 if (!largest1) { 2049 break; 2050 } 2051 SkTSpan<OppCurve, TCurve>* largest2 = sect2->boundsMax(); 2052 // split it 2053 if (!largest2 || (largest1 && (largest1->fBoundsMax > largest2->fBoundsMax 2054 || (!largest1->fCollapsed && largest2->fCollapsed)))) { 2055 if (largest1->fCollapsed) { 2056 break; 2057 } 2058 // trim parts that don't intersect the opposite 2059 SkTSpan<TCurve, OppCurve>* half1 = sect1->addOne(); 2060 if (!half1->split(largest1, §1->fHeap)) { 2061 break; 2062 } 2063 sect1->trim(largest1, sect2); 2064 sect1->trim(half1, sect2); 2065 } else { 2066 if (largest2->fCollapsed) { 2067 break; 2068 } 2069 // trim parts that don't intersect the opposite 2070 SkTSpan<OppCurve, TCurve>* half2 = sect2->addOne(); 2071 if (!half2->split(largest2, §2->fHeap)) { 2072 break; 2073 } 2074 sect2->trim(largest2, sect1); 2075 sect2->trim(half2, sect1); 2076 } 2077 sect1->validate(); 2078 sect2->validate(); 2079 #if DEBUG_T_SECT_LOOP_COUNT 2080 intersections->debugBumpLoopCount(SkIntersections::kIterations_DebugLoop); 2081 #endif 2082 // if there are 9 or more continuous spans on both sects, suspect coincidence 2083 if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT 2084 && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) { 2085 if (coinLoopCount == kMaxCoinLoopCount) { 2086 start1s = sect1->fHead->fStartT; 2087 start1e = sect1->tail()->fEndT; 2088 } 2089 sect1->coincidentCheck(sect2); 2090 sect1->validate(); 2091 sect2->validate(); 2092 #if DEBUG_T_SECT_LOOP_COUNT 2093 intersections->debugBumpLoopCount(SkIntersections::kCoinCheck_DebugLoop); 2094 #endif 2095 if (!--coinLoopCount && sect1->fHead && sect2->fHead) { 2096 /* All known working cases resolve in two tries. Sadly, cubicConicTests[0] 2097 gets stuck in a loop. It adds an extension to allow a coincident end 2098 perpendicular to track its intersection in the opposite curve. However, 2099 the bounding box of the extension does not intersect the original curve, 2100 so the extension is discarded, only to be added again the next time around. */ 2101 sect1->coincidentForce(sect2, start1s, start1e); 2102 sect1->validate(); 2103 sect2->validate(); 2104 } 2105 } 2106 if (sect1->fActiveCount >= COINCIDENT_SPAN_COUNT 2107 && sect2->fActiveCount >= COINCIDENT_SPAN_COUNT) { 2108 sect1->computePerpendiculars(sect2, sect1->fHead, sect1->tail()); 2109 sect2->computePerpendiculars(sect1, sect2->fHead, sect2->tail()); 2110 sect1->removeByPerpendicular(sect2); 2111 sect1->validate(); 2112 sect2->validate(); 2113 #if DEBUG_T_SECT_LOOP_COUNT 2114 intersections->debugBumpLoopCount(SkIntersections::kComputePerp_DebugLoop); 2115 #endif 2116 if (sect1->collapsed() > TCurve::kMaxIntersections) { 2117 break; 2118 } 2119 } 2120 #if DEBUG_T_SECT_DUMP 2121 sect1->dumpBoth(sect2); 2122 #endif 2123 if (!sect1->fHead || !sect2->fHead) { 2124 break; 2125 } 2126 } while (true); 2127 SkTSpan<TCurve, OppCurve>* coincident = sect1->fCoincident; 2128 if (coincident) { 2129 // if there is more than one coincident span, check loosely to see if they should be joined 2130 if (coincident->fNext) { 2131 sect1->mergeCoincidence(sect2); 2132 coincident = sect1->fCoincident; 2133 } 2134 SkASSERT(sect2->fCoincident); // courtesy check : coincidence only looks at sect 1 2135 do { 2136 if (!coincident->fCoinStart.isCoincident()) { 2137 continue; 2138 } 2139 if (!coincident->fCoinEnd.isCoincident()) { 2140 continue; 2141 } 2142 int index = intersections->insertCoincident(coincident->fStartT, 2143 coincident->fCoinStart.perpT(), coincident->fPart[0]); 2144 if ((intersections->insertCoincident(coincident->fEndT, 2145 coincident->fCoinEnd.perpT(), 2146 coincident->fPart[TCurve::kPointLast]) < 0) && index >= 0) { 2147 intersections->clearCoincidence(index); 2148 } 2149 } while ((coincident = coincident->fNext)); 2150 } 2151 int zeroOneSet = EndsEqual(sect1, sect2, intersections); 2152 if (!sect1->fHead || !sect2->fHead) { 2153 return; 2154 } 2155 sect1->recoverCollapsed(); 2156 sect2->recoverCollapsed(); 2157 SkTSpan<TCurve, OppCurve>* result1 = sect1->fHead; 2158 // check heads and tails for zero and ones and insert them if we haven't already done so 2159 const SkTSpan<TCurve, OppCurve>* head1 = result1; 2160 if (!(zeroOneSet & kZeroS1Set) && approximately_less_than_zero(head1->fStartT)) { 2161 const SkDPoint& start1 = sect1->fCurve[0]; 2162 if (head1->isBounded()) { 2163 double t = head1->closestBoundedT(start1); 2164 if (sect2->fCurve.ptAtT(t).approximatelyEqual(start1)) { 2165 intersections->insert(0, t, start1); 2166 } 2167 } 2168 } 2169 const SkTSpan<OppCurve, TCurve>* head2 = sect2->fHead; 2170 if (!(zeroOneSet & kZeroS2Set) && approximately_less_than_zero(head2->fStartT)) { 2171 const SkDPoint& start2 = sect2->fCurve[0]; 2172 if (head2->isBounded()) { 2173 double t = head2->closestBoundedT(start2); 2174 if (sect1->fCurve.ptAtT(t).approximatelyEqual(start2)) { 2175 intersections->insert(t, 0, start2); 2176 } 2177 } 2178 } 2179 const SkTSpan<TCurve, OppCurve>* tail1 = sect1->tail(); 2180 if (!(zeroOneSet & kOneS1Set) && approximately_greater_than_one(tail1->fEndT)) { 2181 const SkDPoint& end1 = sect1->fCurve[TCurve::kPointLast]; 2182 if (tail1->isBounded()) { 2183 double t = tail1->closestBoundedT(end1); 2184 if (sect2->fCurve.ptAtT(t).approximatelyEqual(end1)) { 2185 intersections->insert(1, t, end1); 2186 } 2187 } 2188 } 2189 const SkTSpan<OppCurve, TCurve>* tail2 = sect2->tail(); 2190 if (!(zeroOneSet & kOneS2Set) && approximately_greater_than_one(tail2->fEndT)) { 2191 const SkDPoint& end2 = sect2->fCurve[OppCurve::kPointLast]; 2192 if (tail2->isBounded()) { 2193 double t = tail2->closestBoundedT(end2); 2194 if (sect1->fCurve.ptAtT(t).approximatelyEqual(end2)) { 2195 intersections->insert(t, 1, end2); 2196 } 2197 } 2198 } 2199 SkClosestSect<TCurve, OppCurve> closest; 2200 do { 2201 while (result1 && result1->fCoinStart.isCoincident() && result1->fCoinEnd.isCoincident()) { 2202 result1 = result1->fNext; 2203 } 2204 if (!result1) { 2205 break; 2206 } 2207 SkTSpan<OppCurve, TCurve>* result2 = sect2->fHead; 2208 bool found = false; 2209 while (result2) { 2210 found |= closest.find(result1, result2); 2211 result2 = result2->fNext; 2212 } 2213 } while ((result1 = result1->fNext)); 2214 closest.finish(intersections); 2215 // if there is more than one intersection and it isn't already coincident, check 2216 int last = intersections->used() - 1; 2217 for (int index = 0; index < last; ) { 2218 if (intersections->isCoincident(index) && intersections->isCoincident(index + 1)) { 2219 ++index; 2220 continue; 2221 } 2222 double midT = ((*intersections)[0][index] + (*intersections)[0][index + 1]) / 2; 2223 SkDPoint midPt = sect1->fCurve.ptAtT(midT); 2224 // intersect perpendicular with opposite curve 2225 SkTCoincident<TCurve, OppCurve> perp; 2226 perp.setPerp(sect1->fCurve, midT, midPt, sect2->fCurve); 2227 if (!perp.isCoincident()) { 2228 ++index; 2229 continue; 2230 } 2231 if (intersections->isCoincident(index)) { 2232 intersections->removeOne(index); 2233 --last; 2234 } else if (intersections->isCoincident(index + 1)) { 2235 intersections->removeOne(index + 1); 2236 --last; 2237 } else { 2238 intersections->setCoincident(index++); 2239 } 2240 intersections->setCoincident(index); 2241 } 2242 SkASSERT(intersections->used() <= TCurve::kMaxIntersections); 2243 } 2244