SkPathOpsCommon.cpp revision 08bc8488fa2ea2d2a17efb1443f0ec6579d5a3c8
1/* 2 * Copyright 2012 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#include "SkAddIntersections.h" 8#include "SkOpCoincidence.h" 9#include "SkOpEdgeBuilder.h" 10#include "SkPathOpsCommon.h" 11#include "SkPathWriter.h" 12#include "SkTSort.h" 13 14static int contourRangeCheckY(const SkTDArray<SkOpContour* >& contourList, 15 SkOpSegment** currentPtr, SkOpSpanBase** startPtr, SkOpSpanBase** endPtr, 16 double* bestHit, SkScalar* bestDx, bool* tryAgain, double* midPtr, bool opp) { 17 SkOpSpanBase* start = *startPtr; 18 SkOpSpanBase* end = *endPtr; 19 const double mid = *midPtr; 20 const SkOpSegment* current = *currentPtr; 21 double tAtMid = SkOpSegment::TAtMid(start, end, mid); 22 SkPoint basePt = current->ptAtT(tAtMid); 23 int contourCount = contourList.count(); 24 SkScalar bestY = SK_ScalarMin; 25 SkOpSegment* bestSeg = NULL; 26 SkOpSpan* bestTSpan = NULL; 27 bool bestOpp; 28 bool hitSomething = false; 29 for (int cTest = 0; cTest < contourCount; ++cTest) { 30 SkOpContour* contour = contourList[cTest]; 31 bool testOpp = contour->operand() ^ current->operand() ^ opp; 32 if (basePt.fY < contour->bounds().fTop) { 33 continue; 34 } 35 if (bestY > contour->bounds().fBottom) { 36 continue; 37 } 38 SkOpSegment* testSeg = contour->first(); 39 SkASSERT(testSeg); 40 do { 41 SkScalar testY = bestY; 42 double testHit; 43 bool vertical; 44 SkOpSpan* testTSpan = testSeg->crossedSpanY(basePt, tAtMid, testOpp, 45 testSeg == current, &testY, &testHit, &hitSomething, &vertical); 46 if (!testTSpan) { 47 if (vertical) { 48 hitSomething = true; 49 bestSeg = NULL; 50 goto abortContours; // vertical encountered, return and try different point 51 } 52 continue; 53 } 54 if (testSeg == current && SkOpSegment::BetweenTs(start, testHit, end)) { 55 double baseT = start->t(); 56 double endT = end->t(); 57 double newMid = (testHit - baseT) / (endT - baseT); 58#if DEBUG_WINDING 59 double midT = SkOpSegment::TAtMid(start, end, mid); 60 SkPoint midXY = current->ptAtT(midT); 61 double newMidT = SkOpSegment::TAtMid(start, end, newMid); 62 SkPoint newXY = current->ptAtT(newMidT); 63 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)" 64 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__, 65 current->debugID(), mid, newMid, 66 baseT, start->pt().fX, start->pt().fY, 67 baseT + mid * (endT - baseT), midXY.fX, midXY.fY, 68 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY, 69 endT, end->pt().fX, end->pt().fY); 70#endif 71 *midPtr = newMid * 2; // calling loop with divide by 2 before continuing 72 return SK_MinS32; 73 } 74 bestSeg = testSeg; 75 *bestHit = testHit; 76 bestOpp = testOpp; 77 bestTSpan = testTSpan; 78 bestY = testY; 79 } while ((testSeg = testSeg->next())); 80 } 81abortContours: 82 int result; 83 if (!bestSeg) { 84 result = hitSomething ? SK_MinS32 : 0; 85 } else { 86 if (bestTSpan->windSum() == SK_MinS32) { 87 *currentPtr = bestSeg; 88 *startPtr = bestTSpan; 89 *endPtr = bestTSpan->next(); 90 SkASSERT(*startPtr != *endPtr && *startPtr && *endPtr); 91 *tryAgain = true; 92 return 0; 93 } 94 result = bestSeg->windingAtT(*bestHit, bestTSpan, bestOpp, bestDx); 95 SkASSERT(result == SK_MinS32 || *bestDx); 96 } 97 double baseT = (*startPtr)->t(); 98 double endT = (*endPtr)->t(); 99 *bestHit = baseT + mid * (endT - baseT); 100 return result; 101} 102 103SkOpSegment* FindUndone(SkTDArray<SkOpContour* >& contourList, SkOpSpanBase** startPtr, 104 SkOpSpanBase** endPtr) { 105 int contourCount = contourList.count(); 106 SkOpSegment* result; 107 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 108 SkOpContour* contour = contourList[cIndex]; 109 result = contour->undoneSegment(startPtr, endPtr); 110 if (result) { 111 return result; 112 } 113 } 114 return NULL; 115} 116 117SkOpSegment* FindChase(SkTDArray<SkOpSpanBase*>* chase, SkOpSpanBase** startPtr, 118 SkOpSpanBase** endPtr) { 119 while (chase->count()) { 120 SkOpSpanBase* span; 121 chase->pop(&span); 122 SkOpSegment* segment = span->segment(); 123 *startPtr = span->ptT()->next()->span(); 124 bool sortable = true; 125 bool done = true; 126 *endPtr = NULL; 127 if (SkOpAngle* last = segment->activeAngle(*startPtr, startPtr, endPtr, &done, 128 &sortable)) { 129 if (last->unorderable()) { 130 continue; 131 } 132 *startPtr = last->start(); 133 *endPtr = last->end(); 134 #if TRY_ROTATE 135 *chase->insert(0) = span; 136 #else 137 *chase->append() = span; 138 #endif 139 return last->segment(); 140 } 141 if (done) { 142 continue; 143 } 144 if (!sortable) { 145 continue; 146 } 147 // find first angle, initialize winding to computed wind sum 148 const SkOpAngle* angle = segment->spanToAngle(*startPtr, *endPtr); 149 if (!angle) { 150 continue; 151 } 152 const SkOpAngle* firstAngle = angle; 153 bool loop = false; 154 int winding = SK_MinS32; 155 do { 156 angle = angle->next(); 157 if (angle == firstAngle && loop) { 158 break; // if we get here, there's no winding, loop is unorderable 159 } 160 loop |= angle == firstAngle; 161 segment = angle->segment(); 162 winding = segment->windSum(angle); 163 } while (winding == SK_MinS32); 164 if (winding == SK_MinS32) { 165 continue; 166 } 167 int sumWinding = segment->updateWindingReverse(angle); 168 SkOpSegment* first = NULL; 169 firstAngle = angle; 170 while ((angle = angle->next()) != firstAngle) { 171 segment = angle->segment(); 172 SkOpSpanBase* start = angle->start(); 173 SkOpSpanBase* end = angle->end(); 174 int maxWinding; 175 segment->setUpWinding(start, end, &maxWinding, &sumWinding); 176 if (!segment->done(angle)) { 177 if (!first) { 178 first = segment; 179 *startPtr = start; 180 *endPtr = end; 181 } 182 // OPTIMIZATION: should this also add to the chase? 183 (void) segment->markAngle(maxWinding, sumWinding, angle); 184 } 185 } 186 if (first) { 187 #if TRY_ROTATE 188 *chase->insert(0) = span; 189 #else 190 *chase->append() = span; 191 #endif 192 return first; 193 } 194 } 195 return NULL; 196} 197 198#if DEBUG_ACTIVE_SPANS 199void DebugShowActiveSpans(SkTDArray<SkOpContour* >& contourList) { 200 int index; 201 for (index = 0; index < contourList.count(); ++ index) { 202 contourList[index]->debugShowActiveSpans(); 203 } 204} 205#endif 206 207static SkOpSegment* findTopSegment(const SkTDArray<SkOpContour* >& contourList, 208 bool firstPass, SkOpSpanBase** start, SkOpSpanBase** end, SkPoint* topLeft, 209 bool* unsortable, bool* done, SkChunkAlloc* allocator) { 210 SkOpSegment* result; 211 const SkOpSegment* lastTopStart = NULL; 212 SkOpSpanBase* lastStart = NULL, * lastEnd = NULL; 213 do { 214 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax}; 215 int contourCount = contourList.count(); 216 SkOpSegment* topStart = NULL; 217 *done = true; 218 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 219 SkOpContour* contour = contourList[cIndex]; 220 if (contour->done()) { 221 continue; 222 } 223 const SkPathOpsBounds& bounds = contour->bounds(); 224 if (bounds.fBottom < topLeft->fY) { 225 *done = false; 226 continue; 227 } 228 if (bounds.fBottom == topLeft->fY && bounds.fRight < topLeft->fX) { 229 *done = false; 230 continue; 231 } 232 contour->topSortableSegment(*topLeft, &bestXY, &topStart); 233 if (!contour->done()) { 234 *done = false; 235 } 236 } 237 if (!topStart) { 238 return NULL; 239 } 240 *topLeft = bestXY; 241 result = topStart->findTop(firstPass, start, end, unsortable, allocator); 242 if (!result) { 243 if (lastTopStart == topStart && lastStart == *start && lastEnd == *end) { 244 *done = true; 245 return NULL; 246 } 247 lastTopStart = topStart; 248 lastStart = *start; 249 lastEnd = *end; 250 } 251 } while (!result); 252 return result; 253} 254 255static int rightAngleWinding(const SkTDArray<SkOpContour* >& contourList, 256 SkOpSegment** currentPtr, SkOpSpanBase** start, SkOpSpanBase** end, double* tHit, 257 SkScalar* hitDx, bool* tryAgain, bool* onlyVertical, bool opp) { 258 double test = 0.9; 259 int contourWinding; 260 do { 261 contourWinding = contourRangeCheckY(contourList, currentPtr, start, end, 262 tHit, hitDx, tryAgain, &test, opp); 263 if (contourWinding != SK_MinS32 || *tryAgain) { 264 return contourWinding; 265 } 266 if (*currentPtr && (*currentPtr)->isVertical()) { 267 *onlyVertical = true; 268 return contourWinding; 269 } 270 test /= 2; 271 } while (!approximately_negative(test)); 272 SkASSERT(0); // FIXME: incomplete functionality 273 return contourWinding; 274} 275 276static void skipVertical(const SkTDArray<SkOpContour* >& contourList, 277 SkOpSegment** current, SkOpSpanBase** start, SkOpSpanBase** end) { 278 if (!(*current)->isVertical(*start, *end)) { 279 return; 280 } 281 int contourCount = contourList.count(); 282 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 283 SkOpContour* contour = contourList[cIndex]; 284 if (contour->done()) { 285 continue; 286 } 287 SkOpSegment* nonVertical = contour->nonVerticalSegment(start, end); 288 if (nonVertical) { 289 *current = nonVertical; 290 return; 291 } 292 } 293 return; 294} 295 296struct SortableTop2 { // error if local in pre-C++11 297 SkOpSpanBase* fStart; 298 SkOpSpanBase* fEnd; 299}; 300 301SkOpSegment* FindSortableTop(const SkTDArray<SkOpContour* >& contourList, bool firstPass, 302 SkOpAngle::IncludeType angleIncludeType, bool* firstContour, SkOpSpanBase** startPtr, 303 SkOpSpanBase** endPtr, SkPoint* topLeft, bool* unsortable, bool* done, bool* onlyVertical, 304 SkChunkAlloc* allocator) { 305 SkOpSegment* current = findTopSegment(contourList, firstPass, startPtr, endPtr, topLeft, 306 unsortable, done, allocator); 307 if (!current) { 308 return NULL; 309 } 310 SkOpSpanBase* start = *startPtr; 311 SkOpSpanBase* end = *endPtr; 312 SkASSERT(current == start->segment()); 313 if (*firstContour) { 314 current->initWinding(start, end, angleIncludeType); 315 *firstContour = false; 316 return current; 317 } 318 SkOpSpan* minSpan = start->starter(end); 319 int sumWinding = minSpan->windSum(); 320 if (sumWinding == SK_MinS32) { 321 SkOpSpanBase* iSpan = end; 322 SkOpSpanBase* oSpan = start; 323 do { 324 bool checkFrom = oSpan->t() < iSpan->t(); 325 if ((checkFrom ? iSpan->fromAngle() : iSpan->upCast()->toAngle()) == NULL) { 326 if (!iSpan->addSimpleAngle(checkFrom, allocator)) { 327 *unsortable = true; 328 return NULL; 329 } 330 } 331 sumWinding = current->computeSum(oSpan, iSpan, angleIncludeType); 332 SkTSwap(iSpan, oSpan); 333 } while (sumWinding == SK_MinS32 && iSpan == start); 334 } 335 if (sumWinding != SK_MinS32 && sumWinding != SK_NaN32) { 336 return current; 337 } 338 int contourWinding; 339 int oppContourWinding = 0; 340 // the simple upward projection of the unresolved points hit unsortable angles 341 // shoot rays at right angles to the segment to find its winding, ignoring angle cases 342 bool tryAgain; 343 double tHit; 344 SkScalar hitDx = 0; 345 SkScalar hitOppDx = 0; 346 // keep track of subsequent returns to detect infinite loops 347 SkTDArray<SortableTop2> sortableTops; 348 do { 349 // if current is vertical, find another candidate which is not 350 // if only remaining candidates are vertical, then they can be marked done 351 SkASSERT(*startPtr != *endPtr && *startPtr && *endPtr); 352 SkASSERT(current == (*startPtr)->segment()); 353 skipVertical(contourList, ¤t, startPtr, endPtr); 354 SkASSERT(current); // FIXME: if null, all remaining are vertical 355 SkASSERT(*startPtr != *endPtr && *startPtr && *endPtr); 356 SkASSERT(current == (*startPtr)->segment()); 357 tryAgain = false; 358 contourWinding = rightAngleWinding(contourList, ¤t, startPtr, endPtr, &tHit, 359 &hitDx, &tryAgain, onlyVertical, false); 360 SkASSERT(current == (*startPtr)->segment()); 361 if (tryAgain) { 362 bool giveUp = false; 363 int count = sortableTops.count(); 364 for (int index = 0; index < count; ++index) { 365 const SortableTop2& prev = sortableTops[index]; 366 if (giveUp) { 367 prev.fStart->segment()->markDone(prev.fStart->starter(prev.fEnd)); 368 } else if (prev.fStart == *startPtr || prev.fEnd == *endPtr) { 369 // remaining edges are non-vertical and cannot have their winding computed 370 // mark them as done and return, and hope that assembly can fill the holes 371 giveUp = true; 372 index = -1; 373 } 374 } 375 if (giveUp) { 376 *done = true; 377 return NULL; 378 } 379 } 380 SortableTop2* sortableTop = sortableTops.append(); 381 sortableTop->fStart = *startPtr; 382 sortableTop->fEnd = *endPtr; 383#if DEBUG_SORT 384 SkDebugf("%s current=%d index=%d endIndex=%d tHit=%1.9g hitDx=%1.9g try=%d vert=%d\n", 385 __FUNCTION__, current->debugID(), (*startPtr)->debugID(), (*endPtr)->debugID(), 386 tHit, hitDx, tryAgain, *onlyVertical); 387#endif 388 if (*onlyVertical) { 389 return current; 390 } 391 if (tryAgain) { 392 continue; 393 } 394 if (angleIncludeType < SkOpAngle::kBinarySingle) { 395 break; 396 } 397 oppContourWinding = rightAngleWinding(contourList, ¤t, startPtr, endPtr, &tHit, 398 &hitOppDx, &tryAgain, NULL, true); 399 SkASSERT(current == (*startPtr)->segment()); 400 } while (tryAgain); 401 bool success = current->initWinding(*startPtr, *endPtr, tHit, contourWinding, hitDx, 402 oppContourWinding, hitOppDx); 403 if (current->done()) { 404 return NULL; 405 } else if (!success) { // check if the span has a valid winding 406 SkOpSpan* minSpan = (*startPtr)->t() < (*endPtr)->t() ? (*startPtr)->upCast() 407 : (*endPtr)->upCast(); 408 if (minSpan->windSum() == SK_MinS32) { 409 return NULL; 410 } 411 } 412 return current; 413} 414 415void MakeContourList(SkOpContour* contour, SkTDArray<SkOpContour* >& list, 416 bool evenOdd, bool oppEvenOdd) { 417 do { 418 if (contour->count()) { 419 contour->setOppXor(contour->operand() ? evenOdd : oppEvenOdd); 420 *list.append() = contour; 421 } 422 } while ((contour = contour->next())); 423 if (list.count() < 2) { 424 return; 425 } 426 SkTQSort<SkOpContour>(list.begin(), list.end() - 1); 427} 428 429class DistanceLessThan { 430public: 431 DistanceLessThan(double* distances) : fDistances(distances) { } 432 double* fDistances; 433 bool operator()(const int one, const int two) { 434 return fDistances[one] < fDistances[two]; 435 } 436}; 437 438 /* 439 check start and end of each contour 440 if not the same, record them 441 match them up 442 connect closest 443 reassemble contour pieces into new path 444 */ 445void Assemble(const SkPathWriter& path, SkPathWriter* simple) { 446 SkChunkAlloc allocator(4096); // FIXME: constant-ize, tune 447 SkOpContour contour; 448 SkOpGlobalState globalState(NULL SkDEBUGPARAMS(&contour)); 449#if DEBUG_SHOW_TEST_NAME 450 SkDebugf("</div>\n"); 451#endif 452#if DEBUG_PATH_CONSTRUCTION 453 SkDebugf("%s\n", __FUNCTION__); 454#endif 455 SkOpEdgeBuilder builder(path, &contour, &allocator, &globalState); 456 builder.finish(&allocator); 457 SkTDArray<const SkOpContour* > runs; // indices of partial contours 458 const SkOpContour* eContour = builder.head(); 459 do { 460 if (!eContour->count()) { 461 continue; 462 } 463 const SkPoint& eStart = eContour->start(); 464 const SkPoint& eEnd = eContour->end(); 465#if DEBUG_ASSEMBLE 466 SkDebugf("%s contour", __FUNCTION__); 467 if (!SkDPoint::ApproximatelyEqual(eStart, eEnd)) { 468 SkDebugf("[%d]", runs.count()); 469 } else { 470 SkDebugf(" "); 471 } 472 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n", 473 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY); 474#endif 475 if (SkDPoint::ApproximatelyEqual(eStart, eEnd)) { 476 eContour->toPath(simple); 477 continue; 478 } 479 *runs.append() = eContour; 480 } while ((eContour = eContour->next())); 481 int count = runs.count(); 482 if (count == 0) { 483 return; 484 } 485 SkTDArray<int> sLink, eLink; 486 sLink.append(count); 487 eLink.append(count); 488 int rIndex, iIndex; 489 for (rIndex = 0; rIndex < count; ++rIndex) { 490 sLink[rIndex] = eLink[rIndex] = SK_MaxS32; 491 } 492 const int ends = count * 2; // all starts and ends 493 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2 494 SkTDArray<double> distances; 495 distances.append(entries); 496 for (rIndex = 0; rIndex < ends - 1; ++rIndex) { 497 const SkOpContour* oContour = runs[rIndex >> 1]; 498 const SkPoint& oPt = rIndex & 1 ? oContour->end() : oContour->start(); 499 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2) 500 * ends - rIndex - 1; 501 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) { 502 const SkOpContour* iContour = runs[iIndex >> 1]; 503 const SkPoint& iPt = iIndex & 1 ? iContour->end() : iContour->start(); 504 double dx = iPt.fX - oPt.fX; 505 double dy = iPt.fY - oPt.fY; 506 double dist = dx * dx + dy * dy; 507 distances[row + iIndex] = dist; // oStart distance from iStart 508 } 509 } 510 SkTDArray<int> sortedDist; 511 sortedDist.append(entries); 512 for (rIndex = 0; rIndex < entries; ++rIndex) { 513 sortedDist[rIndex] = rIndex; 514 } 515 SkTQSort<int>(sortedDist.begin(), sortedDist.end() - 1, DistanceLessThan(distances.begin())); 516 int remaining = count; // number of start/end pairs 517 for (rIndex = 0; rIndex < entries; ++rIndex) { 518 int pair = sortedDist[rIndex]; 519 int row = pair / ends; 520 int col = pair - row * ends; 521 int thingOne = row < col ? row : ends - row - 2; 522 int ndxOne = thingOne >> 1; 523 bool endOne = thingOne & 1; 524 int* linkOne = endOne ? eLink.begin() : sLink.begin(); 525 if (linkOne[ndxOne] != SK_MaxS32) { 526 continue; 527 } 528 int thingTwo = row < col ? col : ends - row + col - 1; 529 int ndxTwo = thingTwo >> 1; 530 bool endTwo = thingTwo & 1; 531 int* linkTwo = endTwo ? eLink.begin() : sLink.begin(); 532 if (linkTwo[ndxTwo] != SK_MaxS32) { 533 continue; 534 } 535 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]); 536 bool flip = endOne == endTwo; 537 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo; 538 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne; 539 if (!--remaining) { 540 break; 541 } 542 } 543 SkASSERT(!remaining); 544#if DEBUG_ASSEMBLE 545 for (rIndex = 0; rIndex < count; ++rIndex) { 546 int s = sLink[rIndex]; 547 int e = eLink[rIndex]; 548 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e', 549 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e); 550 } 551#endif 552 rIndex = 0; 553 do { 554 bool forward = true; 555 bool first = true; 556 int sIndex = sLink[rIndex]; 557 SkASSERT(sIndex != SK_MaxS32); 558 sLink[rIndex] = SK_MaxS32; 559 int eIndex; 560 if (sIndex < 0) { 561 eIndex = sLink[~sIndex]; 562 sLink[~sIndex] = SK_MaxS32; 563 } else { 564 eIndex = eLink[sIndex]; 565 eLink[sIndex] = SK_MaxS32; 566 } 567 SkASSERT(eIndex != SK_MaxS32); 568#if DEBUG_ASSEMBLE 569 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e', 570 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e', 571 eIndex < 0 ? ~eIndex : eIndex); 572#endif 573 do { 574 const SkOpContour* contour = runs[rIndex]; 575 if (first) { 576 first = false; 577 const SkPoint* startPtr = &contour->start(); 578 simple->deferredMove(startPtr[0]); 579 } 580 if (forward) { 581 contour->toPartialForward(simple); 582 } else { 583 contour->toPartialBackward(simple); 584 } 585#if DEBUG_ASSEMBLE 586 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex, 587 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex, 588 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)); 589#endif 590 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) { 591 simple->close(); 592 break; 593 } 594 if (forward) { 595 eIndex = eLink[rIndex]; 596 SkASSERT(eIndex != SK_MaxS32); 597 eLink[rIndex] = SK_MaxS32; 598 if (eIndex >= 0) { 599 SkASSERT(sLink[eIndex] == rIndex); 600 sLink[eIndex] = SK_MaxS32; 601 } else { 602 SkASSERT(eLink[~eIndex] == ~rIndex); 603 eLink[~eIndex] = SK_MaxS32; 604 } 605 } else { 606 eIndex = sLink[rIndex]; 607 SkASSERT(eIndex != SK_MaxS32); 608 sLink[rIndex] = SK_MaxS32; 609 if (eIndex >= 0) { 610 SkASSERT(eLink[eIndex] == rIndex); 611 eLink[eIndex] = SK_MaxS32; 612 } else { 613 SkASSERT(sLink[~eIndex] == ~rIndex); 614 sLink[~eIndex] = SK_MaxS32; 615 } 616 } 617 rIndex = eIndex; 618 if (rIndex < 0) { 619 forward ^= 1; 620 rIndex = ~rIndex; 621 } 622 } while (true); 623 for (rIndex = 0; rIndex < count; ++rIndex) { 624 if (sLink[rIndex] != SK_MaxS32) { 625 break; 626 } 627 } 628 } while (rIndex < count); 629#if DEBUG_ASSEMBLE 630 for (rIndex = 0; rIndex < count; ++rIndex) { 631 SkASSERT(sLink[rIndex] == SK_MaxS32); 632 SkASSERT(eLink[rIndex] == SK_MaxS32); 633 } 634#endif 635} 636 637static void align(SkTDArray<SkOpContour* >* contourList) { 638 int contourCount = (*contourList).count(); 639 for (int cTest = 0; cTest < contourCount; ++cTest) { 640 SkOpContour* contour = (*contourList)[cTest]; 641 contour->align(); 642 } 643} 644 645static void calcAngles(SkTDArray<SkOpContour* >* contourList, SkChunkAlloc* allocator) { 646 int contourCount = (*contourList).count(); 647 for (int cTest = 0; cTest < contourCount; ++cTest) { 648 SkOpContour* contour = (*contourList)[cTest]; 649 contour->calcAngles(allocator); 650 } 651} 652 653static void missingCoincidence(SkTDArray<SkOpContour* >* contourList, 654 SkOpCoincidence* coincidence, SkChunkAlloc* allocator) { 655 int contourCount = (*contourList).count(); 656 for (int cTest = 0; cTest < contourCount; ++cTest) { 657 SkOpContour* contour = (*contourList)[cTest]; 658 contour->missingCoincidence(coincidence, allocator); 659 } 660} 661 662static void moveMultiples(SkTDArray<SkOpContour* >* contourList) { 663 int contourCount = (*contourList).count(); 664 for (int cTest = 0; cTest < contourCount; ++cTest) { 665 SkOpContour* contour = (*contourList)[cTest]; 666 contour->moveMultiples(); 667 } 668} 669 670static void moveNearby(SkTDArray<SkOpContour* >* contourList) { 671 int contourCount = (*contourList).count(); 672 for (int cTest = 0; cTest < contourCount; ++cTest) { 673 SkOpContour* contour = (*contourList)[cTest]; 674 contour->moveNearby(); 675 } 676} 677 678static void sortAngles(SkTDArray<SkOpContour* >* contourList) { 679 int contourCount = (*contourList).count(); 680 for (int cTest = 0; cTest < contourCount; ++cTest) { 681 SkOpContour* contour = (*contourList)[cTest]; 682 contour->sortAngles(); 683 } 684} 685 686static void sortSegments(SkTDArray<SkOpContour* >* contourList) { 687 int contourCount = (*contourList).count(); 688 for (int cTest = 0; cTest < contourCount; ++cTest) { 689 SkOpContour* contour = (*contourList)[cTest]; 690 contour->sortSegments(); 691 } 692} 693 694bool HandleCoincidence(SkTDArray<SkOpContour* >* contourList, SkOpCoincidence* coincidence, 695 SkChunkAlloc* allocator, SkOpGlobalState* globalState) { 696 // combine t values when multiple intersections occur on some segments but not others 697 moveMultiples(contourList); 698 // move t values and points together to eliminate small/tiny gaps 699 moveNearby(contourList); 700 align(contourList); // give all span members common values 701#if DEBUG_VALIDATE 702 globalState->setPhase(SkOpGlobalState::kIntersecting); 703#endif 704 coincidence->addMissing(allocator); 705#if DEBUG_VALIDATE 706 globalState->setPhase(SkOpGlobalState::kWalking); 707#endif 708 coincidence->expand(); // check to see if, loosely, coincident ranges may be expanded 709 coincidence->mark(); // mark spans of coincident segments as coincident 710 missingCoincidence(contourList, coincidence, allocator); // look for coincidence missed earlier 711 if (!coincidence->apply()) { // adjust the winding value to account for coincident edges 712 return false; 713 } 714 sortSegments(contourList); 715 calcAngles(contourList, allocator); 716 sortAngles(contourList); 717 if (globalState->angleCoincidence()) { 718 missingCoincidence(contourList, coincidence, allocator); 719 if (!coincidence->apply()) { 720 return false; 721 } 722 } 723#if DEBUG_ACTIVE_SPANS 724 DebugShowActiveSpans(*contourList); 725#endif 726 return true; 727} 728