blob: f14bab61b86a389a80ab096f58b1166cd07fd940 [file] [log] [blame]
caryclark@google.com07393ca2013-04-08 11:47:37 +00001/*
2 * Copyright 2013 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 SkOpContour_DEFINED
8#define SkOpContour_DEFINED
9
10#include "SkOpSegment.h"
caryclark54359292015-03-26 07:52:43 -070011#include "SkTDArray.h"
12#include "SkTSort.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +000013
caryclark624637c2015-05-11 07:21:27 -070014enum class SkOpRayDir;
15struct SkOpRayHit;
caryclark@google.com07393ca2013-04-08 11:47:37 +000016class SkPathWriter;
17
caryclark@google.com07393ca2013-04-08 11:47:37 +000018class SkOpContour {
19public:
20 SkOpContour() {
21 reset();
caryclark54359292015-03-26 07:52:43 -070022 }
23
24 ~SkOpContour() {
25 if (fNext) {
26 fNext->~SkOpContour();
27 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000028 }
29
30 bool operator<(const SkOpContour& rh) const {
31 return fBounds.fTop == rh.fBounds.fTop
caryclark55888e42016-07-18 10:01:36 -070032 ? fBounds.fLeft < rh.fBounds.fLeft
33 : fBounds.fTop < rh.fBounds.fTop;
caryclark@google.com07393ca2013-04-08 11:47:37 +000034 }
35
caryclark55888e42016-07-18 10:01:36 -070036 void addConic(SkPoint pts[3], SkScalar weight) {
37 appendSegment().addConic(pts, weight, this);
caryclark27c8eb82015-07-06 11:38:33 -070038 }
39
caryclark55888e42016-07-18 10:01:36 -070040 void addCubic(SkPoint pts[4]) {
41 appendSegment().addCubic(pts, this);
caryclark1049f122015-04-20 08:31:59 -070042 }
43
caryclark27c015d2016-09-23 05:47:20 -070044 SkOpSegment* addCurve(SkPath::Verb verb, const SkPoint pts[4], SkScalar weight = 1);
caryclark55888e42016-07-18 10:01:36 -070045
46 SkOpSegment* addLine(SkPoint pts[2]) {
caryclarkbb51f4a2016-08-23 07:38:48 -070047 SkASSERT(pts[0] != pts[1]);
caryclark55888e42016-07-18 10:01:36 -070048 return appendSegment().addLine(pts, this);
caryclark54359292015-03-26 07:52:43 -070049 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000050
caryclark55888e42016-07-18 10:01:36 -070051 void addQuad(SkPoint pts[3]) {
52 appendSegment().addQuad(pts, this);
caryclark54359292015-03-26 07:52:43 -070053 }
54
caryclark55888e42016-07-18 10:01:36 -070055 SkOpSegment& appendSegment() {
caryclark54359292015-03-26 07:52:43 -070056 SkOpSegment* result = fCount++
caryclark55888e42016-07-18 10:01:36 -070057 ? SkOpTAllocator<SkOpSegment>::Allocate(this->globalState()->allocator()) : &fHead;
caryclark54359292015-03-26 07:52:43 -070058 result->setPrev(fTail);
59 if (fTail) {
60 fTail->setNext(result);
caryclark@google.com07393ca2013-04-08 11:47:37 +000061 }
caryclark54359292015-03-26 07:52:43 -070062 fTail = result;
63 return *result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000064 }
65
caryclark@google.com07393ca2013-04-08 11:47:37 +000066 const SkPathOpsBounds& bounds() const {
67 return fBounds;
68 }
69
caryclark55888e42016-07-18 10:01:36 -070070 void calcAngles() {
caryclark54359292015-03-26 07:52:43 -070071 SkASSERT(fCount > 0);
72 SkOpSegment* segment = &fHead;
73 do {
caryclark55888e42016-07-18 10:01:36 -070074 segment->calcAngles();
caryclark54359292015-03-26 07:52:43 -070075 } while ((segment = segment->next()));
caryclark@google.comfa2aeee2013-07-15 13:29:13 +000076 }
77
caryclark@google.com07393ca2013-04-08 11:47:37 +000078 void complete() {
79 setBounds();
caryclark@google.com07393ca2013-04-08 11:47:37 +000080 }
81
caryclark54359292015-03-26 07:52:43 -070082 int count() const {
83 return fCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +000084 }
85
caryclark54359292015-03-26 07:52:43 -070086 int debugID() const {
caryclark1049f122015-04-20 08:31:59 -070087 return SkDEBUGRELEASE(fID, -1);
caryclark54359292015-03-26 07:52:43 -070088 }
89
90 int debugIndent() const {
caryclark624637c2015-05-11 07:21:27 -070091 return SkDEBUGRELEASE(fDebugIndent, 0);
caryclark54359292015-03-26 07:52:43 -070092 }
93
caryclark54359292015-03-26 07:52:43 -070094
95 const SkOpAngle* debugAngle(int id) const {
halcanary96fcdcc2015-08-27 07:41:13 -070096 return SkDEBUGRELEASE(this->globalState()->debugAngle(id), nullptr);
caryclark54359292015-03-26 07:52:43 -070097 }
98
caryclark55888e42016-07-18 10:01:36 -070099 const SkOpCoincidence* debugCoincidence() const {
100 return this->globalState()->coincidence();
101 }
102
Cary Clarkab87d7a2016-10-04 10:01:04 -0400103#if DEBUG_COIN
104 void debugCheckHealth(SkPathOpsDebug::GlitchLog* ) const;
caryclark55888e42016-07-18 10:01:36 -0700105#endif
caryclark26ad22a2015-10-16 09:03:38 -0700106
caryclark30b9fdd2016-08-31 14:36:29 -0700107 SkOpContour* debugContour(int id) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700108 return SkDEBUGRELEASE(this->globalState()->debugContour(id), nullptr);
caryclark54359292015-03-26 07:52:43 -0700109 }
110
Cary Clarkab87d7a2016-10-04 10:01:04 -0400111#if DEBUG_COIN
112 void debugMissingCoincidence(SkPathOpsDebug::GlitchLog* log) const;
113 void debugMoveMultiples(SkPathOpsDebug::GlitchLog* ) const;
114 void debugMoveNearby(SkPathOpsDebug::GlitchLog* log) const;
caryclark55888e42016-07-18 10:01:36 -0700115#endif
caryclark26ad22a2015-10-16 09:03:38 -0700116
caryclark54359292015-03-26 07:52:43 -0700117 const SkOpPtT* debugPtT(int id) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700118 return SkDEBUGRELEASE(this->globalState()->debugPtT(id), nullptr);
caryclark54359292015-03-26 07:52:43 -0700119 }
120
121 const SkOpSegment* debugSegment(int id) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700122 return SkDEBUGRELEASE(this->globalState()->debugSegment(id), nullptr);
caryclark54359292015-03-26 07:52:43 -0700123 }
124
Cary Clarkab87d7a2016-10-04 10:01:04 -0400125#if DEBUG_ACTIVE_SPANS
126 void debugShowActiveSpans() {
127 SkOpSegment* segment = &fHead;
128 do {
129 segment->debugShowActiveSpans();
130 } while ((segment = segment->next()));
131 }
132#endif
133
caryclark54359292015-03-26 07:52:43 -0700134 const SkOpSpanBase* debugSpan(int id) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700135 return SkDEBUGRELEASE(this->globalState()->debugSpan(id), nullptr);
caryclark54359292015-03-26 07:52:43 -0700136 }
137
138 SkOpGlobalState* globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700139 return fState;
caryclark54359292015-03-26 07:52:43 -0700140 }
141
142 void debugValidate() const {
143#if DEBUG_VALIDATE
144 const SkOpSegment* segment = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700145 const SkOpSegment* prior = nullptr;
caryclark54359292015-03-26 07:52:43 -0700146 do {
147 segment->debugValidate();
148 SkASSERT(segment->prev() == prior);
149 prior = segment;
150 } while ((segment = segment->next()));
151 SkASSERT(prior == fTail);
152#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000153 }
154
155 bool done() const {
156 return fDone;
157 }
158
caryclark624637c2015-05-11 07:21:27 -0700159 void dump() const;
160 void dumpAll() const;
caryclark54359292015-03-26 07:52:43 -0700161 void dumpAngles() const;
caryclark624637c2015-05-11 07:21:27 -0700162 void dumpContours() const;
163 void dumpContoursAll() const;
164 void dumpContoursAngles() const;
165 void dumpContoursPts() const;
166 void dumpContoursPt(int segmentID) const;
167 void dumpContoursSegment(int segmentID) const;
168 void dumpContoursSpan(int segmentID) const;
169 void dumpContoursSpans() const;
caryclark54359292015-03-26 07:52:43 -0700170 void dumpPt(int ) const;
caryclark26ad22a2015-10-16 09:03:38 -0700171 void dumpPts(const char* prefix = "seg") const;
172 void dumpPtsX(const char* prefix) const;
caryclark54359292015-03-26 07:52:43 -0700173 void dumpSegment(int ) const;
caryclark26ad22a2015-10-16 09:03:38 -0700174 void dumpSegments(const char* prefix = "seg", SkPathOp op = (SkPathOp) -1) const;
caryclark54359292015-03-26 07:52:43 -0700175 void dumpSpan(int ) const;
176 void dumpSpans() const;
177
caryclark@google.com07393ca2013-04-08 11:47:37 +0000178 const SkPoint& end() const {
caryclark54359292015-03-26 07:52:43 -0700179 return fTail->pts()[SkPathOpsVerbToPoints(fTail->verb())];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000180 }
181
caryclark624637c2015-05-11 07:21:27 -0700182 SkOpSpan* findSortableTop(SkOpContour* );
183
caryclark54359292015-03-26 07:52:43 -0700184 SkOpSegment* first() {
185 SkASSERT(fCount > 0);
186 return &fHead;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000187 }
188
caryclark54359292015-03-26 07:52:43 -0700189 const SkOpSegment* first() const {
190 SkASSERT(fCount > 0);
191 return &fHead;
caryclarkdac1d172014-06-17 05:15:38 -0700192 }
193
caryclark624637c2015-05-11 07:21:27 -0700194 void indentDump() const {
195 SkDEBUGCODE(fDebugIndent += 2);
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000196 }
197
caryclark54359292015-03-26 07:52:43 -0700198 void init(SkOpGlobalState* globalState, bool operand, bool isXor) {
199 fState = globalState;
200 fOperand = operand;
201 fXor = isXor;
caryclark1049f122015-04-20 08:31:59 -0700202 SkDEBUGCODE(fID = globalState->nextContourID());
caryclark54359292015-03-26 07:52:43 -0700203 }
204
caryclark5b5ddd72015-05-18 05:12:56 -0700205 int isCcw() const {
206 return fCcw;
207 }
208
caryclark54359292015-03-26 07:52:43 -0700209 bool isXor() const {
210 return fXor;
211 }
212
caryclarkeed356d2016-09-14 07:18:20 -0700213 void joinSegments() {
214 SkOpSegment* segment = &fHead;
215 SkOpSegment* next;
216 do {
217 next = segment->next();
218 segment->joinEnds(next ? next : &fHead);
219 } while ((segment = next));
220 }
221
caryclark55888e42016-07-18 10:01:36 -0700222 void markAllDone() {
caryclark5b5ddd72015-05-18 05:12:56 -0700223 SkOpSegment* segment = &fHead;
224 do {
225 segment->markAllDone();
226 } while ((segment = segment->next()));
227 }
228
caryclark55888e42016-07-18 10:01:36 -0700229 // Please keep this aligned with debugMissingCoincidence()
230 bool missingCoincidence() {
caryclark54359292015-03-26 07:52:43 -0700231 SkASSERT(fCount > 0);
232 SkOpSegment* segment = &fHead;
caryclark27c8eb82015-07-06 11:38:33 -0700233 bool result = false;
caryclark54359292015-03-26 07:52:43 -0700234 do {
235 if (fState->angleCoincidence()) {
caryclark26ad22a2015-10-16 09:03:38 -0700236#if DEBUG_ANGLE
237 segment->debugCheckAngleCoin();
238#endif
caryclark55888e42016-07-18 10:01:36 -0700239 } else if (segment->missingCoincidence()) {
caryclark27c8eb82015-07-06 11:38:33 -0700240 result = true;
caryclark54359292015-03-26 07:52:43 -0700241 }
caryclark27c8eb82015-07-06 11:38:33 -0700242 segment = segment->next();
243 } while (segment);
244 return result;
caryclark54359292015-03-26 07:52:43 -0700245 }
246
caryclark08bc8482015-04-24 09:08:57 -0700247 bool moveMultiples() {
caryclark54359292015-03-26 07:52:43 -0700248 SkASSERT(fCount > 0);
249 SkOpSegment* segment = &fHead;
250 do {
caryclarkd78c0882016-02-24 09:03:07 -0800251 if (!segment->moveMultiples()) {
252 return false;
253 }
caryclark54359292015-03-26 07:52:43 -0700254 } while ((segment = segment->next()));
255 return true;
256 }
257
caryclark08bc8482015-04-24 09:08:57 -0700258 void moveNearby() {
259 SkASSERT(fCount > 0);
260 SkOpSegment* segment = &fHead;
261 do {
262 segment->moveNearby();
263 } while ((segment = segment->next()));
264 }
265
caryclark54359292015-03-26 07:52:43 -0700266 SkOpContour* next() {
267 return fNext;
268 }
269
270 const SkOpContour* next() const {
271 return fNext;
272 }
273
caryclark@google.com07393ca2013-04-08 11:47:37 +0000274 bool operand() const {
275 return fOperand;
276 }
277
caryclark54359292015-03-26 07:52:43 -0700278 bool oppXor() const {
279 return fOppXor;
280 }
281
caryclark624637c2015-05-11 07:21:27 -0700282 void outdentDump() const {
283 SkDEBUGCODE(fDebugIndent -= 2);
caryclark54359292015-03-26 07:52:43 -0700284 }
285
caryclark624637c2015-05-11 07:21:27 -0700286 void rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits, SkChunkAlloc* );
287
caryclark@google.com07393ca2013-04-08 11:47:37 +0000288 void reset() {
halcanary96fcdcc2015-08-27 07:41:13 -0700289 fTail = nullptr;
290 fNext = nullptr;
caryclark54359292015-03-26 07:52:43 -0700291 fCount = 0;
292 fDone = false;
293 SkDEBUGCODE(fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin));
294 SkDEBUGCODE(fFirstSorted = -1);
caryclark624637c2015-05-11 07:21:27 -0700295 SkDEBUGCODE(fDebugIndent = 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000296 }
297
caryclark5b5ddd72015-05-18 05:12:56 -0700298 void resetReverse() {
299 SkOpContour* next = this;
300 do {
301 next->fCcw = -1;
302 next->fReverse = false;
303 } while ((next = next->next()));
304 }
305
306 bool reversed() const {
307 return fReverse;
308 }
309
caryclark54359292015-03-26 07:52:43 -0700310 void setBounds() {
311 SkASSERT(fCount > 0);
312 const SkOpSegment* segment = &fHead;
313 fBounds = segment->bounds();
314 while ((segment = segment->next())) {
315 fBounds.add(segment->bounds());
316 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000317 }
318
caryclark5b5ddd72015-05-18 05:12:56 -0700319 void setCcw(int ccw) {
320 fCcw = ccw;
321 }
322
caryclark54359292015-03-26 07:52:43 -0700323 void setGlobalState(SkOpGlobalState* state) {
324 fState = state;
325 }
326
327 void setNext(SkOpContour* contour) {
328// SkASSERT(!fNext == !!contour);
329 fNext = contour;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000330 }
331
332 void setOperand(bool isOp) {
333 fOperand = isOp;
334 }
335
336 void setOppXor(bool isOppXor) {
337 fOppXor = isOppXor;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000338 }
339
caryclark5b5ddd72015-05-18 05:12:56 -0700340 void setReverse() {
341 fReverse = true;
342 }
343
caryclark@google.com07393ca2013-04-08 11:47:37 +0000344 void setXor(bool isXor) {
345 fXor = isXor;
346 }
347
caryclark54359292015-03-26 07:52:43 -0700348 void sortAngles() {
349 SkASSERT(fCount > 0);
350 SkOpSegment* segment = &fHead;
351 do {
352 segment->sortAngles();
353 } while ((segment = segment->next()));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000354 }
355
caryclark54359292015-03-26 07:52:43 -0700356 const SkPoint& start() const {
357 return fHead.pts()[0];
358 }
reed0dc4dd62015-03-24 13:55:33 -0700359
360 void toPartialBackward(SkPathWriter* path) const {
caryclark54359292015-03-26 07:52:43 -0700361 const SkOpSegment* segment = fTail;
362 do {
caryclarkef784fb2015-10-30 12:03:06 -0700363 SkAssertResult(segment->addCurveTo(segment->tail(), segment->head(), path));
caryclark54359292015-03-26 07:52:43 -0700364 } while ((segment = segment->prev()));
reed0dc4dd62015-03-24 13:55:33 -0700365 }
366
367 void toPartialForward(SkPathWriter* path) const {
caryclark54359292015-03-26 07:52:43 -0700368 const SkOpSegment* segment = &fHead;
369 do {
caryclarkef784fb2015-10-30 12:03:06 -0700370 SkAssertResult(segment->addCurveTo(segment->head(), segment->tail(), path));
caryclark54359292015-03-26 07:52:43 -0700371 } while ((segment = segment->next()));
reed0dc4dd62015-03-24 13:55:33 -0700372 }
373
caryclark5b5ddd72015-05-18 05:12:56 -0700374 void toReversePath(SkPathWriter* path) const;
caryclark54359292015-03-26 07:52:43 -0700375 void toPath(SkPathWriter* path) const;
caryclark54359292015-03-26 07:52:43 -0700376 SkOpSegment* undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000377
caryclark@google.com07393ca2013-04-08 11:47:37 +0000378private:
caryclark54359292015-03-26 07:52:43 -0700379 SkOpGlobalState* fState;
380 SkOpSegment fHead;
381 SkOpSegment* fTail;
382 SkOpContour* fNext;
reed0dc4dd62015-03-24 13:55:33 -0700383 SkPathOpsBounds fBounds;
caryclark5b5ddd72015-05-18 05:12:56 -0700384 int fCcw;
caryclark54359292015-03-26 07:52:43 -0700385 int fCount;
386 int fFirstSorted;
387 bool fDone; // set by find top segment
caryclark@google.com07393ca2013-04-08 11:47:37 +0000388 bool fOperand; // true for the second argument to a binary operator
caryclark5b5ddd72015-05-18 05:12:56 -0700389 bool fReverse; // true if contour should be reverse written to path (used only by fix winding)
caryclark54359292015-03-26 07:52:43 -0700390 bool fXor; // set if original path had even-odd fill
391 bool fOppXor; // set if opposite path had even-odd fill
caryclark1049f122015-04-20 08:31:59 -0700392 SkDEBUGCODE(int fID);
caryclark624637c2015-05-11 07:21:27 -0700393 SkDEBUGCODE(mutable int fDebugIndent);
394};
395
396class SkOpContourHead : public SkOpContour {
caryclarkeed356d2016-09-14 07:18:20 -0700397public:
398 SkOpContour* appendContour() {
399 SkOpContour* contour = SkOpTAllocator<SkOpContour>::New(this->globalState()->allocator());
400 contour->setNext(nullptr);
401 SkOpContour* prev = this;
402 SkOpContour* next;
403 while ((next = prev->next())) {
404 prev = next;
405 }
406 prev->setNext(contour);
407 return contour;
408 }
409
410 void joinAllSegments() {
411 SkOpContour* next = this;
412 do {
413 next->joinSegments();
414 } while ((next = next->next()));
415 }
416
417 void remove(SkOpContour* contour) {
418 if (contour == this) {
419 SkASSERT(this->count() == 0);
420 return;
421 }
422 SkASSERT(contour->next() == nullptr);
423 SkOpContour* prev = this;
424 SkOpContour* next;
425 while ((next = prev->next()) != contour) {
426 SkASSERT(next);
427 prev = next;
428 }
429 SkASSERT(prev);
430 prev->setNext(nullptr);
431 }
432
caryclark@google.com07393ca2013-04-08 11:47:37 +0000433};
434
435#endif