blob: d0e09a3a7045cbea343b412e959b791f57720f6a [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
caryclark54359292015-03-26 07:52:43 -070014class SkChunkAlloc;
caryclark624637c2015-05-11 07:21:27 -070015enum class SkOpRayDir;
16struct SkOpRayHit;
caryclark@google.com07393ca2013-04-08 11:47:37 +000017class SkPathWriter;
18
caryclark@google.com07393ca2013-04-08 11:47:37 +000019class SkOpContour {
20public:
21 SkOpContour() {
22 reset();
caryclark54359292015-03-26 07:52:43 -070023 }
24
25 ~SkOpContour() {
26 if (fNext) {
27 fNext->~SkOpContour();
28 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000029 }
30
31 bool operator<(const SkOpContour& rh) const {
32 return fBounds.fTop == rh.fBounds.fTop
33 ? fBounds.fLeft < rh.fBounds.fLeft
34 : fBounds.fTop < rh.fBounds.fTop;
35 }
36
caryclark27c8eb82015-07-06 11:38:33 -070037 void addAlignIntersections(SkOpContourHead* contourList, SkChunkAlloc* allocator) {
38 SkASSERT(fCount > 0);
39 SkOpSegment* segment = &fHead;
40 do {
41 segment->addAlignIntersections(contourList, allocator);
42 } while ((segment = segment->next()));
43 }
44
caryclark1049f122015-04-20 08:31:59 -070045 void addConic(SkPoint pts[3], SkScalar weight, SkChunkAlloc* allocator) {
46 appendSegment(allocator).addConic(pts, weight, this);
47 }
48
caryclark54359292015-03-26 07:52:43 -070049 void addCubic(SkPoint pts[4], SkChunkAlloc* allocator) {
50 appendSegment(allocator).addCubic(pts, this);
51 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000052
caryclark03b03ca2015-04-23 09:13:37 -070053 SkOpSegment* addCurve(SkPath::Verb verb, const SkPoint pts[4], SkChunkAlloc* allocator);
caryclark54359292015-03-26 07:52:43 -070054
55 void addLine(SkPoint pts[2], SkChunkAlloc* allocator) {
56 appendSegment(allocator).addLine(pts, this);
57 }
58
59 void addQuad(SkPoint pts[3], SkChunkAlloc* allocator) {
60 appendSegment(allocator).addQuad(pts, this);
61 }
62
63 void align() {
64 SkASSERT(fCount > 0);
65 SkOpSegment* segment = &fHead;
66 do {
67 segment->align();
68 } while ((segment = segment->next()));
69 }
70
71 SkOpSegment& appendSegment(SkChunkAlloc* allocator) {
72 SkOpSegment* result = fCount++
73 ? SkOpTAllocator<SkOpSegment>::Allocate(allocator) : &fHead;
74 result->setPrev(fTail);
75 if (fTail) {
76 fTail->setNext(result);
caryclark@google.com07393ca2013-04-08 11:47:37 +000077 }
caryclark54359292015-03-26 07:52:43 -070078 fTail = result;
79 return *result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000080 }
81
caryclark54359292015-03-26 07:52:43 -070082 SkOpContour* appendContour(SkChunkAlloc* allocator) {
83 SkOpContour* contour = SkOpTAllocator<SkOpContour>::New(allocator);
halcanary96fcdcc2015-08-27 07:41:13 -070084 contour->setNext(nullptr);
caryclark54359292015-03-26 07:52:43 -070085 SkOpContour* prev = this;
86 SkOpContour* next;
87 while ((next = prev->next())) {
88 prev = next;
reed0dc4dd62015-03-24 13:55:33 -070089 }
caryclark54359292015-03-26 07:52:43 -070090 prev->setNext(contour);
91 return contour;
reed0dc4dd62015-03-24 13:55:33 -070092 }
caryclark54359292015-03-26 07:52:43 -070093
caryclark@google.com07393ca2013-04-08 11:47:37 +000094 const SkPathOpsBounds& bounds() const {
95 return fBounds;
96 }
97
caryclark54359292015-03-26 07:52:43 -070098 void calcAngles(SkChunkAlloc* allocator) {
99 SkASSERT(fCount > 0);
100 SkOpSegment* segment = &fHead;
101 do {
102 segment->calcAngles(allocator);
103 } while ((segment = segment->next()));
caryclark@google.comfa2aeee2013-07-15 13:29:13 +0000104 }
105
caryclark@google.com07393ca2013-04-08 11:47:37 +0000106 void complete() {
107 setBounds();
caryclark@google.com07393ca2013-04-08 11:47:37 +0000108 }
109
caryclark54359292015-03-26 07:52:43 -0700110 int count() const {
111 return fCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000112 }
113
caryclark54359292015-03-26 07:52:43 -0700114 int debugID() const {
caryclark1049f122015-04-20 08:31:59 -0700115 return SkDEBUGRELEASE(fID, -1);
caryclark54359292015-03-26 07:52:43 -0700116 }
117
118 int debugIndent() const {
caryclark624637c2015-05-11 07:21:27 -0700119 return SkDEBUGRELEASE(fDebugIndent, 0);
caryclark54359292015-03-26 07:52:43 -0700120 }
121
122#if DEBUG_ACTIVE_SPANS
123 void debugShowActiveSpans() {
124 SkOpSegment* segment = &fHead;
125 do {
126 segment->debugShowActiveSpans();
127 } while ((segment = segment->next()));
128 }
129#endif
130
131 const SkOpAngle* debugAngle(int id) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700132 return SkDEBUGRELEASE(this->globalState()->debugAngle(id), nullptr);
caryclark54359292015-03-26 07:52:43 -0700133 }
134
caryclark26ad22a2015-10-16 09:03:38 -0700135 void debugCheckHealth(const char* id, SkPathOpsDebug::GlitchLog* ) const;
136
caryclark54359292015-03-26 07:52:43 -0700137 SkOpContour* debugContour(int id) {
halcanary96fcdcc2015-08-27 07:41:13 -0700138 return SkDEBUGRELEASE(this->globalState()->debugContour(id), nullptr);
caryclark54359292015-03-26 07:52:43 -0700139 }
140
caryclark26ad22a2015-10-16 09:03:38 -0700141 void debugMissingCoincidence(const char* id, SkPathOpsDebug::GlitchLog* log,
142 const SkOpCoincidence* coincidence) const;
143
caryclark54359292015-03-26 07:52:43 -0700144 const SkOpPtT* debugPtT(int id) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700145 return SkDEBUGRELEASE(this->globalState()->debugPtT(id), nullptr);
caryclark54359292015-03-26 07:52:43 -0700146 }
147
148 const SkOpSegment* debugSegment(int id) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700149 return SkDEBUGRELEASE(this->globalState()->debugSegment(id), nullptr);
caryclark54359292015-03-26 07:52:43 -0700150 }
151
152 const SkOpSpanBase* debugSpan(int id) const {
halcanary96fcdcc2015-08-27 07:41:13 -0700153 return SkDEBUGRELEASE(this->globalState()->debugSpan(id), nullptr);
caryclark54359292015-03-26 07:52:43 -0700154 }
155
156 SkOpGlobalState* globalState() const {
157 return fState;
158 }
159
160 void debugValidate() const {
161#if DEBUG_VALIDATE
162 const SkOpSegment* segment = &fHead;
halcanary96fcdcc2015-08-27 07:41:13 -0700163 const SkOpSegment* prior = nullptr;
caryclark54359292015-03-26 07:52:43 -0700164 do {
165 segment->debugValidate();
166 SkASSERT(segment->prev() == prior);
167 prior = segment;
168 } while ((segment = segment->next()));
169 SkASSERT(prior == fTail);
170#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000171 }
172
173 bool done() const {
174 return fDone;
175 }
176
caryclark624637c2015-05-11 07:21:27 -0700177 void dump() const;
178 void dumpAll() const;
caryclark54359292015-03-26 07:52:43 -0700179 void dumpAngles() const;
caryclark624637c2015-05-11 07:21:27 -0700180 void dumpContours() const;
181 void dumpContoursAll() const;
182 void dumpContoursAngles() const;
183 void dumpContoursPts() const;
184 void dumpContoursPt(int segmentID) const;
185 void dumpContoursSegment(int segmentID) const;
186 void dumpContoursSpan(int segmentID) const;
187 void dumpContoursSpans() const;
caryclark54359292015-03-26 07:52:43 -0700188 void dumpPt(int ) const;
caryclark26ad22a2015-10-16 09:03:38 -0700189 void dumpPts(const char* prefix = "seg") const;
190 void dumpPtsX(const char* prefix) const;
caryclark54359292015-03-26 07:52:43 -0700191 void dumpSegment(int ) const;
caryclark26ad22a2015-10-16 09:03:38 -0700192 void dumpSegments(const char* prefix = "seg", SkPathOp op = (SkPathOp) -1) const;
caryclark54359292015-03-26 07:52:43 -0700193 void dumpSpan(int ) const;
194 void dumpSpans() const;
195
caryclark@google.com07393ca2013-04-08 11:47:37 +0000196 const SkPoint& end() const {
caryclark54359292015-03-26 07:52:43 -0700197 return fTail->pts()[SkPathOpsVerbToPoints(fTail->verb())];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000198 }
199
caryclarkd4349722015-07-23 12:40:22 -0700200 bool findCollapsed() {
201 SkASSERT(fCount > 0);
202 SkOpSegment* segment = &fHead;
203 do {
204 segment->findCollapsed();
205 } while ((segment = segment->next()));
206 return true;
207 }
208
caryclark624637c2015-05-11 07:21:27 -0700209 SkOpSpan* findSortableTop(SkOpContour* );
210
caryclark54359292015-03-26 07:52:43 -0700211 SkOpSegment* first() {
212 SkASSERT(fCount > 0);
213 return &fHead;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000214 }
215
caryclark54359292015-03-26 07:52:43 -0700216 const SkOpSegment* first() const {
217 SkASSERT(fCount > 0);
218 return &fHead;
caryclarkdac1d172014-06-17 05:15:38 -0700219 }
220
caryclark624637c2015-05-11 07:21:27 -0700221 void indentDump() const {
222 SkDEBUGCODE(fDebugIndent += 2);
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000223 }
224
caryclark54359292015-03-26 07:52:43 -0700225 void init(SkOpGlobalState* globalState, bool operand, bool isXor) {
226 fState = globalState;
227 fOperand = operand;
228 fXor = isXor;
caryclark1049f122015-04-20 08:31:59 -0700229 SkDEBUGCODE(fID = globalState->nextContourID());
caryclark54359292015-03-26 07:52:43 -0700230 }
231
caryclark5b5ddd72015-05-18 05:12:56 -0700232 int isCcw() const {
233 return fCcw;
234 }
235
caryclark54359292015-03-26 07:52:43 -0700236 bool isXor() const {
237 return fXor;
238 }
239
caryclark5b5ddd72015-05-18 05:12:56 -0700240 void markDone() {
241 SkOpSegment* segment = &fHead;
242 do {
243 segment->markAllDone();
244 } while ((segment = segment->next()));
245 }
246
caryclark27c8eb82015-07-06 11:38:33 -0700247 bool missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocator) {
caryclark54359292015-03-26 07:52:43 -0700248 SkASSERT(fCount > 0);
249 SkOpSegment* segment = &fHead;
caryclark27c8eb82015-07-06 11:38:33 -0700250 bool result = false;
caryclark54359292015-03-26 07:52:43 -0700251 do {
252 if (fState->angleCoincidence()) {
caryclark26ad22a2015-10-16 09:03:38 -0700253#if DEBUG_ANGLE
254 segment->debugCheckAngleCoin();
255#endif
caryclark27c8eb82015-07-06 11:38:33 -0700256 } else if (segment->missingCoincidence(coincidences, allocator)) {
257 result = true;
258 // FIXME: trying again loops forever in issue3651_6
259 // The continue below is speculative -- once there's an actual case that requires it,
260 // add the plumbing necessary to look for another missing coincidence in the same segment
261 // continue; // try again in case another missing coincidence is further along
caryclark54359292015-03-26 07:52:43 -0700262 }
caryclark27c8eb82015-07-06 11:38:33 -0700263 segment = segment->next();
264 } while (segment);
265 return result;
caryclark54359292015-03-26 07:52:43 -0700266 }
267
caryclark08bc8482015-04-24 09:08:57 -0700268 bool moveMultiples() {
caryclark54359292015-03-26 07:52:43 -0700269 SkASSERT(fCount > 0);
270 SkOpSegment* segment = &fHead;
271 do {
caryclark08bc8482015-04-24 09:08:57 -0700272 segment->moveMultiples();
caryclark54359292015-03-26 07:52:43 -0700273 } while ((segment = segment->next()));
274 return true;
275 }
276
caryclark08bc8482015-04-24 09:08:57 -0700277 void moveNearby() {
278 SkASSERT(fCount > 0);
279 SkOpSegment* segment = &fHead;
280 do {
281 segment->moveNearby();
282 } while ((segment = segment->next()));
283 }
284
caryclark54359292015-03-26 07:52:43 -0700285 SkOpContour* next() {
286 return fNext;
287 }
288
289 const SkOpContour* next() const {
290 return fNext;
291 }
292
caryclark@google.com07393ca2013-04-08 11:47:37 +0000293 bool operand() const {
294 return fOperand;
295 }
296
caryclark54359292015-03-26 07:52:43 -0700297 bool oppXor() const {
298 return fOppXor;
299 }
300
caryclark624637c2015-05-11 07:21:27 -0700301 void outdentDump() const {
302 SkDEBUGCODE(fDebugIndent -= 2);
caryclark54359292015-03-26 07:52:43 -0700303 }
304
caryclark624637c2015-05-11 07:21:27 -0700305 void rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits, SkChunkAlloc* );
306
caryclark54359292015-03-26 07:52:43 -0700307 void remove(SkOpContour* contour) {
308 if (contour == this) {
309 SkASSERT(fCount == 0);
310 return;
311 }
halcanary96fcdcc2015-08-27 07:41:13 -0700312 SkASSERT(contour->fNext == nullptr);
caryclark54359292015-03-26 07:52:43 -0700313 SkOpContour* prev = this;
314 SkOpContour* next;
315 while ((next = prev->next()) != contour) {
316 SkASSERT(next);
317 prev = next;
318 }
319 SkASSERT(prev);
halcanary96fcdcc2015-08-27 07:41:13 -0700320 prev->setNext(nullptr);
caryclark54359292015-03-26 07:52:43 -0700321 }
322
caryclark@google.com07393ca2013-04-08 11:47:37 +0000323 void reset() {
halcanary96fcdcc2015-08-27 07:41:13 -0700324 fTail = nullptr;
325 fNext = nullptr;
caryclark54359292015-03-26 07:52:43 -0700326 fCount = 0;
327 fDone = false;
328 SkDEBUGCODE(fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin));
329 SkDEBUGCODE(fFirstSorted = -1);
caryclark624637c2015-05-11 07:21:27 -0700330 SkDEBUGCODE(fDebugIndent = 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000331 }
332
caryclark5b5ddd72015-05-18 05:12:56 -0700333 void resetReverse() {
334 SkOpContour* next = this;
335 do {
336 next->fCcw = -1;
337 next->fReverse = false;
338 } while ((next = next->next()));
339 }
340
341 bool reversed() const {
342 return fReverse;
343 }
344
caryclark54359292015-03-26 07:52:43 -0700345 void setBounds() {
346 SkASSERT(fCount > 0);
347 const SkOpSegment* segment = &fHead;
348 fBounds = segment->bounds();
349 while ((segment = segment->next())) {
350 fBounds.add(segment->bounds());
351 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000352 }
353
caryclark5b5ddd72015-05-18 05:12:56 -0700354 void setCcw(int ccw) {
355 fCcw = ccw;
356 }
357
caryclark54359292015-03-26 07:52:43 -0700358 void setGlobalState(SkOpGlobalState* state) {
359 fState = state;
360 }
361
362 void setNext(SkOpContour* contour) {
363// SkASSERT(!fNext == !!contour);
364 fNext = contour;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000365 }
366
367 void setOperand(bool isOp) {
368 fOperand = isOp;
369 }
370
371 void setOppXor(bool isOppXor) {
372 fOppXor = isOppXor;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000373 }
374
caryclark5b5ddd72015-05-18 05:12:56 -0700375 void setReverse() {
376 fReverse = true;
377 }
378
caryclark@google.com07393ca2013-04-08 11:47:37 +0000379 void setXor(bool isXor) {
380 fXor = isXor;
381 }
382
caryclark54359292015-03-26 07:52:43 -0700383 SkPath::Verb simplifyCubic(SkPoint pts[4]);
caryclarkccec0f92015-03-24 07:28:17 -0700384
caryclark54359292015-03-26 07:52:43 -0700385 void sortAngles() {
386 SkASSERT(fCount > 0);
387 SkOpSegment* segment = &fHead;
388 do {
389 segment->sortAngles();
390 } while ((segment = segment->next()));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000391 }
392
caryclark54359292015-03-26 07:52:43 -0700393 const SkPoint& start() const {
394 return fHead.pts()[0];
395 }
reed0dc4dd62015-03-24 13:55:33 -0700396
397 void toPartialBackward(SkPathWriter* path) const {
caryclark54359292015-03-26 07:52:43 -0700398 const SkOpSegment* segment = fTail;
399 do {
caryclarkef784fb2015-10-30 12:03:06 -0700400 SkAssertResult(segment->addCurveTo(segment->tail(), segment->head(), path));
caryclark54359292015-03-26 07:52:43 -0700401 } while ((segment = segment->prev()));
reed0dc4dd62015-03-24 13:55:33 -0700402 }
403
404 void toPartialForward(SkPathWriter* path) const {
caryclark54359292015-03-26 07:52:43 -0700405 const SkOpSegment* segment = &fHead;
406 do {
caryclarkef784fb2015-10-30 12:03:06 -0700407 SkAssertResult(segment->addCurveTo(segment->head(), segment->tail(), path));
caryclark54359292015-03-26 07:52:43 -0700408 } while ((segment = segment->next()));
reed0dc4dd62015-03-24 13:55:33 -0700409 }
410
caryclark5b5ddd72015-05-18 05:12:56 -0700411 void toReversePath(SkPathWriter* path) const;
caryclark54359292015-03-26 07:52:43 -0700412 void toPath(SkPathWriter* path) const;
caryclark54359292015-03-26 07:52:43 -0700413 SkOpSegment* undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000414
caryclark@google.com07393ca2013-04-08 11:47:37 +0000415private:
caryclark54359292015-03-26 07:52:43 -0700416 SkOpGlobalState* fState;
417 SkOpSegment fHead;
418 SkOpSegment* fTail;
419 SkOpContour* fNext;
reed0dc4dd62015-03-24 13:55:33 -0700420 SkPathOpsBounds fBounds;
caryclark5b5ddd72015-05-18 05:12:56 -0700421 int fCcw;
caryclark54359292015-03-26 07:52:43 -0700422 int fCount;
423 int fFirstSorted;
424 bool fDone; // set by find top segment
caryclark@google.com07393ca2013-04-08 11:47:37 +0000425 bool fOperand; // true for the second argument to a binary operator
caryclark5b5ddd72015-05-18 05:12:56 -0700426 bool fReverse; // true if contour should be reverse written to path (used only by fix winding)
caryclark54359292015-03-26 07:52:43 -0700427 bool fXor; // set if original path had even-odd fill
428 bool fOppXor; // set if opposite path had even-odd fill
caryclark1049f122015-04-20 08:31:59 -0700429 SkDEBUGCODE(int fID);
caryclark624637c2015-05-11 07:21:27 -0700430 SkDEBUGCODE(mutable int fDebugIndent);
431};
432
433class SkOpContourHead : public SkOpContour {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000434};
435
436#endif