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