blob: c6fc4b138f0c8135dd367f1ac717e3705e030df2 [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
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
caryclark54359292015-03-26 07:52:43 -070010#include "SkPathOpsDebug.h"
caryclark27c8eb82015-07-06 11:38:33 -070011#include "SkPathOpsTypes.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +000012#include "SkPoint.h"
13
caryclark54359292015-03-26 07:52:43 -070014class SkChunkAlloc;
15struct SkOpAngle;
16class SkOpContour;
17class SkOpGlobalState;
caryclark@google.com07393ca2013-04-08 11:47:37 +000018class SkOpSegment;
caryclark54359292015-03-26 07:52:43 -070019class SkOpSpanBase;
20class SkOpSpan;
caryclark@google.com07393ca2013-04-08 11:47:37 +000021
caryclark54359292015-03-26 07:52:43 -070022// subset of op span used by terminal span (when t is equal to one)
23class SkOpPtT {
24public:
25 enum {
26 kIsAlias = 1,
27 kIsDuplicate = 1
28 };
29
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;
caryclarkd4349722015-07-23 12:40:22 -070051 bool collapsed(const SkOpPtT* ) const;
caryclark27c8eb82015-07-06 11:38:33 -070052 bool contains(const SkOpPtT* ) const;
53 SkOpPtT* contains(const SkOpSegment* );
caryclark54359292015-03-26 07:52:43 -070054 SkOpContour* contour() const;
55
56 int debugID() const {
caryclark1049f122015-04-20 08:31:59 -070057 return SkDEBUGRELEASE(fID, -1);
caryclark54359292015-03-26 07:52:43 -070058 }
59
60 const SkOpAngle* debugAngle(int id) const;
caryclark26ad22a2015-10-16 09:03:38 -070061 bool debugContains(const SkOpPtT* ) const;
62 const SkOpPtT* debugContains(const SkOpSegment* check) const;
caryclark54359292015-03-26 07:52:43 -070063 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;
caryclark54359292015-03-26 07:52:43 -070069 void debugValidate() const;
70
71 bool deleted() const {
72 return fDeleted;
73 }
74
caryclark27c8eb82015-07-06 11:38:33 -070075 SkOpPtT* doppelganger();
76
caryclark54359292015-03-26 07:52:43 -070077 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
caryclark27c8eb82015-07-06 11:38:33 -070085 SkOpPtT* find(SkOpSegment* );
caryclark26ad22a2015-10-16 09:03:38 -070086 SkOpGlobalState* globalState() const;
caryclark54359292015-03-26 07:52:43 -070087 void init(SkOpSpanBase* , double t, const SkPoint& , bool dup);
88
89 void insert(SkOpPtT* span) {
90 SkASSERT(span != this);
91 span->fNext = fNext;
92 fNext = span;
93 }
94
95 const SkOpPtT* next() const {
96 return fNext;
97 }
98
99 SkOpPtT* next() {
100 return fNext;
101 }
102
103 bool onEnd() const;
caryclark27c8eb82015-07-06 11:38:33 -0700104
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
halcanary96fcdcc2015-08-27 07:41:13 -0700110 : between(s2->fT, start1->fT, e2->fT) ? start1 : nullptr;
caryclark27c8eb82015-07-06 11:38:33 -0700111 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
halcanary96fcdcc2015-08-27 07:41:13 -0700114 : between(s2->fT, end1->fT, e2->fT) ? end1 : nullptr;
caryclark27c8eb82015-07-06 11:38:33 -0700115 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
caryclark54359292015-03-26 07:52:43 -0700123 SkOpPtT* prev();
124 SkOpPtT* remove();
125 void removeNext(SkOpPtT* kept);
126
127 const SkOpSegment* segment() const;
128 SkOpSegment* segment();
129
130 void setDeleted() {
131 SkASSERT(!fDeleted);
132 fDeleted = true;
133 }
134
135 const SkOpSpanBase* span() const {
136 return fSpan;
137 }
138
139 SkOpSpanBase* span() {
140 return fSpan;
141 }
142
caryclark27c8eb82015-07-06 11:38:33 -0700143 const SkOpPtT* starter(const SkOpPtT* end) const {
144 return fT < end->fT ? this : end;
145 }
146
caryclark54359292015-03-26 07:52:43 -0700147 double fT;
148 SkPoint fPt; // cache of point value at this t
149protected:
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
caryclark1049f122015-04-20 08:31:59 -0700154 SkDEBUGCODE(int fID);
caryclark54359292015-03-26 07:52:43 -0700155};
156
157class SkOpSpanBase {
158public:
caryclark54359292015-03-26 07:52:43 -0700159 void align();
160
161 bool aligned() const {
162 return fAligned;
163 }
164
165 void alignEnd(double t, const SkPoint& pt);
166
caryclark08bc8482015-04-24 09:08:57 -0700167 void bumpSpanAdds() {
168 ++fSpanAdds;
169 }
170
caryclark54359292015-03-26 07:52:43 -0700171 bool chased() const {
172 return fChased;
173 }
174
175 void clearCoinEnd() {
176 SkASSERT(fCoinEnd != this);
177 fCoinEnd = this;
178 }
179
180 const SkOpSpanBase* coinEnd() const {
181 return fCoinEnd;
182 }
183
184 bool contains(const SkOpSpanBase* ) const;
185 SkOpPtT* contains(const SkOpSegment* );
186
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
201 int debugBumpCount() {
caryclark1049f122015-04-20 08:31:59 -0700202 return SkDEBUGRELEASE(++fCount, -1);
caryclark54359292015-03-26 07:52:43 -0700203 }
204
205 int debugID() const {
caryclark1049f122015-04-20 08:31:59 -0700206 return SkDEBUGRELEASE(fID, -1);
caryclark54359292015-03-26 07:52:43 -0700207 }
208
caryclark26ad22a2015-10-16 09:03:38 -0700209 bool debugAlignedEnd(double t, const SkPoint& pt) const;
210 bool debugAlignedInner() const;
caryclark54359292015-03-26 07:52:43 -0700211 const SkOpAngle* debugAngle(int id) const;
212 bool debugCoinEndLoopCheck() const;
caryclark26ad22a2015-10-16 09:03:38 -0700213 bool debugContains(const SkOpSegment* ) const;
caryclark54359292015-03-26 07:52:43 -0700214 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;
caryclark26ad22a2015-10-16 09:03:38 -0700218 const SkOpSpan* debugStarter(SkOpSpanBase const** endPtr) const;
caryclark54359292015-03-26 07:52:43 -0700219 SkOpGlobalState* globalState() const;
220 void debugValidate() const;
221
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
231 bool final() const {
232 return fPtT.fT == 1;
233 }
234
235 SkOpAngle* fromAngle() const {
236 return fFromAngle;
237 }
238
239 void initBase(SkOpSegment* parent, SkOpSpan* prev, double t, const SkPoint& pt);
240
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
256 SkOpSpan* prev() const {
257 return fPrev;
258 }
259
260 const SkPoint& pt() const {
261 return fPtT.fPt;
262 }
263
264 const SkOpPtT* ptT() const {
265 return &fPtT;
266 }
267
268 SkOpPtT* ptT() {
269 return &fPtT;
270 }
271
272 SkOpSegment* segment() const {
273 return fSegment;
274 }
275
caryclarkd4349722015-07-23 12:40:22 -0700276 void setAligned() {
277 fAligned = true;
278 }
279
caryclark54359292015-03-26 07:52:43 -0700280 void setChased(bool chased) {
281 fChased = chased;
282 }
283
284 SkOpPtT* setCoinEnd(SkOpSpanBase* oldCoinEnd, SkOpSegment* oppSegment);
285
286 void setFromAngle(SkOpAngle* angle) {
287 fFromAngle = angle;
288 }
289
290 void setPrev(SkOpSpan* prev) {
291 fPrev = prev;
292 }
293
294 bool simple() const {
295 fPtT.debugValidate();
296 return fPtT.next()->next() == &fPtT;
297 }
298
caryclark08bc8482015-04-24 09:08:57 -0700299 int spanAddsCount() const {
300 return fSpanAdds;
301 }
302
caryclark54359292015-03-26 07:52:43 -0700303 const SkOpSpan* starter(const SkOpSpanBase* end) const {
304 const SkOpSpanBase* result = t() < end->t() ? this : end;
305 return result->upCast();
306 }
307
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
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
327 int step(const SkOpSpanBase* end) const {
328 return t() < end->t() ? 1 : -1;
329 }
330
331 double t() const {
332 return fPtT.fT;
333 }
334
335 void unaligned() {
336 fAligned = false;
337 }
338
339 SkOpSpan* upCast() {
340 SkASSERT(!final());
341 return (SkOpSpan*) this;
342 }
343
344 const SkOpSpan* upCast() const {
345 SkASSERT(!final());
346 return (const SkOpSpan*) this;
347 }
348
349 SkOpSpan* upCastable() {
halcanary96fcdcc2015-08-27 07:41:13 -0700350 return final() ? nullptr : upCast();
caryclark54359292015-03-26 07:52:43 -0700351 }
352
353 const SkOpSpan* upCastable() const {
halcanary96fcdcc2015-08-27 07:41:13 -0700354 return final() ? nullptr : upCast();
caryclark54359292015-03-26 07:52:43 -0700355 }
356
357private:
358 void alignInner();
359
360protected: // 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
caryclark08bc8482015-04-24 09:08:57 -0700366 int fSpanAdds; // number of times intersections have been added to span
caryclark54359292015-03-26 07:52:43 -0700367 bool fAligned;
368 bool fChased; // set after span has been added to chase array
caryclark1049f122015-04-20 08:31:59 -0700369 SkDEBUGCODE(int fCount); // number of pt/t pairs added
370 SkDEBUGCODE(int fID);
caryclark54359292015-03-26 07:52:43 -0700371};
372
373class SkOpSpan : public SkOpSpanBase {
374public:
caryclarkef784fb2015-10-30 12:03:06 -0700375 bool alreadyAdded() const {
376 if (fAlreadyAdded) {
377 return true;
378 }
379 fAlreadyAdded = true;
380 return false;
381 }
382
caryclark54359292015-03-26 07:52:43 -0700383 bool clearCoincident() {
384 SkASSERT(!final());
385 if (fCoincident == this) {
386 return false;
387 }
388 fCoincident = this;
389 return true;
390 }
391
caryclarkbca19f72015-05-13 08:23:48 -0700392 int computeWindSum();
caryclark54359292015-03-26 07:52:43 -0700393 bool containsCoincidence(const SkOpSegment* ) const;
394
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;
mtklein18300a32016-03-16 13:53:35 -0700407 void release(SkOpPtT* );
caryclark54359292015-03-26 07:52:43 -0700408
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
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
431 bool isCanceled() const {
432 SkASSERT(!final());
433 return fWindValue == 0 && fOppValue == 0;
434 }
435
436 bool isCoincident() const {
437 SkASSERT(!final());
438 return fCoincident != this;
439 }
440
441 SkOpSpanBase* next() const {
442 SkASSERT(!final());
443 return fNext;
444 }
445
446 int oppSum() const {
447 SkASSERT(!final());
448 return fOppSum;
449 }
450
451 int oppValue() const {
452 SkASSERT(!final());
453 return fOppValue;
454 }
455
456 SkOpPtT* setCoinStart(SkOpSpan* oldCoinStart, SkOpSegment* oppSegment);
457
458 void setDone(bool done) {
459 SkASSERT(!final());
460 fDone = done;
461 }
462
463 void setNext(SkOpSpanBase* nextT) {
464 SkASSERT(!final());
465 fNext = nextT;
466 }
467
468 void setOppSum(int oppSum);
469
470 void setOppValue(int oppValue) {
471 SkASSERT(!final());
472 SkASSERT(fOppSum == SK_MinS32);
473 fOppValue = oppValue;
474 }
475
476 void setToAngle(SkOpAngle* angle) {
477 SkASSERT(!final());
478 fToAngle = angle;
479 }
480
caryclark624637c2015-05-11 07:21:27 -0700481 void setWindSum(int windSum);
caryclark54359292015-03-26 07:52:43 -0700482
483 void setWindValue(int windValue) {
484 SkASSERT(!final());
485 SkASSERT(windValue >= 0);
486 SkASSERT(fWindSum == SK_MinS32);
487 fWindValue = windValue;
488 }
489
caryclark624637c2015-05-11 07:21:27 -0700490 bool sortableTop(SkOpContour* );
491
caryclark54359292015-03-26 07:52:43 -0700492 SkOpAngle* toAngle() const {
493 SkASSERT(!final());
494 return fToAngle;
495 }
496
497 int windSum() const {
498 SkASSERT(!final());
499 return fWindSum;
500 }
501
502 int windValue() const {
503 SkASSERT(!final());
504 return fWindValue;
505 }
506
507private: // 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
caryclark@google.com07393ca2013-04-08 11:47:37 +0000511 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
caryclark624637c2015-05-11 07:21:27 -0700515 int fTopTTry; // specifies direction and t value to try next
caryclark@google.com07393ca2013-04-08 11:47:37 +0000516 bool fDone; // if set, this span to next higher T has been processed
caryclarkef784fb2015-10-30 12:03:06 -0700517 mutable bool fAlreadyAdded;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000518};
519
520#endif