blob: 184ee92ddffd96d619a7833fe058c19619ef260a [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;
caryclark@google.com07393ca2013-04-08 11:47:37 +000015class SkPathWriter;
16
caryclark@google.com07393ca2013-04-08 11:47:37 +000017class SkOpContour {
18public:
19 SkOpContour() {
20 reset();
caryclark54359292015-03-26 07:52:43 -070021 }
22
23 ~SkOpContour() {
24 if (fNext) {
25 fNext->~SkOpContour();
26 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000027 }
28
29 bool operator<(const SkOpContour& rh) const {
30 return fBounds.fTop == rh.fBounds.fTop
31 ? fBounds.fLeft < rh.fBounds.fLeft
32 : fBounds.fTop < rh.fBounds.fTop;
33 }
34
caryclark1049f122015-04-20 08:31:59 -070035 void addConic(SkPoint pts[3], SkScalar weight, SkChunkAlloc* allocator) {
36 appendSegment(allocator).addConic(pts, weight, this);
37 }
38
caryclark54359292015-03-26 07:52:43 -070039 void addCubic(SkPoint pts[4], SkChunkAlloc* allocator) {
40 appendSegment(allocator).addCubic(pts, this);
41 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000042
caryclark54359292015-03-26 07:52:43 -070043 void addCurve(SkPath::Verb verb, const SkPoint pts[4], SkChunkAlloc* allocator);
44
45 void addLine(SkPoint pts[2], SkChunkAlloc* allocator) {
46 appendSegment(allocator).addLine(pts, this);
47 }
48
49 void addQuad(SkPoint pts[3], SkChunkAlloc* allocator) {
50 appendSegment(allocator).addQuad(pts, this);
51 }
52
53 void align() {
54 SkASSERT(fCount > 0);
55 SkOpSegment* segment = &fHead;
56 do {
57 segment->align();
58 } while ((segment = segment->next()));
59 }
60
61 SkOpSegment& appendSegment(SkChunkAlloc* allocator) {
62 SkOpSegment* result = fCount++
63 ? SkOpTAllocator<SkOpSegment>::Allocate(allocator) : &fHead;
64 result->setPrev(fTail);
65 if (fTail) {
66 fTail->setNext(result);
caryclark@google.com07393ca2013-04-08 11:47:37 +000067 }
caryclark54359292015-03-26 07:52:43 -070068 fTail = result;
69 return *result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000070 }
71
caryclark54359292015-03-26 07:52:43 -070072 SkOpContour* appendContour(SkChunkAlloc* allocator) {
73 SkOpContour* contour = SkOpTAllocator<SkOpContour>::New(allocator);
74 contour->setNext(NULL);
75 SkOpContour* prev = this;
76 SkOpContour* next;
77 while ((next = prev->next())) {
78 prev = next;
reed0dc4dd62015-03-24 13:55:33 -070079 }
caryclark54359292015-03-26 07:52:43 -070080 prev->setNext(contour);
81 return contour;
reed0dc4dd62015-03-24 13:55:33 -070082 }
caryclark54359292015-03-26 07:52:43 -070083
caryclark@google.com07393ca2013-04-08 11:47:37 +000084 const SkPathOpsBounds& bounds() const {
85 return fBounds;
86 }
87
caryclark54359292015-03-26 07:52:43 -070088 void calcAngles(SkChunkAlloc* allocator) {
89 SkASSERT(fCount > 0);
90 SkOpSegment* segment = &fHead;
91 do {
92 segment->calcAngles(allocator);
93 } while ((segment = segment->next()));
caryclark@google.comfa2aeee2013-07-15 13:29:13 +000094 }
95
caryclark@google.com07393ca2013-04-08 11:47:37 +000096 void complete() {
97 setBounds();
caryclark@google.com07393ca2013-04-08 11:47:37 +000098 }
99
caryclark54359292015-03-26 07:52:43 -0700100 int count() const {
101 return fCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000102 }
103
caryclark54359292015-03-26 07:52:43 -0700104 int debugID() const {
caryclark1049f122015-04-20 08:31:59 -0700105 return SkDEBUGRELEASE(fID, -1);
caryclark54359292015-03-26 07:52:43 -0700106 }
107
108 int debugIndent() const {
caryclark1049f122015-04-20 08:31:59 -0700109 return SkDEBUGRELEASE(fIndent, 0);
caryclark54359292015-03-26 07:52:43 -0700110 }
111
112#if DEBUG_ACTIVE_SPANS
113 void debugShowActiveSpans() {
114 SkOpSegment* segment = &fHead;
115 do {
116 segment->debugShowActiveSpans();
117 } while ((segment = segment->next()));
118 }
119#endif
120
121 const SkOpAngle* debugAngle(int id) const {
caryclark1049f122015-04-20 08:31:59 -0700122 return SkDEBUGRELEASE(globalState()->debugAngle(id), NULL);
caryclark54359292015-03-26 07:52:43 -0700123 }
124
125 SkOpContour* debugContour(int id) {
caryclark1049f122015-04-20 08:31:59 -0700126 return SkDEBUGRELEASE(globalState()->debugContour(id), NULL);
caryclark54359292015-03-26 07:52:43 -0700127 }
128
129 const SkOpPtT* debugPtT(int id) const {
caryclark1049f122015-04-20 08:31:59 -0700130 return SkDEBUGRELEASE(globalState()->debugPtT(id), NULL);
caryclark54359292015-03-26 07:52:43 -0700131 }
132
133 const SkOpSegment* debugSegment(int id) const {
caryclark1049f122015-04-20 08:31:59 -0700134 return SkDEBUGRELEASE(globalState()->debugSegment(id), NULL);
caryclark54359292015-03-26 07:52:43 -0700135 }
136
137 const SkOpSpanBase* debugSpan(int id) const {
caryclark1049f122015-04-20 08:31:59 -0700138 return SkDEBUGRELEASE(globalState()->debugSpan(id), NULL);
caryclark54359292015-03-26 07:52:43 -0700139 }
140
141 SkOpGlobalState* globalState() const {
142 return fState;
143 }
144
145 void debugValidate() const {
146#if DEBUG_VALIDATE
147 const SkOpSegment* segment = &fHead;
148 const SkOpSegment* prior = NULL;
149 do {
150 segment->debugValidate();
151 SkASSERT(segment->prev() == prior);
152 prior = segment;
153 } while ((segment = segment->next()));
154 SkASSERT(prior == fTail);
155#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000156 }
157
158 bool done() const {
159 return fDone;
160 }
161
caryclark54359292015-03-26 07:52:43 -0700162 void dump();
163 void dumpAll();
164 void dumpAngles() const;
165 void dumpPt(int ) const;
166 void dumpPts() const;
167 void dumpPtsX() const;
168 void dumpSegment(int ) const;
169 void dumpSegments(SkPathOp op) const;
170 void dumpSpan(int ) const;
171 void dumpSpans() const;
172
caryclark@google.com07393ca2013-04-08 11:47:37 +0000173 const SkPoint& end() const {
caryclark54359292015-03-26 07:52:43 -0700174 return fTail->pts()[SkPathOpsVerbToPoints(fTail->verb())];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000175 }
176
caryclark54359292015-03-26 07:52:43 -0700177 SkOpSegment* first() {
178 SkASSERT(fCount > 0);
179 return &fHead;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000180 }
181
caryclark54359292015-03-26 07:52:43 -0700182 const SkOpSegment* first() const {
183 SkASSERT(fCount > 0);
184 return &fHead;
caryclarkdac1d172014-06-17 05:15:38 -0700185 }
186
caryclark54359292015-03-26 07:52:43 -0700187 void indentDump() {
caryclark1049f122015-04-20 08:31:59 -0700188 SkDEBUGCODE(fIndent += 2);
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000189 }
190
caryclark54359292015-03-26 07:52:43 -0700191 void init(SkOpGlobalState* globalState, bool operand, bool isXor) {
192 fState = globalState;
193 fOperand = operand;
194 fXor = isXor;
caryclark1049f122015-04-20 08:31:59 -0700195 SkDEBUGCODE(fID = globalState->nextContourID());
caryclark54359292015-03-26 07:52:43 -0700196 }
197
198 bool isXor() const {
199 return fXor;
200 }
201
202 void missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocator) {
203 SkASSERT(fCount > 0);
204 SkOpSegment* segment = &fHead;
205 do {
206 if (fState->angleCoincidence()) {
207 segment->checkAngleCoin(coincidences, allocator);
208 } else {
209 segment->missingCoincidence(coincidences, allocator);
210 }
211 } while ((segment = segment->next()));
212 }
213
214 bool moveNearby() {
215 SkASSERT(fCount > 0);
216 SkOpSegment* segment = &fHead;
217 do {
218 if (!segment->moveNearby()) {
219 return false;
220 }
221 } while ((segment = segment->next()));
222 return true;
223 }
224
225 SkOpContour* next() {
226 return fNext;
227 }
228
229 const SkOpContour* next() const {
230 return fNext;
231 }
232
233 SkOpSegment* nonVerticalSegment(SkOpSpanBase** start, SkOpSpanBase** end);
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000234
caryclark@google.com07393ca2013-04-08 11:47:37 +0000235 bool operand() const {
236 return fOperand;
237 }
238
caryclark54359292015-03-26 07:52:43 -0700239 bool oppXor() const {
240 return fOppXor;
241 }
242
243 void outdentDump() {
caryclark1049f122015-04-20 08:31:59 -0700244 SkDEBUGCODE(fIndent -= 2);
caryclark54359292015-03-26 07:52:43 -0700245 }
246
247 void remove(SkOpContour* contour) {
248 if (contour == this) {
249 SkASSERT(fCount == 0);
250 return;
251 }
252 SkASSERT(contour->fNext == NULL);
253 SkOpContour* prev = this;
254 SkOpContour* next;
255 while ((next = prev->next()) != contour) {
256 SkASSERT(next);
257 prev = next;
258 }
259 SkASSERT(prev);
260 prev->setNext(NULL);
261 }
262
caryclark@google.com07393ca2013-04-08 11:47:37 +0000263 void reset() {
caryclark54359292015-03-26 07:52:43 -0700264 fTail = NULL;
265 fNext = NULL;
266 fCount = 0;
267 fDone = false;
268 SkDEBUGCODE(fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin));
269 SkDEBUGCODE(fFirstSorted = -1);
caryclark1049f122015-04-20 08:31:59 -0700270 SkDEBUGCODE(fIndent = 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000271 }
272
caryclark54359292015-03-26 07:52:43 -0700273 void setBounds() {
274 SkASSERT(fCount > 0);
275 const SkOpSegment* segment = &fHead;
276 fBounds = segment->bounds();
277 while ((segment = segment->next())) {
278 fBounds.add(segment->bounds());
279 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000280 }
281
caryclark54359292015-03-26 07:52:43 -0700282 void setGlobalState(SkOpGlobalState* state) {
283 fState = state;
284 }
285
286 void setNext(SkOpContour* contour) {
287// SkASSERT(!fNext == !!contour);
288 fNext = contour;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000289 }
290
291 void setOperand(bool isOp) {
292 fOperand = isOp;
293 }
294
295 void setOppXor(bool isOppXor) {
296 fOppXor = isOppXor;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000297 }
298
299 void setXor(bool isXor) {
300 fXor = isXor;
301 }
302
caryclark54359292015-03-26 07:52:43 -0700303 SkPath::Verb simplifyCubic(SkPoint pts[4]);
caryclarkccec0f92015-03-24 07:28:17 -0700304
caryclark54359292015-03-26 07:52:43 -0700305 void sortAngles() {
306 SkASSERT(fCount > 0);
307 SkOpSegment* segment = &fHead;
308 do {
309 segment->sortAngles();
310 } while ((segment = segment->next()));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000311 }
312
caryclark54359292015-03-26 07:52:43 -0700313 void sortSegments() {
314 SkOpSegment* segment = &fHead;
315 do {
316 *fSortedSegments.append() = segment;
317 } while ((segment = segment->next()));
318 SkTQSort<SkOpSegment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
319 fFirstSorted = 0;
320 }
321
322 const SkPoint& start() const {
323 return fHead.pts()[0];
324 }
reed0dc4dd62015-03-24 13:55:33 -0700325
326 void toPartialBackward(SkPathWriter* path) const {
caryclark54359292015-03-26 07:52:43 -0700327 const SkOpSegment* segment = fTail;
328 do {
329 segment->addCurveTo(segment->tail(), segment->head(), path, true);
330 } while ((segment = segment->prev()));
reed0dc4dd62015-03-24 13:55:33 -0700331 }
332
333 void toPartialForward(SkPathWriter* path) const {
caryclark54359292015-03-26 07:52:43 -0700334 const SkOpSegment* segment = &fHead;
335 do {
336 segment->addCurveTo(segment->head(), segment->tail(), path, true);
337 } while ((segment = segment->next()));
reed0dc4dd62015-03-24 13:55:33 -0700338 }
339
caryclark54359292015-03-26 07:52:43 -0700340 void toPath(SkPathWriter* path) const;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000341 void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment** topStart);
caryclark54359292015-03-26 07:52:43 -0700342 SkOpSegment* undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000343
caryclark@google.com07393ca2013-04-08 11:47:37 +0000344private:
caryclark54359292015-03-26 07:52:43 -0700345 SkOpGlobalState* fState;
346 SkOpSegment fHead;
347 SkOpSegment* fTail;
348 SkOpContour* fNext;
349 SkTDArray<SkOpSegment*> fSortedSegments; // set by find top segment
reed0dc4dd62015-03-24 13:55:33 -0700350 SkPathOpsBounds fBounds;
caryclark54359292015-03-26 07:52:43 -0700351 int fCount;
352 int fFirstSorted;
353 bool fDone; // set by find top segment
caryclark@google.com07393ca2013-04-08 11:47:37 +0000354 bool fOperand; // true for the second argument to a binary operator
caryclark54359292015-03-26 07:52:43 -0700355 bool fXor; // set if original path had even-odd fill
356 bool fOppXor; // set if opposite path had even-odd fill
caryclark1049f122015-04-20 08:31:59 -0700357 SkDEBUGCODE(int fID);
358 SkDEBUGCODE(int fIndent);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000359};
360
361#endif