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