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