blob: 17effc619708cbb7cfc48ff13af30048b0849c67 [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
caryclark@google.com07393ca2013-04-08 11:47:37 +000024 bool operator<(const SkOpContour& rh) const {
25 return fBounds.fTop == rh.fBounds.fTop
caryclark55888e42016-07-18 10:01:36 -070026 ? fBounds.fLeft < rh.fBounds.fLeft
27 : fBounds.fTop < rh.fBounds.fTop;
caryclark@google.com07393ca2013-04-08 11:47:37 +000028 }
29
caryclark55888e42016-07-18 10:01:36 -070030 void addConic(SkPoint pts[3], SkScalar weight) {
31 appendSegment().addConic(pts, weight, this);
caryclark27c8eb82015-07-06 11:38:33 -070032 }
33
caryclark55888e42016-07-18 10:01:36 -070034 void addCubic(SkPoint pts[4]) {
35 appendSegment().addCubic(pts, this);
caryclark1049f122015-04-20 08:31:59 -070036 }
37
caryclark55888e42016-07-18 10:01:36 -070038 SkOpSegment* addLine(SkPoint pts[2]) {
caryclarkbb51f4a2016-08-23 07:38:48 -070039 SkASSERT(pts[0] != pts[1]);
caryclark55888e42016-07-18 10:01:36 -070040 return appendSegment().addLine(pts, this);
caryclark54359292015-03-26 07:52:43 -070041 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000042
caryclark55888e42016-07-18 10:01:36 -070043 void addQuad(SkPoint pts[3]) {
44 appendSegment().addQuad(pts, this);
caryclark54359292015-03-26 07:52:43 -070045 }
46
caryclark55888e42016-07-18 10:01:36 -070047 SkOpSegment& appendSegment() {
Herb Derbyecc364c2017-04-19 15:09:48 -040048 SkOpSegment* result = fCount++ ? this->globalState()->allocator()->make<SkOpSegment>()
49 : &fHead;
caryclark54359292015-03-26 07:52:43 -070050 result->setPrev(fTail);
51 if (fTail) {
52 fTail->setNext(result);
caryclark@google.com07393ca2013-04-08 11:47:37 +000053 }
caryclark54359292015-03-26 07:52:43 -070054 fTail = result;
55 return *result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000056 }
57
caryclark@google.com07393ca2013-04-08 11:47:37 +000058 const SkPathOpsBounds& bounds() const {
59 return fBounds;
60 }
61
caryclark55888e42016-07-18 10:01:36 -070062 void calcAngles() {
caryclark54359292015-03-26 07:52:43 -070063 SkASSERT(fCount > 0);
64 SkOpSegment* segment = &fHead;
65 do {
caryclark55888e42016-07-18 10:01:36 -070066 segment->calcAngles();
caryclark54359292015-03-26 07:52:43 -070067 } while ((segment = segment->next()));
caryclark@google.comfa2aeee2013-07-15 13:29:13 +000068 }
69
caryclark@google.com07393ca2013-04-08 11:47:37 +000070 void complete() {
71 setBounds();
caryclark@google.com07393ca2013-04-08 11:47:37 +000072 }
73
caryclark54359292015-03-26 07:52:43 -070074 int count() const {
75 return fCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +000076 }
77
caryclark54359292015-03-26 07:52:43 -070078 int debugID() const {
caryclark1049f122015-04-20 08:31:59 -070079 return SkDEBUGRELEASE(fID, -1);
caryclark54359292015-03-26 07:52:43 -070080 }
81
82 int debugIndent() const {
caryclark624637c2015-05-11 07:21:27 -070083 return SkDEBUGRELEASE(fDebugIndent, 0);
caryclark54359292015-03-26 07:52:43 -070084 }
85
caryclark54359292015-03-26 07:52:43 -070086
87 const SkOpAngle* debugAngle(int id) const {
halcanary96fcdcc2015-08-27 07:41:13 -070088 return SkDEBUGRELEASE(this->globalState()->debugAngle(id), nullptr);
caryclark54359292015-03-26 07:52:43 -070089 }
90
caryclark55888e42016-07-18 10:01:36 -070091 const SkOpCoincidence* debugCoincidence() const {
92 return this->globalState()->coincidence();
93 }
94
Cary Clarkab87d7a2016-10-04 10:01:04 -040095#if DEBUG_COIN
96 void debugCheckHealth(SkPathOpsDebug::GlitchLog* ) const;
caryclark55888e42016-07-18 10:01:36 -070097#endif
caryclark26ad22a2015-10-16 09:03:38 -070098
caryclark30b9fdd2016-08-31 14:36:29 -070099 SkOpContour* debugContour(int id) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700100 return SkDEBUGRELEASE(this->globalState()->debugContour(id), nullptr);
caryclark54359292015-03-26 07:52:43 -0700101 }
102
Cary Clarkab87d7a2016-10-04 10:01:04 -0400103#if DEBUG_COIN
104 void debugMissingCoincidence(SkPathOpsDebug::GlitchLog* log) const;
105 void debugMoveMultiples(SkPathOpsDebug::GlitchLog* ) const;
106 void debugMoveNearby(SkPathOpsDebug::GlitchLog* log) const;
caryclark55888e42016-07-18 10:01:36 -0700107#endif
caryclark26ad22a2015-10-16 09:03:38 -0700108
caryclark54359292015-03-26 07:52:43 -0700109 const SkOpPtT* debugPtT(int id) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700110 return SkDEBUGRELEASE(this->globalState()->debugPtT(id), nullptr);
caryclark54359292015-03-26 07:52:43 -0700111 }
112
113 const SkOpSegment* debugSegment(int id) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700114 return SkDEBUGRELEASE(this->globalState()->debugSegment(id), nullptr);
caryclark54359292015-03-26 07:52:43 -0700115 }
116
Cary Clarkab87d7a2016-10-04 10:01:04 -0400117#if DEBUG_ACTIVE_SPANS
Cary Clarkff114282016-12-14 11:56:16 -0500118 void debugShowActiveSpans(SkString* str) {
Cary Clarkab87d7a2016-10-04 10:01:04 -0400119 SkOpSegment* segment = &fHead;
120 do {
Cary Clarkff114282016-12-14 11:56:16 -0500121 segment->debugShowActiveSpans(str);
Cary Clarkab87d7a2016-10-04 10:01:04 -0400122 } while ((segment = segment->next()));
123 }
124#endif
125
caryclark54359292015-03-26 07:52:43 -0700126 const SkOpSpanBase* debugSpan(int id) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700127 return SkDEBUGRELEASE(this->globalState()->debugSpan(id), nullptr);
caryclark54359292015-03-26 07:52:43 -0700128 }
129
130 SkOpGlobalState* globalState() const {
caryclark55888e42016-07-18 10:01:36 -0700131 return fState;
caryclark54359292015-03-26 07:52:43 -0700132 }
133
134 void debugValidate() const {
135#if DEBUG_VALIDATE
136 const SkOpSegment* segment = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700137 const SkOpSegment* prior = nullptr;
caryclark54359292015-03-26 07:52:43 -0700138 do {
139 segment->debugValidate();
140 SkASSERT(segment->prev() == prior);
141 prior = segment;
142 } while ((segment = segment->next()));
143 SkASSERT(prior == fTail);
144#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000145 }
146
147 bool done() const {
148 return fDone;
149 }
150
caryclark624637c2015-05-11 07:21:27 -0700151 void dump() const;
152 void dumpAll() const;
caryclark54359292015-03-26 07:52:43 -0700153 void dumpAngles() const;
caryclark624637c2015-05-11 07:21:27 -0700154 void dumpContours() const;
155 void dumpContoursAll() const;
156 void dumpContoursAngles() const;
157 void dumpContoursPts() const;
158 void dumpContoursPt(int segmentID) const;
159 void dumpContoursSegment(int segmentID) const;
160 void dumpContoursSpan(int segmentID) const;
161 void dumpContoursSpans() const;
caryclark54359292015-03-26 07:52:43 -0700162 void dumpPt(int ) const;
caryclark26ad22a2015-10-16 09:03:38 -0700163 void dumpPts(const char* prefix = "seg") const;
164 void dumpPtsX(const char* prefix) const;
caryclark54359292015-03-26 07:52:43 -0700165 void dumpSegment(int ) const;
caryclark26ad22a2015-10-16 09:03:38 -0700166 void dumpSegments(const char* prefix = "seg", SkPathOp op = (SkPathOp) -1) const;
caryclark54359292015-03-26 07:52:43 -0700167 void dumpSpan(int ) const;
168 void dumpSpans() const;
169
caryclark@google.com07393ca2013-04-08 11:47:37 +0000170 const SkPoint& end() const {
caryclark54359292015-03-26 07:52:43 -0700171 return fTail->pts()[SkPathOpsVerbToPoints(fTail->verb())];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000172 }
173
caryclark624637c2015-05-11 07:21:27 -0700174 SkOpSpan* findSortableTop(SkOpContour* );
175
caryclark54359292015-03-26 07:52:43 -0700176 SkOpSegment* first() {
177 SkASSERT(fCount > 0);
178 return &fHead;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000179 }
180
caryclark54359292015-03-26 07:52:43 -0700181 const SkOpSegment* first() const {
182 SkASSERT(fCount > 0);
183 return &fHead;
caryclarkdac1d172014-06-17 05:15:38 -0700184 }
185
caryclark624637c2015-05-11 07:21:27 -0700186 void indentDump() const {
187 SkDEBUGCODE(fDebugIndent += 2);
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000188 }
189
caryclark54359292015-03-26 07:52:43 -0700190 void init(SkOpGlobalState* globalState, bool operand, bool isXor) {
191 fState = globalState;
192 fOperand = operand;
193 fXor = isXor;
caryclark1049f122015-04-20 08:31:59 -0700194 SkDEBUGCODE(fID = globalState->nextContourID());
caryclark54359292015-03-26 07:52:43 -0700195 }
196
caryclark5b5ddd72015-05-18 05:12:56 -0700197 int isCcw() const {
198 return fCcw;
199 }
200
caryclark54359292015-03-26 07:52:43 -0700201 bool isXor() const {
202 return fXor;
203 }
204
caryclarkeed356d2016-09-14 07:18:20 -0700205 void joinSegments() {
206 SkOpSegment* segment = &fHead;
207 SkOpSegment* next;
208 do {
209 next = segment->next();
210 segment->joinEnds(next ? next : &fHead);
211 } while ((segment = next));
212 }
213
caryclark55888e42016-07-18 10:01:36 -0700214 void markAllDone() {
caryclark5b5ddd72015-05-18 05:12:56 -0700215 SkOpSegment* segment = &fHead;
216 do {
217 segment->markAllDone();
218 } while ((segment = segment->next()));
219 }
220
caryclark55888e42016-07-18 10:01:36 -0700221 // Please keep this aligned with debugMissingCoincidence()
222 bool missingCoincidence() {
caryclark54359292015-03-26 07:52:43 -0700223 SkASSERT(fCount > 0);
224 SkOpSegment* segment = &fHead;
caryclark27c8eb82015-07-06 11:38:33 -0700225 bool result = false;
caryclark54359292015-03-26 07:52:43 -0700226 do {
Cary Clarke47ae292016-10-05 08:51:39 -0400227 if (segment->missingCoincidence()) {
caryclark27c8eb82015-07-06 11:38:33 -0700228 result = true;
caryclark54359292015-03-26 07:52:43 -0700229 }
caryclark27c8eb82015-07-06 11:38:33 -0700230 segment = segment->next();
231 } while (segment);
232 return result;
caryclark54359292015-03-26 07:52:43 -0700233 }
234
caryclark08bc8482015-04-24 09:08:57 -0700235 bool moveMultiples() {
caryclark54359292015-03-26 07:52:43 -0700236 SkASSERT(fCount > 0);
237 SkOpSegment* segment = &fHead;
238 do {
caryclarkd78c0882016-02-24 09:03:07 -0800239 if (!segment->moveMultiples()) {
240 return false;
241 }
caryclark54359292015-03-26 07:52:43 -0700242 } while ((segment = segment->next()));
243 return true;
244 }
245
Cary Clark28da2832017-03-21 10:30:50 -0400246 bool moveNearby() {
caryclark08bc8482015-04-24 09:08:57 -0700247 SkASSERT(fCount > 0);
248 SkOpSegment* segment = &fHead;
249 do {
Cary Clark28da2832017-03-21 10:30:50 -0400250 if (!segment->moveNearby()) {
251 return false;
252 }
caryclark08bc8482015-04-24 09:08:57 -0700253 } while ((segment = segment->next()));
Cary Clark28da2832017-03-21 10:30:50 -0400254 return true;
caryclark08bc8482015-04-24 09:08:57 -0700255 }
256
caryclark54359292015-03-26 07:52:43 -0700257 SkOpContour* next() {
258 return fNext;
259 }
260
261 const SkOpContour* next() const {
262 return fNext;
263 }
264
caryclark@google.com07393ca2013-04-08 11:47:37 +0000265 bool operand() const {
266 return fOperand;
267 }
268
caryclark54359292015-03-26 07:52:43 -0700269 bool oppXor() const {
270 return fOppXor;
271 }
272
caryclark624637c2015-05-11 07:21:27 -0700273 void outdentDump() const {
274 SkDEBUGCODE(fDebugIndent -= 2);
caryclark54359292015-03-26 07:52:43 -0700275 }
276
Herb Derbyc3cc5fa2017-03-07 11:11:47 -0500277 void rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits, SkArenaAlloc*);
caryclark624637c2015-05-11 07:21:27 -0700278
caryclark@google.com07393ca2013-04-08 11:47:37 +0000279 void reset() {
halcanary96fcdcc2015-08-27 07:41:13 -0700280 fTail = nullptr;
281 fNext = nullptr;
caryclark54359292015-03-26 07:52:43 -0700282 fCount = 0;
283 fDone = false;
284 SkDEBUGCODE(fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin));
285 SkDEBUGCODE(fFirstSorted = -1);
caryclark624637c2015-05-11 07:21:27 -0700286 SkDEBUGCODE(fDebugIndent = 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000287 }
288
caryclark5b5ddd72015-05-18 05:12:56 -0700289 void resetReverse() {
290 SkOpContour* next = this;
291 do {
Cary Clark9c16d1e2016-12-19 11:16:36 -0500292 if (!next->count()) {
293 continue;
294 }
caryclark5b5ddd72015-05-18 05:12:56 -0700295 next->fCcw = -1;
296 next->fReverse = false;
297 } while ((next = next->next()));
298 }
299
300 bool reversed() const {
301 return fReverse;
302 }
303
caryclark54359292015-03-26 07:52:43 -0700304 void setBounds() {
305 SkASSERT(fCount > 0);
306 const SkOpSegment* segment = &fHead;
307 fBounds = segment->bounds();
308 while ((segment = segment->next())) {
309 fBounds.add(segment->bounds());
310 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000311 }
312
caryclark5b5ddd72015-05-18 05:12:56 -0700313 void setCcw(int ccw) {
314 fCcw = ccw;
315 }
316
caryclark54359292015-03-26 07:52:43 -0700317 void setGlobalState(SkOpGlobalState* state) {
318 fState = state;
319 }
320
321 void setNext(SkOpContour* contour) {
322// SkASSERT(!fNext == !!contour);
323 fNext = contour;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000324 }
325
326 void setOperand(bool isOp) {
327 fOperand = isOp;
328 }
329
330 void setOppXor(bool isOppXor) {
331 fOppXor = isOppXor;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000332 }
333
caryclark5b5ddd72015-05-18 05:12:56 -0700334 void setReverse() {
335 fReverse = true;
336 }
337
caryclark@google.com07393ca2013-04-08 11:47:37 +0000338 void setXor(bool isXor) {
339 fXor = isXor;
340 }
341
caryclarkb36a3cd2016-10-18 07:59:44 -0700342 bool sortAngles() {
caryclark54359292015-03-26 07:52:43 -0700343 SkASSERT(fCount > 0);
344 SkOpSegment* segment = &fHead;
345 do {
caryclarkb36a3cd2016-10-18 07:59:44 -0700346 FAIL_IF(!segment->sortAngles());
caryclark54359292015-03-26 07:52:43 -0700347 } while ((segment = segment->next()));
caryclarkb36a3cd2016-10-18 07:59:44 -0700348 return true;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000349 }
350
caryclark54359292015-03-26 07:52:43 -0700351 const SkPoint& start() const {
352 return fHead.pts()[0];
353 }
reed0dc4dd62015-03-24 13:55:33 -0700354
355 void toPartialBackward(SkPathWriter* path) const {
caryclark54359292015-03-26 07:52:43 -0700356 const SkOpSegment* segment = fTail;
357 do {
caryclarkef784fb2015-10-30 12:03:06 -0700358 SkAssertResult(segment->addCurveTo(segment->tail(), segment->head(), path));
caryclark54359292015-03-26 07:52:43 -0700359 } while ((segment = segment->prev()));
reed0dc4dd62015-03-24 13:55:33 -0700360 }
361
362 void toPartialForward(SkPathWriter* path) const {
caryclark54359292015-03-26 07:52:43 -0700363 const SkOpSegment* segment = &fHead;
364 do {
caryclarkef784fb2015-10-30 12:03:06 -0700365 SkAssertResult(segment->addCurveTo(segment->head(), segment->tail(), path));
caryclark54359292015-03-26 07:52:43 -0700366 } while ((segment = segment->next()));
reed0dc4dd62015-03-24 13:55:33 -0700367 }
368
caryclark5b5ddd72015-05-18 05:12:56 -0700369 void toReversePath(SkPathWriter* path) const;
caryclark54359292015-03-26 07:52:43 -0700370 void toPath(SkPathWriter* path) const;
Cary Clarkab2d73b2016-12-16 17:17:25 -0500371 SkOpSpan* undoneSpan();
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000372
Cary Clarkff114282016-12-14 11:56:16 -0500373protected:
caryclark54359292015-03-26 07:52:43 -0700374 SkOpGlobalState* fState;
375 SkOpSegment fHead;
376 SkOpSegment* fTail;
377 SkOpContour* fNext;
reed0dc4dd62015-03-24 13:55:33 -0700378 SkPathOpsBounds fBounds;
caryclark5b5ddd72015-05-18 05:12:56 -0700379 int fCcw;
caryclark54359292015-03-26 07:52:43 -0700380 int fCount;
381 int fFirstSorted;
382 bool fDone; // set by find top segment
caryclark@google.com07393ca2013-04-08 11:47:37 +0000383 bool fOperand; // true for the second argument to a binary operator
caryclark5b5ddd72015-05-18 05:12:56 -0700384 bool fReverse; // true if contour should be reverse written to path (used only by fix winding)
caryclark54359292015-03-26 07:52:43 -0700385 bool fXor; // set if original path had even-odd fill
386 bool fOppXor; // set if opposite path had even-odd fill
caryclark1049f122015-04-20 08:31:59 -0700387 SkDEBUGCODE(int fID);
caryclark624637c2015-05-11 07:21:27 -0700388 SkDEBUGCODE(mutable int fDebugIndent);
389};
390
391class SkOpContourHead : public SkOpContour {
caryclarkeed356d2016-09-14 07:18:20 -0700392public:
393 SkOpContour* appendContour() {
Herb Derbyecc364c2017-04-19 15:09:48 -0400394 SkOpContour* contour = this->globalState()->allocator()->make<SkOpContour>();
caryclarkeed356d2016-09-14 07:18:20 -0700395 contour->setNext(nullptr);
396 SkOpContour* prev = this;
397 SkOpContour* next;
398 while ((next = prev->next())) {
399 prev = next;
400 }
401 prev->setNext(contour);
402 return contour;
403 }
404
405 void joinAllSegments() {
406 SkOpContour* next = this;
407 do {
Cary Clark9c16d1e2016-12-19 11:16:36 -0500408 if (!next->count()) {
409 continue;
410 }
caryclarkeed356d2016-09-14 07:18:20 -0700411 next->joinSegments();
412 } while ((next = next->next()));
413 }
414
415 void remove(SkOpContour* contour) {
416 if (contour == this) {
417 SkASSERT(this->count() == 0);
418 return;
419 }
420 SkASSERT(contour->next() == nullptr);
421 SkOpContour* prev = this;
422 SkOpContour* next;
423 while ((next = prev->next()) != contour) {
424 SkASSERT(next);
425 prev = next;
426 }
427 SkASSERT(prev);
428 prev->setNext(nullptr);
429 }
430
caryclark@google.com07393ca2013-04-08 11:47:37 +0000431};
432
Cary Clarkff114282016-12-14 11:56:16 -0500433class SkOpContourBuilder {
434public:
435 SkOpContourBuilder(SkOpContour* contour)
436 : fContour(contour)
437 , fLastIsLine(false) {
438 }
439
440 void addConic(SkPoint pts[3], SkScalar weight);
441 void addCubic(SkPoint pts[4]);
442 void addCurve(SkPath::Verb verb, const SkPoint pts[4], SkScalar weight = 1);
443 void addLine(const SkPoint pts[2]);
444 void addQuad(SkPoint pts[3]);
445 void flush();
446 SkOpContour* contour() { return fContour; }
447 void setContour(SkOpContour* contour) { flush(); fContour = contour; }
448protected:
449 SkOpContour* fContour;
450 SkPoint fLastLine[2];
451 bool fLastIsLine;
452};
453
caryclark@google.com07393ca2013-04-08 11:47:37 +0000454#endif