OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2012 Google Inc. | 2 * Copyright 2012 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 #ifndef SkOpSpan_DEFINED | 7 #ifndef SkOpSpan_DEFINED |
8 #define SkOpSpan_DEFINED | 8 #define SkOpSpan_DEFINED |
9 | 9 |
| 10 #include "SkPathOpsDebug.h" |
10 #include "SkPoint.h" | 11 #include "SkPoint.h" |
11 | 12 |
12 class SkOpAngle; | 13 class SkChunkAlloc; |
| 14 struct SkOpAngle; |
| 15 class SkOpContour; |
| 16 class SkOpGlobalState; |
13 class SkOpSegment; | 17 class SkOpSegment; |
14 | 18 class SkOpSpanBase; |
15 struct SkOpSpan { | 19 class SkOpSpan; |
16 SkPoint fPt; // computed when the curves are intersected | 20 |
17 double fT; | 21 // subset of op span used by terminal span (when t is equal to one) |
18 double fOtherT; // value at fOther[fOtherIndex].fT | 22 class SkOpPtT { |
19 SkOpSegment* fOther; | 23 public: |
20 SkOpAngle* fFromAngle; // (if t > 0) index into segment's angle array going
negative in t | 24 enum { |
21 SkOpAngle* fToAngle; // (if t < 1) index into segment's angle array going p
ositive in t | 25 kIsAlias = 1, |
22 int fOtherIndex; // can't be used during intersection | 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 PATH_OPS_DEBUG_RELEASE(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 |
| 117 protected: |
| 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 PATH_OPS_DEBUG_CODE(int fID); |
| 123 }; |
| 124 |
| 125 class SkOpSpanBase { |
| 126 public: |
| 127 void addSimpleAngle(bool checkFrom , SkChunkAlloc* ); |
| 128 void align(); |
| 129 |
| 130 bool aligned() const { |
| 131 return fAligned; |
| 132 } |
| 133 |
| 134 void alignEnd(double t, const SkPoint& pt); |
| 135 |
| 136 bool chased() const { |
| 137 return fChased; |
| 138 } |
| 139 |
| 140 void clearCoinEnd() { |
| 141 SkASSERT(fCoinEnd != this); |
| 142 fCoinEnd = this; |
| 143 } |
| 144 |
| 145 const SkOpSpanBase* coinEnd() const { |
| 146 return fCoinEnd; |
| 147 } |
| 148 |
| 149 bool contains(const SkOpSpanBase* ) const; |
| 150 SkOpPtT* contains(const SkOpSegment* ); |
| 151 |
| 152 bool containsCoinEnd(const SkOpSpanBase* coin) const { |
| 153 SkASSERT(this != coin); |
| 154 const SkOpSpanBase* next = this; |
| 155 while ((next = next->fCoinEnd) != this) { |
| 156 if (next == coin) { |
| 157 return true; |
| 158 } |
| 159 } |
| 160 return false; |
| 161 } |
| 162 |
| 163 bool containsCoinEnd(const SkOpSegment* ) const; |
| 164 SkOpContour* contour() const; |
| 165 |
| 166 int debugBumpCount() { |
| 167 return PATH_OPS_DEBUG_RELEASE(++fCount, -1); |
| 168 } |
| 169 |
| 170 int debugID() const { |
| 171 return PATH_OPS_DEBUG_RELEASE(fID, -1); |
| 172 } |
| 173 |
| 174 const SkOpAngle* debugAngle(int id) const; |
| 175 bool debugCoinEndLoopCheck() const; |
| 176 SkOpContour* debugContour(int id); |
| 177 const SkOpPtT* debugPtT(int id) const; |
| 178 const SkOpSegment* debugSegment(int id) const; |
| 179 const SkOpSpanBase* debugSpan(int id) const; |
| 180 SkOpGlobalState* globalState() const; |
| 181 void debugValidate() const; |
| 182 |
| 183 bool deleted() const { |
| 184 return fPtT.deleted(); |
| 185 } |
| 186 |
| 187 void dump() const; // available to testing only |
| 188 void dumpCoin() const; |
| 189 void dumpAll() const; |
| 190 void dumpBase() const; |
| 191 |
| 192 bool final() const { |
| 193 return fPtT.fT == 1; |
| 194 } |
| 195 |
| 196 SkOpAngle* fromAngle() const { |
| 197 return fFromAngle; |
| 198 } |
| 199 |
| 200 void initBase(SkOpSegment* parent, SkOpSpan* prev, double t, const SkPoint&
pt); |
| 201 |
| 202 void insertCoinEnd(SkOpSpanBase* coin) { |
| 203 if (containsCoinEnd(coin)) { |
| 204 SkASSERT(coin->containsCoinEnd(this)); |
| 205 return; |
| 206 } |
| 207 debugValidate(); |
| 208 SkASSERT(this != coin); |
| 209 SkOpSpanBase* coinNext = coin->fCoinEnd; |
| 210 coin->fCoinEnd = this->fCoinEnd; |
| 211 this->fCoinEnd = coinNext; |
| 212 debugValidate(); |
| 213 } |
| 214 |
| 215 void merge(SkOpSpan* span); |
| 216 |
| 217 SkOpSpan* prev() const { |
| 218 return fPrev; |
| 219 } |
| 220 |
| 221 const SkPoint& pt() const { |
| 222 return fPtT.fPt; |
| 223 } |
| 224 |
| 225 const SkOpPtT* ptT() const { |
| 226 return &fPtT; |
| 227 } |
| 228 |
| 229 SkOpPtT* ptT() { |
| 230 return &fPtT; |
| 231 } |
| 232 |
| 233 SkOpSegment* segment() const { |
| 234 return fSegment; |
| 235 } |
| 236 |
| 237 void setChased(bool chased) { |
| 238 fChased = chased; |
| 239 } |
| 240 |
| 241 SkOpPtT* setCoinEnd(SkOpSpanBase* oldCoinEnd, SkOpSegment* oppSegment); |
| 242 |
| 243 void setFromAngle(SkOpAngle* angle) { |
| 244 fFromAngle = angle; |
| 245 } |
| 246 |
| 247 void setPrev(SkOpSpan* prev) { |
| 248 fPrev = prev; |
| 249 } |
| 250 |
| 251 bool simple() const { |
| 252 fPtT.debugValidate(); |
| 253 return fPtT.next()->next() == &fPtT; |
| 254 } |
| 255 |
| 256 const SkOpSpan* starter(const SkOpSpanBase* end) const { |
| 257 const SkOpSpanBase* result = t() < end->t() ? this : end; |
| 258 return result->upCast(); |
| 259 } |
| 260 |
| 261 SkOpSpan* starter(SkOpSpanBase* end) { |
| 262 SkASSERT(this->segment() == end->segment()); |
| 263 SkOpSpanBase* result = t() < end->t() ? this : end; |
| 264 return result->upCast(); |
| 265 } |
| 266 |
| 267 SkOpSpan* starter(SkOpSpanBase** endPtr) { |
| 268 SkOpSpanBase* end = *endPtr; |
| 269 SkASSERT(this->segment() == end->segment()); |
| 270 SkOpSpanBase* result; |
| 271 if (t() < end->t()) { |
| 272 result = this; |
| 273 } else { |
| 274 result = end; |
| 275 *endPtr = this; |
| 276 } |
| 277 return result->upCast(); |
| 278 } |
| 279 |
| 280 int step(const SkOpSpanBase* end) const { |
| 281 return t() < end->t() ? 1 : -1; |
| 282 } |
| 283 |
| 284 double t() const { |
| 285 return fPtT.fT; |
| 286 } |
| 287 |
| 288 void unaligned() { |
| 289 fAligned = false; |
| 290 } |
| 291 |
| 292 SkOpSpan* upCast() { |
| 293 SkASSERT(!final()); |
| 294 return (SkOpSpan*) this; |
| 295 } |
| 296 |
| 297 const SkOpSpan* upCast() const { |
| 298 SkASSERT(!final()); |
| 299 return (const SkOpSpan*) this; |
| 300 } |
| 301 |
| 302 SkOpSpan* upCastable() { |
| 303 return final() ? NULL : upCast(); |
| 304 } |
| 305 |
| 306 const SkOpSpan* upCastable() const { |
| 307 return final() ? NULL : upCast(); |
| 308 } |
| 309 |
| 310 private: |
| 311 void alignInner(); |
| 312 |
| 313 protected: // no direct access to internals to avoid treating a span base as a
span |
| 314 SkOpPtT fPtT; // list of points and t values associated with the start of t
his span |
| 315 SkOpSegment* fSegment; // segment that contains this span |
| 316 SkOpSpanBase* fCoinEnd; // linked list of coincident spans that end here (m
ay point to itself) |
| 317 SkOpAngle* fFromAngle; // points to next angle from span start to end |
| 318 SkOpSpan* fPrev; // previous intersection point |
| 319 bool fAligned; |
| 320 bool fChased; // set after span has been added to chase array |
| 321 PATH_OPS_DEBUG_CODE(int fCount); // number of pt/t pairs added |
| 322 PATH_OPS_DEBUG_CODE(int fID); |
| 323 }; |
| 324 |
| 325 class SkOpSpan : public SkOpSpanBase { |
| 326 public: |
| 327 void applyCoincidence(SkOpSpan* opp); |
| 328 |
| 329 bool clearCoincident() { |
| 330 SkASSERT(!final()); |
| 331 if (fCoincident == this) { |
| 332 return false; |
| 333 } |
| 334 fCoincident = this; |
| 335 return true; |
| 336 } |
| 337 |
| 338 bool containsCoincidence(const SkOpSegment* ) const; |
| 339 |
| 340 bool containsCoincidence(const SkOpSpan* coin) const { |
| 341 SkASSERT(this != coin); |
| 342 const SkOpSpan* next = this; |
| 343 while ((next = next->fCoincident) != this) { |
| 344 if (next == coin) { |
| 345 return true; |
| 346 } |
| 347 } |
| 348 return false; |
| 349 } |
| 350 |
| 351 bool debugCoinLoopCheck() const; |
| 352 void detach(SkOpPtT* ); |
| 353 |
| 354 bool done() const { |
| 355 SkASSERT(!final()); |
| 356 return fDone; |
| 357 } |
| 358 |
| 359 void dumpCoin() const; |
| 360 bool dumpSpan() const; |
| 361 void init(SkOpSegment* parent, SkOpSpan* prev, double t, const SkPoint& pt); |
| 362 |
| 363 void insertCoincidence(SkOpSpan* coin) { |
| 364 if (containsCoincidence(coin)) { |
| 365 SkASSERT(coin->containsCoincidence(this)); |
| 366 return; |
| 367 } |
| 368 debugValidate(); |
| 369 SkASSERT(this != coin); |
| 370 SkOpSpan* coinNext = coin->fCoincident; |
| 371 coin->fCoincident = this->fCoincident; |
| 372 this->fCoincident = coinNext; |
| 373 debugValidate(); |
| 374 } |
| 375 |
| 376 bool isCanceled() const { |
| 377 SkASSERT(!final()); |
| 378 return fWindValue == 0 && fOppValue == 0; |
| 379 } |
| 380 |
| 381 bool isCoincident() const { |
| 382 SkASSERT(!final()); |
| 383 return fCoincident != this; |
| 384 } |
| 385 |
| 386 SkOpSpanBase* next() const { |
| 387 SkASSERT(!final()); |
| 388 return fNext; |
| 389 } |
| 390 |
| 391 int oppSum() const { |
| 392 SkASSERT(!final()); |
| 393 return fOppSum; |
| 394 } |
| 395 |
| 396 int oppValue() const { |
| 397 SkASSERT(!final()); |
| 398 return fOppValue; |
| 399 } |
| 400 |
| 401 SkOpPtT* setCoinStart(SkOpSpan* oldCoinStart, SkOpSegment* oppSegment); |
| 402 |
| 403 void setDone(bool done) { |
| 404 SkASSERT(!final()); |
| 405 fDone = done; |
| 406 } |
| 407 |
| 408 void setNext(SkOpSpanBase* nextT) { |
| 409 SkASSERT(!final()); |
| 410 fNext = nextT; |
| 411 } |
| 412 |
| 413 void setOppSum(int oppSum); |
| 414 |
| 415 void setOppValue(int oppValue) { |
| 416 SkASSERT(!final()); |
| 417 SkASSERT(fOppSum == SK_MinS32); |
| 418 fOppValue = oppValue; |
| 419 } |
| 420 |
| 421 void setToAngle(SkOpAngle* angle) { |
| 422 SkASSERT(!final()); |
| 423 fToAngle = angle; |
| 424 } |
| 425 |
| 426 void setWindSum(int windSum) { |
| 427 SkASSERT(!final()); |
| 428 SkASSERT(fWindSum == SK_MinS32 || fWindSum == windSum); |
| 429 SkASSERT(!DEBUG_LIMIT_WIND_SUM || abs(windSum) <= DEBUG_LIMIT_WIND_SUM); |
| 430 fWindSum = windSum; |
| 431 } |
| 432 |
| 433 void setWindValue(int windValue) { |
| 434 SkASSERT(!final()); |
| 435 SkASSERT(windValue >= 0); |
| 436 SkASSERT(fWindSum == SK_MinS32); |
| 437 fWindValue = windValue; |
| 438 } |
| 439 |
| 440 SkOpAngle* toAngle() const { |
| 441 SkASSERT(!final()); |
| 442 return fToAngle; |
| 443 } |
| 444 |
| 445 int windSum() const { |
| 446 SkASSERT(!final()); |
| 447 return fWindSum; |
| 448 } |
| 449 |
| 450 int windValue() const { |
| 451 SkASSERT(!final()); |
| 452 return fWindValue; |
| 453 } |
| 454 |
| 455 private: // no direct access to internals to avoid treating a span base as a sp
an |
| 456 SkOpSpan* fCoincident; // linked list of spans coincident with this one (ma
y point to itself) |
| 457 SkOpAngle* fToAngle; // points to next angle from span start to end |
| 458 SkOpSpanBase* fNext; // next intersection point |
23 int fWindSum; // accumulated from contours surrounding this one. | 459 int fWindSum; // accumulated from contours surrounding this one. |
24 int fOppSum; // for binary operators: the opposite winding sum | 460 int fOppSum; // for binary operators: the opposite winding sum |
25 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident | 461 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident |
26 int fOppValue; // normally 0 -- when binary coincident edges combine, opp v
alue goes here | 462 int fOppValue; // normally 0 -- when binary coincident edges combine, opp v
alue goes here |
27 bool fChased; // set after span has been added to chase array | |
28 bool fCoincident; // set if span is bumped -- if set additional points aren
't inserted | |
29 bool fDone; // if set, this span to next higher T has been processed | 463 bool fDone; // if set, this span to next higher T has been processed |
30 bool fLoop; // set when a cubic loops back to this point | |
31 bool fMultiple; // set if this is one of mutiple spans with identical t and
pt values | |
32 bool fNear; // set if opposite end point is near but not equal to this one | |
33 bool fSmall; // if set, consecutive points are almost equal | |
34 bool fTiny; // if set, consecutive points are equal but consecutive ts are
not precisely equal | |
35 | |
36 // available to testing only | |
37 const SkOpSegment* debugToSegment(ptrdiff_t* ) const; | |
38 void dump() const; | |
39 void dumpOne() const; | |
40 }; | 464 }; |
41 | 465 |
42 #endif | 466 #endif |
OLD | NEW |