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 #ifndef SkOpSpan_DEFINED 8 #define SkOpSpan_DEFINED 9 10 #include "SkPathOpsDebug.h" 11 #include "SkPathOpsTypes.h" 12 #include "SkPoint.h" 13 14 class SkArenaAlloc; 15 class SkOpAngle; 16 class SkOpContour; 17 class SkOpGlobalState; 18 class SkOpSegment; 19 class SkOpSpanBase; 20 class SkOpSpan; 21 struct SkPathOpsBounds; 22 23 // subset of op span used by terminal span (when t is equal to one) 24 class SkOpPtT { 25 public: 26 enum { 27 kIsAlias = 1, 28 kIsDuplicate = 1 29 }; 30 31 const SkOpPtT* active() const; 32 33 // please keep in sync with debugAddOpp() addOpp(SkOpPtT * opp,SkOpPtT * oppPrev)34 void addOpp(SkOpPtT* opp, SkOpPtT* oppPrev) { 35 SkOpPtT* oldNext = this->fNext; 36 SkASSERT(this != opp); 37 this->fNext = opp; 38 SkASSERT(oppPrev != oldNext); 39 oppPrev->fNext = oldNext; 40 } 41 42 bool alias() const; coincident()43 bool coincident() const { return fCoincident; } 44 bool contains(const SkOpPtT* ) const; 45 bool contains(const SkOpSegment*, const SkPoint& ) const; 46 bool contains(const SkOpSegment*, double t) const; 47 const SkOpPtT* contains(const SkOpSegment* ) const; 48 SkOpContour* contour() const; 49 debugID()50 int debugID() const { 51 return SkDEBUGRELEASE(fID, -1); 52 } 53 54 void debugAddOpp(const SkOpPtT* opp, const SkOpPtT* oppPrev) const; 55 const SkOpAngle* debugAngle(int id) const; 56 const SkOpCoincidence* debugCoincidence() const; 57 bool debugContains(const SkOpPtT* ) const; 58 const SkOpPtT* debugContains(const SkOpSegment* check) const; 59 SkOpContour* debugContour(int id) const; 60 const SkOpPtT* debugEnder(const SkOpPtT* end) const; 61 int debugLoopLimit(bool report) const; 62 bool debugMatchID(int id) const; 63 const SkOpPtT* debugOppPrev(const SkOpPtT* opp) const; 64 const SkOpPtT* debugPtT(int id) const; 65 void debugResetCoinT() const; 66 const SkOpSegment* debugSegment(int id) const; 67 void debugSetCoinT(int ) const; 68 const SkOpSpanBase* debugSpan(int id) const; 69 void debugValidate() const; 70 deleted()71 bool deleted() const { 72 return fDeleted; 73 } 74 duplicate()75 bool duplicate() const { 76 return fDuplicatePt; 77 } 78 79 void dump() const; // available to testing only 80 void dumpAll() const; 81 void dumpBase() const; 82 83 const SkOpPtT* find(const SkOpSegment* ) const; 84 SkOpGlobalState* globalState() const; 85 void init(SkOpSpanBase* , double t, const SkPoint& , bool dup); 86 insert(SkOpPtT * span)87 void insert(SkOpPtT* span) { 88 SkASSERT(span != this); 89 span->fNext = fNext; 90 fNext = span; 91 } 92 next()93 const SkOpPtT* next() const { 94 return fNext; 95 } 96 next()97 SkOpPtT* next() { 98 return fNext; 99 } 100 101 bool onEnd() const; 102 103 // returns nullptr if this is already in the opp ptT loop oppPrev(const SkOpPtT * opp)104 SkOpPtT* oppPrev(const SkOpPtT* opp) const { 105 // find the fOpp ptr to opp 106 SkOpPtT* oppPrev = opp->fNext; 107 if (oppPrev == this) { 108 return nullptr; 109 } 110 while (oppPrev->fNext != opp) { 111 oppPrev = oppPrev->fNext; 112 if (oppPrev == this) { 113 return nullptr; 114 } 115 } 116 return oppPrev; 117 } 118 Overlaps(const SkOpPtT * s1,const SkOpPtT * e1,const SkOpPtT * s2,const SkOpPtT * e2,const SkOpPtT ** sOut,const SkOpPtT ** eOut)119 static bool Overlaps(const SkOpPtT* s1, const SkOpPtT* e1, const SkOpPtT* s2, 120 const SkOpPtT* e2, const SkOpPtT** sOut, const SkOpPtT** eOut) { 121 const SkOpPtT* start1 = s1->fT < e1->fT ? s1 : e1; 122 const SkOpPtT* start2 = s2->fT < e2->fT ? s2 : e2; 123 *sOut = between(s1->fT, start2->fT, e1->fT) ? start2 124 : between(s2->fT, start1->fT, e2->fT) ? start1 : nullptr; 125 const SkOpPtT* end1 = s1->fT < e1->fT ? e1 : s1; 126 const SkOpPtT* end2 = s2->fT < e2->fT ? e2 : s2; 127 *eOut = between(s1->fT, end2->fT, e1->fT) ? end2 128 : between(s2->fT, end1->fT, e2->fT) ? end1 : nullptr; 129 if (*sOut == *eOut) { 130 SkASSERT(start1->fT >= end2->fT || start2->fT >= end1->fT); 131 return false; 132 } 133 SkASSERT(!*sOut || *sOut != *eOut); 134 return *sOut && *eOut; 135 } 136 137 bool ptAlreadySeen(const SkOpPtT* head) const; 138 SkOpPtT* prev(); 139 140 const SkOpSegment* segment() const; 141 SkOpSegment* segment(); 142 setCoincident()143 void setCoincident() const { 144 SkOPASSERT(!fDeleted); 145 fCoincident = true; 146 } 147 148 void setDeleted(); 149 setSpan(const SkOpSpanBase * span)150 void setSpan(const SkOpSpanBase* span) { 151 fSpan = const_cast<SkOpSpanBase*>(span); 152 } 153 span()154 const SkOpSpanBase* span() const { 155 return fSpan; 156 } 157 span()158 SkOpSpanBase* span() { 159 return fSpan; 160 } 161 starter(const SkOpPtT * end)162 const SkOpPtT* starter(const SkOpPtT* end) const { 163 return fT < end->fT ? this : end; 164 } 165 166 double fT; 167 SkPoint fPt; // cache of point value at this t 168 protected: 169 SkOpSpanBase* fSpan; // contains winding data 170 SkOpPtT* fNext; // intersection on opposite curve or alias on this curve 171 bool fDeleted; // set if removed from span list 172 bool fDuplicatePt; // set if identical pt is somewhere in the next loop 173 // below mutable since referrer is otherwise always const 174 mutable bool fCoincident; // set if at some point a coincident span pointed here 175 SkDEBUGCODE(int fID); 176 }; 177 178 class SkOpSpanBase { 179 public: 180 SkOpSpanBase* active(); 181 void addOpp(SkOpSpanBase* opp); 182 bumpSpanAdds()183 void bumpSpanAdds() { 184 ++fSpanAdds; 185 } 186 chased()187 bool chased() const { 188 return fChased; 189 } 190 191 void checkForCollapsedCoincidence(); 192 coinEnd()193 const SkOpSpanBase* coinEnd() const { 194 return fCoinEnd; 195 } 196 197 bool collapsed(double s, double e) const; 198 bool contains(const SkOpSpanBase* ) const; 199 const SkOpPtT* contains(const SkOpSegment* ) const; 200 containsCoinEnd(const SkOpSpanBase * coin)201 bool containsCoinEnd(const SkOpSpanBase* coin) const { 202 SkASSERT(this != coin); 203 const SkOpSpanBase* next = this; 204 while ((next = next->fCoinEnd) != this) { 205 if (next == coin) { 206 return true; 207 } 208 } 209 return false; 210 } 211 212 bool containsCoinEnd(const SkOpSegment* ) const; 213 SkOpContour* contour() const; 214 debugBumpCount()215 int debugBumpCount() { 216 return SkDEBUGRELEASE(++fCount, -1); 217 } 218 debugID()219 int debugID() const { 220 return SkDEBUGRELEASE(fID, -1); 221 } 222 223 #if DEBUG_COIN 224 void debugAddOpp(SkPathOpsDebug::GlitchLog* , const SkOpSpanBase* opp) const; 225 #endif 226 bool debugAlignedEnd(double t, const SkPoint& pt) const; 227 bool debugAlignedInner() const; 228 const SkOpAngle* debugAngle(int id) const; 229 #if DEBUG_COIN 230 void debugCheckForCollapsedCoincidence(SkPathOpsDebug::GlitchLog* ) const; 231 #endif 232 const SkOpCoincidence* debugCoincidence() const; 233 bool debugCoinEndLoopCheck() const; 234 SkOpContour* debugContour(int id) const; 235 #ifdef SK_DEBUG debugDeleted()236 bool debugDeleted() const { return fDebugDeleted; } 237 #endif 238 #if DEBUG_COIN 239 void debugInsertCoinEnd(SkPathOpsDebug::GlitchLog* , 240 const SkOpSpanBase* ) const; 241 void debugMergeMatches(SkPathOpsDebug::GlitchLog* log, 242 const SkOpSpanBase* opp) const; 243 #endif 244 const SkOpPtT* debugPtT(int id) const; 245 void debugResetCoinT() const; 246 const SkOpSegment* debugSegment(int id) const; 247 void debugSetCoinT(int ) const; 248 #ifdef SK_DEBUG debugSetDeleted()249 void debugSetDeleted() { fDebugDeleted = true; } 250 #endif 251 const SkOpSpanBase* debugSpan(int id) const; 252 const SkOpSpan* debugStarter(SkOpSpanBase const** endPtr) const; 253 SkOpGlobalState* globalState() const; 254 void debugValidate() const; 255 deleted()256 bool deleted() const { 257 return fPtT.deleted(); 258 } 259 260 void dump() const; // available to testing only 261 void dumpCoin() const; 262 void dumpAll() const; 263 void dumpBase() const; 264 void dumpHead() const; 265 final()266 bool final() const { 267 return fPtT.fT == 1; 268 } 269 fromAngle()270 SkOpAngle* fromAngle() const { 271 return fFromAngle; 272 } 273 274 void initBase(SkOpSegment* parent, SkOpSpan* prev, double t, const SkPoint& pt); 275 276 // Please keep this in sync with debugInsertCoinEnd() insertCoinEnd(SkOpSpanBase * coin)277 void insertCoinEnd(SkOpSpanBase* coin) { 278 if (containsCoinEnd(coin)) { 279 SkASSERT(coin->containsCoinEnd(this)); 280 return; 281 } 282 debugValidate(); 283 SkASSERT(this != coin); 284 SkOpSpanBase* coinNext = coin->fCoinEnd; 285 coin->fCoinEnd = this->fCoinEnd; 286 this->fCoinEnd = coinNext; 287 debugValidate(); 288 } 289 290 void merge(SkOpSpan* span); 291 void mergeMatches(SkOpSpanBase* opp); 292 prev()293 const SkOpSpan* prev() const { 294 return fPrev; 295 } 296 prev()297 SkOpSpan* prev() { 298 return fPrev; 299 } 300 pt()301 const SkPoint& pt() const { 302 return fPtT.fPt; 303 } 304 ptT()305 const SkOpPtT* ptT() const { 306 return &fPtT; 307 } 308 ptT()309 SkOpPtT* ptT() { 310 return &fPtT; 311 } 312 segment()313 SkOpSegment* segment() const { 314 return fSegment; 315 } 316 setAligned()317 void setAligned() { 318 fAligned = true; 319 } 320 setChased(bool chased)321 void setChased(bool chased) { 322 fChased = chased; 323 } 324 setFromAngle(SkOpAngle * angle)325 void setFromAngle(SkOpAngle* angle) { 326 fFromAngle = angle; 327 } 328 setPrev(SkOpSpan * prev)329 void setPrev(SkOpSpan* prev) { 330 fPrev = prev; 331 } 332 simple()333 bool simple() const { 334 fPtT.debugValidate(); 335 return fPtT.next()->next() == &fPtT; 336 } 337 spanAddsCount()338 int spanAddsCount() const { 339 return fSpanAdds; 340 } 341 starter(const SkOpSpanBase * end)342 const SkOpSpan* starter(const SkOpSpanBase* end) const { 343 const SkOpSpanBase* result = t() < end->t() ? this : end; 344 return result->upCast(); 345 } 346 starter(SkOpSpanBase * end)347 SkOpSpan* starter(SkOpSpanBase* end) { 348 SkASSERT(this->segment() == end->segment()); 349 SkOpSpanBase* result = t() < end->t() ? this : end; 350 return result->upCast(); 351 } 352 starter(SkOpSpanBase ** endPtr)353 SkOpSpan* starter(SkOpSpanBase** endPtr) { 354 SkOpSpanBase* end = *endPtr; 355 SkASSERT(this->segment() == end->segment()); 356 SkOpSpanBase* result; 357 if (t() < end->t()) { 358 result = this; 359 } else { 360 result = end; 361 *endPtr = this; 362 } 363 return result->upCast(); 364 } 365 step(const SkOpSpanBase * end)366 int step(const SkOpSpanBase* end) const { 367 return t() < end->t() ? 1 : -1; 368 } 369 t()370 double t() const { 371 return fPtT.fT; 372 } 373 unaligned()374 void unaligned() { 375 fAligned = false; 376 } 377 upCast()378 SkOpSpan* upCast() { 379 SkASSERT(!final()); 380 return (SkOpSpan*) this; 381 } 382 upCast()383 const SkOpSpan* upCast() const { 384 SkOPASSERT(!final()); 385 return (const SkOpSpan*) this; 386 } 387 upCastable()388 SkOpSpan* upCastable() { 389 return final() ? nullptr : upCast(); 390 } 391 upCastable()392 const SkOpSpan* upCastable() const { 393 return final() ? nullptr : upCast(); 394 } 395 396 private: 397 void alignInner(); 398 399 protected: // no direct access to internals to avoid treating a span base as a span 400 SkOpPtT fPtT; // list of points and t values associated with the start of this span 401 SkOpSegment* fSegment; // segment that contains this span 402 SkOpSpanBase* fCoinEnd; // linked list of coincident spans that end here (may point to itself) 403 SkOpAngle* fFromAngle; // points to next angle from span start to end 404 SkOpSpan* fPrev; // previous intersection point 405 int fSpanAdds; // number of times intersections have been added to span 406 bool fAligned; 407 bool fChased; // set after span has been added to chase array 408 SkDEBUGCODE(int fCount); // number of pt/t pairs added 409 SkDEBUGCODE(int fID); 410 SkDEBUGCODE(bool fDebugDeleted); // set when span was merged with another span 411 }; 412 413 class SkOpSpan : public SkOpSpanBase { 414 public: alreadyAdded()415 bool alreadyAdded() const { 416 if (fAlreadyAdded) { 417 return true; 418 } 419 fAlreadyAdded = true; 420 return false; 421 } 422 clearCoincident()423 bool clearCoincident() { 424 SkASSERT(!final()); 425 if (fCoincident == this) { 426 return false; 427 } 428 fCoincident = this; 429 return true; 430 } 431 432 int computeWindSum(); 433 bool containsCoincidence(const SkOpSegment* ) const; 434 containsCoincidence(const SkOpSpan * coin)435 bool containsCoincidence(const SkOpSpan* coin) const { 436 SkASSERT(this != coin); 437 const SkOpSpan* next = this; 438 while ((next = next->fCoincident) != this) { 439 if (next == coin) { 440 return true; 441 } 442 } 443 return false; 444 } 445 446 bool debugCoinLoopCheck() const; 447 #if DEBUG_COIN 448 void debugInsertCoincidence(SkPathOpsDebug::GlitchLog* , const SkOpSpan* ) const; 449 void debugInsertCoincidence(SkPathOpsDebug::GlitchLog* , 450 const SkOpSegment* , bool flipped, bool ordered) const; 451 #endif 452 void dumpCoin() const; 453 bool dumpSpan() const; 454 done()455 bool done() const { 456 SkASSERT(!final()); 457 return fDone; 458 } 459 460 void init(SkOpSegment* parent, SkOpSpan* prev, double t, const SkPoint& pt); 461 bool insertCoincidence(const SkOpSegment* , bool flipped, bool ordered); 462 463 // Please keep this in sync with debugInsertCoincidence() insertCoincidence(SkOpSpan * coin)464 void insertCoincidence(SkOpSpan* coin) { 465 if (containsCoincidence(coin)) { 466 SkASSERT(coin->containsCoincidence(this)); 467 return; 468 } 469 debugValidate(); 470 SkASSERT(this != coin); 471 SkOpSpan* coinNext = coin->fCoincident; 472 coin->fCoincident = this->fCoincident; 473 this->fCoincident = coinNext; 474 debugValidate(); 475 } 476 isCanceled()477 bool isCanceled() const { 478 SkASSERT(!final()); 479 return fWindValue == 0 && fOppValue == 0; 480 } 481 isCoincident()482 bool isCoincident() const { 483 SkASSERT(!final()); 484 return fCoincident != this; 485 } 486 next()487 SkOpSpanBase* next() const { 488 SkASSERT(!final()); 489 return fNext; 490 } 491 oppSum()492 int oppSum() const { 493 SkASSERT(!final()); 494 return fOppSum; 495 } 496 oppValue()497 int oppValue() const { 498 SkASSERT(!final()); 499 return fOppValue; 500 } 501 502 void release(const SkOpPtT* ); 503 504 SkOpPtT* setCoinStart(SkOpSpan* oldCoinStart, SkOpSegment* oppSegment); 505 setDone(bool done)506 void setDone(bool done) { 507 SkASSERT(!final()); 508 fDone = done; 509 } 510 setNext(SkOpSpanBase * nextT)511 void setNext(SkOpSpanBase* nextT) { 512 SkASSERT(!final()); 513 fNext = nextT; 514 } 515 516 void setOppSum(int oppSum); 517 setOppValue(int oppValue)518 void setOppValue(int oppValue) { 519 SkASSERT(!final()); 520 SkASSERT(fOppSum == SK_MinS32); 521 SkOPASSERT(!oppValue || !fDone); 522 fOppValue = oppValue; 523 } 524 setToAngle(SkOpAngle * angle)525 void setToAngle(SkOpAngle* angle) { 526 SkASSERT(!final()); 527 fToAngle = angle; 528 } 529 530 void setWindSum(int windSum); 531 setWindValue(int windValue)532 void setWindValue(int windValue) { 533 SkASSERT(!final()); 534 SkASSERT(windValue >= 0); 535 SkASSERT(fWindSum == SK_MinS32); 536 SkOPASSERT(!windValue || !fDone); 537 fWindValue = windValue; 538 } 539 540 bool sortableTop(SkOpContour* ); 541 toAngle()542 SkOpAngle* toAngle() const { 543 SkASSERT(!final()); 544 return fToAngle; 545 } 546 windSum()547 int windSum() const { 548 SkASSERT(!final()); 549 return fWindSum; 550 } 551 windValue()552 int windValue() const { 553 SkOPASSERT(!final()); 554 return fWindValue; 555 } 556 557 private: // no direct access to internals to avoid treating a span base as a span 558 SkOpSpan* fCoincident; // linked list of spans coincident with this one (may point to itself) 559 SkOpAngle* fToAngle; // points to next angle from span start to end 560 SkOpSpanBase* fNext; // next intersection point 561 int fWindSum; // accumulated from contours surrounding this one. 562 int fOppSum; // for binary operators: the opposite winding sum 563 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident 564 int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here 565 int fTopTTry; // specifies direction and t value to try next 566 bool fDone; // if set, this span to next higher T has been processed 567 mutable bool fAlreadyAdded; 568 }; 569 570 #endif 571