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 #include "SkOpCoincidence.h" 8 #include "SkOpContour.h" 9 #include "SkOpSegment.h" 10 #include "SkPathWriter.h" 11 12 bool SkOpPtT::alias() const { 13 return this->span()->ptT() != this; 14 } 15 16 const SkOpPtT* SkOpPtT::active() const { 17 if (!fDeleted) { 18 return this; 19 } 20 const SkOpPtT* ptT = this; 21 const SkOpPtT* stopPtT = ptT; 22 while ((ptT = ptT->next()) != stopPtT) { 23 if (ptT->fSpan == fSpan && !ptT->fDeleted) { 24 return ptT; 25 } 26 } 27 return nullptr; // should never return deleted; caller must abort 28 } 29 30 bool SkOpPtT::contains(const SkOpPtT* check) const { 31 SkOPASSERT(this != check); 32 const SkOpPtT* ptT = this; 33 const SkOpPtT* stopPtT = ptT; 34 while ((ptT = ptT->next()) != stopPtT) { 35 if (ptT == check) { 36 return true; 37 } 38 } 39 return false; 40 } 41 42 bool SkOpPtT::contains(const SkOpSegment* segment, const SkPoint& pt) const { 43 SkASSERT(this->segment() != segment); 44 const SkOpPtT* ptT = this; 45 const SkOpPtT* stopPtT = ptT; 46 while ((ptT = ptT->next()) != stopPtT) { 47 if (ptT->fPt == pt && ptT->segment() == segment) { 48 return true; 49 } 50 } 51 return false; 52 } 53 54 bool SkOpPtT::contains(const SkOpSegment* segment, double t) const { 55 const SkOpPtT* ptT = this; 56 const SkOpPtT* stopPtT = ptT; 57 while ((ptT = ptT->next()) != stopPtT) { 58 if (ptT->fT == t && ptT->segment() == segment) { 59 return true; 60 } 61 } 62 return false; 63 } 64 65 const SkOpPtT* SkOpPtT::contains(const SkOpSegment* check) const { 66 SkASSERT(this->segment() != check); 67 const SkOpPtT* ptT = this; 68 const SkOpPtT* stopPtT = ptT; 69 while ((ptT = ptT->next()) != stopPtT) { 70 if (ptT->segment() == check && !ptT->deleted()) { 71 return ptT; 72 } 73 } 74 return nullptr; 75 } 76 77 SkOpContour* SkOpPtT::contour() const { 78 return segment()->contour(); 79 } 80 81 const SkOpPtT* SkOpPtT::find(const SkOpSegment* segment) const { 82 const SkOpPtT* ptT = this; 83 const SkOpPtT* stopPtT = ptT; 84 do { 85 if (ptT->segment() == segment && !ptT->deleted()) { 86 return ptT; 87 } 88 ptT = ptT->fNext; 89 } while (stopPtT != ptT); 90 // SkASSERT(0); 91 return nullptr; 92 } 93 94 SkOpGlobalState* SkOpPtT::globalState() const { 95 return contour()->globalState(); 96 } 97 98 void SkOpPtT::init(SkOpSpanBase* span, double t, const SkPoint& pt, bool duplicate) { 99 fT = t; 100 fPt = pt; 101 fSpan = span; 102 fNext = this; 103 fDuplicatePt = duplicate; 104 fDeleted = false; 105 fCoincident = false; 106 SkDEBUGCODE(fID = span->globalState()->nextPtTID()); 107 } 108 109 bool SkOpPtT::onEnd() const { 110 const SkOpSpanBase* span = this->span(); 111 if (span->ptT() != this) { 112 return false; 113 } 114 const SkOpSegment* segment = this->segment(); 115 return span == segment->head() || span == segment->tail(); 116 } 117 118 bool SkOpPtT::ptAlreadySeen(const SkOpPtT* check) const { 119 while (this != check) { 120 if (this->fPt == check->fPt) { 121 return true; 122 } 123 check = check->fNext; 124 } 125 return false; 126 } 127 128 SkOpPtT* SkOpPtT::prev() { 129 SkOpPtT* result = this; 130 SkOpPtT* next = this; 131 while ((next = next->fNext) != this) { 132 result = next; 133 } 134 SkASSERT(result->fNext == this); 135 return result; 136 } 137 138 const SkOpSegment* SkOpPtT::segment() const { 139 return span()->segment(); 140 } 141 142 SkOpSegment* SkOpPtT::segment() { 143 return span()->segment(); 144 } 145 146 void SkOpPtT::setDeleted() { 147 SkASSERT(this->span()->debugDeleted() || this->span()->ptT() != this); 148 SkOPASSERT(!fDeleted); 149 fDeleted = true; 150 } 151 152 bool SkOpSpanBase::addOpp(SkOpSpanBase* opp) { 153 SkOpPtT* oppPrev = this->ptT()->oppPrev(opp->ptT()); 154 if (!oppPrev) { 155 return true; 156 } 157 FAIL_IF(!this->mergeMatches(opp)); 158 this->ptT()->addOpp(opp->ptT(), oppPrev); 159 this->checkForCollapsedCoincidence(); 160 return true; 161 } 162 163 SkOpSpanBase::Collapsed SkOpSpanBase::collapsed(double s, double e) const { 164 const SkOpPtT* start = &fPtT; 165 const SkOpPtT* startNext = nullptr; 166 const SkOpPtT* walk = start; 167 double min = walk->fT; 168 double max = min; 169 const SkOpSegment* segment = this->segment(); 170 int safetyNet = 100000; 171 while ((walk = walk->next()) != start) { 172 if (!--safetyNet) { 173 return Collapsed::kError; 174 } 175 if (walk == startNext) { 176 return Collapsed::kError; 177 } 178 if (walk->segment() != segment) { 179 continue; 180 } 181 min = SkTMin(min, walk->fT); 182 max = SkTMax(max, walk->fT); 183 if (between(min, s, max) && between(min, e, max)) { 184 return Collapsed::kYes; 185 } 186 startNext = start->next(); 187 } 188 return Collapsed::kNo; 189 } 190 191 bool SkOpSpanBase::contains(const SkOpSpanBase* span) const { 192 const SkOpPtT* start = &fPtT; 193 const SkOpPtT* check = &span->fPtT; 194 SkOPASSERT(start != check); 195 const SkOpPtT* walk = start; 196 while ((walk = walk->next()) != start) { 197 if (walk == check) { 198 return true; 199 } 200 } 201 return false; 202 } 203 204 const SkOpPtT* SkOpSpanBase::contains(const SkOpSegment* segment) const { 205 const SkOpPtT* start = &fPtT; 206 const SkOpPtT* walk = start; 207 while ((walk = walk->next()) != start) { 208 if (walk->deleted()) { 209 continue; 210 } 211 if (walk->segment() == segment && walk->span()->ptT() == walk) { 212 return walk; 213 } 214 } 215 return nullptr; 216 } 217 218 bool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const { 219 SkASSERT(this->segment() != segment); 220 const SkOpSpanBase* next = this; 221 while ((next = next->fCoinEnd) != this) { 222 if (next->segment() == segment) { 223 return true; 224 } 225 } 226 return false; 227 } 228 229 SkOpContour* SkOpSpanBase::contour() const { 230 return segment()->contour(); 231 } 232 233 SkOpGlobalState* SkOpSpanBase::globalState() const { 234 return contour()->globalState(); 235 } 236 237 void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) { 238 fSegment = segment; 239 fPtT.init(this, t, pt, false); 240 fCoinEnd = this; 241 fFromAngle = nullptr; 242 fPrev = prev; 243 fSpanAdds = 0; 244 fAligned = true; 245 fChased = false; 246 SkDEBUGCODE(fCount = 1); 247 SkDEBUGCODE(fID = globalState()->nextSpanID()); 248 SkDEBUGCODE(fDebugDeleted = false); 249 } 250 251 // this pair of spans share a common t value or point; merge them and eliminate duplicates 252 // this does not compute the best t or pt value; this merely moves all data into a single list 253 void SkOpSpanBase::merge(SkOpSpan* span) { 254 SkOpPtT* spanPtT = span->ptT(); 255 SkASSERT(this->t() != spanPtT->fT); 256 SkASSERT(!zero_or_one(spanPtT->fT)); 257 span->release(this->ptT()); 258 if (this->contains(span)) { 259 SkOPASSERT(0); // check to see if this ever happens -- should have been found earlier 260 return; // merge is already in the ptT loop 261 } 262 SkOpPtT* remainder = spanPtT->next(); 263 this->ptT()->insert(spanPtT); 264 while (remainder != spanPtT) { 265 SkOpPtT* next = remainder->next(); 266 SkOpPtT* compare = spanPtT->next(); 267 while (compare != spanPtT) { 268 SkOpPtT* nextC = compare->next(); 269 if (nextC->span() == remainder->span() && nextC->fT == remainder->fT) { 270 goto tryNextRemainder; 271 } 272 compare = nextC; 273 } 274 spanPtT->insert(remainder); 275 tryNextRemainder: 276 remainder = next; 277 } 278 fSpanAdds += span->fSpanAdds; 279 } 280 281 // please keep in sync with debugCheckForCollapsedCoincidence() 282 void SkOpSpanBase::checkForCollapsedCoincidence() { 283 SkOpCoincidence* coins = this->globalState()->coincidence(); 284 if (coins->isEmpty()) { 285 return; 286 } 287 // the insert above may have put both ends of a coincident run in the same span 288 // for each coincident ptT in loop; see if its opposite in is also in the loop 289 // this implementation is the motivation for marking that a ptT is referenced by a coincident span 290 SkOpPtT* head = this->ptT(); 291 SkOpPtT* test = head; 292 do { 293 if (!test->coincident()) { 294 continue; 295 } 296 coins->markCollapsed(test); 297 } while ((test = test->next()) != head); 298 coins->releaseDeleted(); 299 } 300 301 // please keep in sync with debugMergeMatches() 302 // Look to see if pt-t linked list contains same segment more than once 303 // if so, and if each pt-t is directly pointed to by spans in that segment, 304 // merge them 305 // keep the points, but remove spans so that the segment doesn't have 2 or more 306 // spans pointing to the same pt-t loop at different loop elements 307 bool SkOpSpanBase::mergeMatches(SkOpSpanBase* opp) { 308 SkOpPtT* test = &fPtT; 309 SkOpPtT* testNext; 310 const SkOpPtT* stop = test; 311 int safetyHatch = 1000000; 312 do { 313 if (!--safetyHatch) { 314 return false; 315 } 316 testNext = test->next(); 317 if (test->deleted()) { 318 continue; 319 } 320 SkOpSpanBase* testBase = test->span(); 321 SkASSERT(testBase->ptT() == test); 322 SkOpSegment* segment = test->segment(); 323 if (segment->done()) { 324 continue; 325 } 326 SkOpPtT* inner = opp->ptT(); 327 const SkOpPtT* innerStop = inner; 328 do { 329 if (inner->segment() != segment) { 330 continue; 331 } 332 if (inner->deleted()) { 333 continue; 334 } 335 SkOpSpanBase* innerBase = inner->span(); 336 SkASSERT(innerBase->ptT() == inner); 337 // when the intersection is first detected, the span base is marked if there are 338 // more than one point in the intersection. 339 if (!zero_or_one(inner->fT)) { 340 innerBase->upCast()->release(test); 341 } else { 342 SkOPASSERT(inner->fT != test->fT); 343 if (!zero_or_one(test->fT)) { 344 testBase->upCast()->release(inner); 345 } else { 346 segment->markAllDone(); // mark segment as collapsed 347 SkDEBUGCODE(testBase->debugSetDeleted()); 348 test->setDeleted(); 349 SkDEBUGCODE(innerBase->debugSetDeleted()); 350 inner->setDeleted(); 351 } 352 } 353 #ifdef SK_DEBUG // assert if another undeleted entry points to segment 354 const SkOpPtT* debugInner = inner; 355 while ((debugInner = debugInner->next()) != innerStop) { 356 if (debugInner->segment() != segment) { 357 continue; 358 } 359 if (debugInner->deleted()) { 360 continue; 361 } 362 SkOPASSERT(0); 363 } 364 #endif 365 break; 366 } while ((inner = inner->next()) != innerStop); 367 } while ((test = testNext) != stop); 368 this->checkForCollapsedCoincidence(); 369 return true; 370 } 371 372 int SkOpSpan::computeWindSum() { 373 SkOpGlobalState* globals = this->globalState(); 374 SkOpContour* contourHead = globals->contourHead(); 375 int windTry = 0; 376 while (!this->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxWindingTries) { 377 } 378 return this->windSum(); 379 } 380 381 bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const { 382 SkASSERT(this->segment() != segment); 383 const SkOpSpan* next = fCoincident; 384 do { 385 if (next->segment() == segment) { 386 return true; 387 } 388 } while ((next = next->fCoincident) != this); 389 return false; 390 } 391 392 void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) { 393 SkASSERT(t != 1); 394 initBase(segment, prev, t, pt); 395 fCoincident = this; 396 fToAngle = nullptr; 397 fWindSum = fOppSum = SK_MinS32; 398 fWindValue = 1; 399 fOppValue = 0; 400 fTopTTry = 0; 401 fChased = fDone = false; 402 segment->bumpCount(); 403 fAlreadyAdded = false; 404 } 405 406 // Please keep this in sync with debugInsertCoincidence() 407 bool SkOpSpan::insertCoincidence(const SkOpSegment* segment, bool flipped, bool ordered) { 408 if (this->containsCoincidence(segment)) { 409 return true; 410 } 411 SkOpPtT* next = &fPtT; 412 while ((next = next->next()) != &fPtT) { 413 if (next->segment() == segment) { 414 SkOpSpan* span; 415 SkOpSpanBase* base = next->span(); 416 if (!ordered) { 417 const SkOpPtT* spanEndPtT = fNext->contains(segment); 418 FAIL_IF(!spanEndPtT); 419 const SkOpSpanBase* spanEnd = spanEndPtT->span(); 420 const SkOpPtT* start = base->ptT()->starter(spanEnd->ptT()); 421 FAIL_IF(!start->span()->upCastable()); 422 span = const_cast<SkOpSpan*>(start->span()->upCast()); 423 } else if (flipped) { 424 span = base->prev(); 425 FAIL_IF(!span); 426 } else { 427 FAIL_IF(!base->upCastable()); 428 span = base->upCast(); 429 } 430 this->insertCoincidence(span); 431 return true; 432 } 433 } 434 #if DEBUG_COINCIDENCE 435 SkASSERT(0); // FIXME? if we get here, the span is missing its opposite segment... 436 #endif 437 return true; 438 } 439 440 void SkOpSpan::release(const SkOpPtT* kept) { 441 SkDEBUGCODE(fDebugDeleted = true); 442 SkOPASSERT(kept->span() != this); 443 SkASSERT(!final()); 444 SkOpSpan* prev = this->prev(); 445 SkASSERT(prev); 446 SkOpSpanBase* next = this->next(); 447 SkASSERT(next); 448 prev->setNext(next); 449 next->setPrev(prev); 450 this->segment()->release(this); 451 SkOpCoincidence* coincidence = this->globalState()->coincidence(); 452 if (coincidence) { 453 coincidence->fixUp(this->ptT(), kept); 454 } 455 this->ptT()->setDeleted(); 456 SkOpPtT* stopPtT = this->ptT(); 457 SkOpPtT* testPtT = stopPtT; 458 const SkOpSpanBase* keptSpan = kept->span(); 459 do { 460 if (this == testPtT->span()) { 461 testPtT->setSpan(keptSpan); 462 } 463 } while ((testPtT = testPtT->next()) != stopPtT); 464 } 465 466 void SkOpSpan::setOppSum(int oppSum) { 467 SkASSERT(!final()); 468 if (fOppSum != SK_MinS32 && fOppSum != oppSum) { 469 this->globalState()->setWindingFailed(); 470 return; 471 } 472 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(oppSum) <= DEBUG_LIMIT_WIND_SUM); 473 fOppSum = oppSum; 474 } 475 476 void SkOpSpan::setWindSum(int windSum) { 477 SkASSERT(!final()); 478 if (fWindSum != SK_MinS32 && fWindSum != windSum) { 479 this->globalState()->setWindingFailed(); 480 return; 481 } 482 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(windSum) <= DEBUG_LIMIT_WIND_SUM); 483 fWindSum = windSum; 484 } 485