blob: be1f59f4bbe2a5fa73f51730c01b646285fe3eea [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"
caryclarkccec0f92015-03-24 07:28:17 -070011#include "SkTDArray.h"
12#include "SkTSort.h"
caryclark@google.com07393ca2013-04-08 11:47:37 +000013
caryclarkccec0f92015-03-24 07:28:17 -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();
caryclark@google.com07393ca2013-04-08 11:47:37 +000021 }
22
23 bool operator<(const SkOpContour& rh) const {
24 return fBounds.fTop == rh.fBounds.fTop
25 ? fBounds.fLeft < rh.fBounds.fLeft
26 : fBounds.fTop < rh.fBounds.fTop;
27 }
28
caryclarkccec0f92015-03-24 07:28:17 -070029 void addCubic(SkPoint pts[4], SkChunkAlloc* allocator) {
30 appendSegment(allocator).addCubic(pts, this);
31 }
caryclark@google.com07393ca2013-04-08 11:47:37 +000032
caryclarkccec0f92015-03-24 07:28:17 -070033 void addCurve(SkPath::Verb verb, const SkPoint pts[4], SkChunkAlloc* allocator);
34
35 void addLine(SkPoint pts[2], SkChunkAlloc* allocator) {
36 appendSegment(allocator).addLine(pts, this);
37 }
38
39 void addQuad(SkPoint pts[3], SkChunkAlloc* allocator) {
40 appendSegment(allocator).addQuad(pts, this);
41 }
42
43 void align() {
44 SkASSERT(fCount > 0);
45 SkOpSegment* segment = &fHead;
46 do {
47 segment->align();
48 } while ((segment = segment->next()));
49 }
50
51 SkOpSegment& appendSegment(SkChunkAlloc* allocator) {
52 SkOpSegment* result = fCount++
53 ? SkOpTAllocator<SkOpSegment>::Allocate(allocator) : &fHead;
54 result->setPrev(fTail);
55 if (fTail) {
56 fTail->setNext(result);
caryclark@google.com07393ca2013-04-08 11:47:37 +000057 }
caryclarkccec0f92015-03-24 07:28:17 -070058 fTail = result;
59 return *result;
caryclark@google.com07393ca2013-04-08 11:47:37 +000060 }
61
caryclarkccec0f92015-03-24 07:28:17 -070062 SkOpContour* appendContour(SkChunkAlloc* allocator) {
63 SkOpContour* contour = SkOpTAllocator<SkOpContour>::New(allocator);
64
65 SkOpContour* prev = this;
66 SkOpContour* next;
67 while ((next = prev->next())) {
68 prev = next;
caryclarkdac1d172014-06-17 05:15:38 -070069 }
caryclarkccec0f92015-03-24 07:28:17 -070070 prev->setNext(contour);
71 return contour;
caryclarkdac1d172014-06-17 05:15:38 -070072 }
caryclarkccec0f92015-03-24 07:28:17 -070073
caryclark@google.com07393ca2013-04-08 11:47:37 +000074 const SkPathOpsBounds& bounds() const {
75 return fBounds;
76 }
77
caryclarkccec0f92015-03-24 07:28:17 -070078 void calcAngles(SkChunkAlloc* allocator) {
79 SkASSERT(fCount > 0);
80 SkOpSegment* segment = &fHead;
81 do {
82 segment->calcAngles(allocator);
83 } while ((segment = segment->next()));
caryclark@google.comfa2aeee2013-07-15 13:29:13 +000084 }
85
caryclark@google.com07393ca2013-04-08 11:47:37 +000086 void complete() {
87 setBounds();
caryclark@google.com07393ca2013-04-08 11:47:37 +000088 }
89
caryclarkccec0f92015-03-24 07:28:17 -070090 int count() const {
91 return fCount;
caryclark@google.com07393ca2013-04-08 11:47:37 +000092 }
93
caryclarkccec0f92015-03-24 07:28:17 -070094 int debugID() const {
95 return PATH_OPS_DEBUG_RELEASE(fID, -1);
96 }
97
98 int debugIndent() const {
99 return PATH_OPS_DEBUG_RELEASE(fIndent, 0);
100 }
101
102#if DEBUG_ACTIVE_SPANS
103 void debugShowActiveSpans() {
104 SkOpSegment* segment = &fHead;
105 do {
106 segment->debugShowActiveSpans();
107 } while ((segment = segment->next()));
108 }
109#endif
110
111 const SkOpAngle* debugAngle(int id) const {
112 return PATH_OPS_DEBUG_RELEASE(globalState()->debugAngle(id), NULL);
113 }
114
115 SkOpContour* debugContour(int id) {
116 return PATH_OPS_DEBUG_RELEASE(globalState()->debugContour(id), NULL);
117 }
118
119 const SkOpPtT* debugPtT(int id) const {
120 return PATH_OPS_DEBUG_RELEASE(globalState()->debugPtT(id), NULL);
121 }
122
123 const SkOpSegment* debugSegment(int id) const {
124 return PATH_OPS_DEBUG_RELEASE(globalState()->debugSegment(id), NULL);
125 }
126
127 const SkOpSpanBase* debugSpan(int id) const {
128 return PATH_OPS_DEBUG_RELEASE(globalState()->debugSpan(id), NULL);
129 }
130
131 SkOpGlobalState* globalState() const {
132 return fState;
133 }
134
135 void debugValidate() const {
136#if DEBUG_VALIDATE
137 const SkOpSegment* segment = &fHead;
138 const SkOpSegment* prior = NULL;
139 do {
140 segment->debugValidate();
141 SkASSERT(segment->prev() == prior);
142 prior = segment;
143 } while ((segment = segment->next()));
144 SkASSERT(prior == fTail);
145#endif
caryclark@google.com07393ca2013-04-08 11:47:37 +0000146 }
147
148 bool done() const {
149 return fDone;
150 }
151
caryclarkccec0f92015-03-24 07:28:17 -0700152 void dump();
153 void dumpAll();
154 void dumpAngles() const;
155 void dumpPt(int ) const;
156 void dumpPts() const;
157 void dumpPtsX() const;
158 void dumpSegment(int ) const;
159 void dumpSegments(SkPathOp op) const;
160 void dumpSpan(int ) const;
161 void dumpSpans() const;
162
caryclark@google.com07393ca2013-04-08 11:47:37 +0000163 const SkPoint& end() const {
caryclarkccec0f92015-03-24 07:28:17 -0700164 return fTail->pts()[SkPathOpsVerbToPoints(fTail->verb())];
caryclark@google.com07393ca2013-04-08 11:47:37 +0000165 }
166
caryclarkccec0f92015-03-24 07:28:17 -0700167 SkOpSegment* first() {
168 SkASSERT(fCount > 0);
169 return &fHead;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000170 }
171
caryclarkccec0f92015-03-24 07:28:17 -0700172 const SkOpSegment* first() const {
173 SkASSERT(fCount > 0);
174 return &fHead;
caryclarkdac1d172014-06-17 05:15:38 -0700175 }
176
caryclarkccec0f92015-03-24 07:28:17 -0700177 void indentDump() {
178 PATH_OPS_DEBUG_CODE(fIndent += 2);
caryclark@google.coma2bbc6e2013-11-01 17:36:03 +0000179 }
180
caryclarkccec0f92015-03-24 07:28:17 -0700181 void init(SkOpGlobalState* globalState, bool operand, bool isXor) {
182 fState = globalState;
183 fOperand = operand;
184 fXor = isXor;
185 }
186
187 bool isXor() const {
188 return fXor;
189 }
190
191 void missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocator) {
192 SkASSERT(fCount > 0);
193 SkOpSegment* segment = &fHead;
194 do {
195 if (fState->angleCoincidence()) {
196 segment->checkAngleCoin(coincidences, allocator);
197 } else {
198 segment->missingCoincidence(coincidences, allocator);
199 }
200 } while ((segment = segment->next()));
201 }
202
203 bool moveNearby() {
204 SkASSERT(fCount > 0);
205 SkOpSegment* segment = &fHead;
206 do {
207 if (!segment->moveNearby()) {
208 return false;
209 }
210 } while ((segment = segment->next()));
211 return true;
212 }
213
214 SkOpContour* next() {
215 return fNext;
216 }
217
218 const SkOpContour* next() const {
219 return fNext;
220 }
221
222 SkOpSegment* nonVerticalSegment(SkOpSpanBase** start, SkOpSpanBase** end);
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000223
caryclark@google.com07393ca2013-04-08 11:47:37 +0000224 bool operand() const {
225 return fOperand;
226 }
227
caryclarkccec0f92015-03-24 07:28:17 -0700228 bool oppXor() const {
229 return fOppXor;
230 }
231
232 void outdentDump() {
233 PATH_OPS_DEBUG_CODE(fIndent -= 2);
234 }
235
236 void remove(SkOpContour* contour) {
237 if (contour == this) {
238 SkASSERT(fCount == 0);
239 return;
240 }
241 SkASSERT(contour->fNext == NULL);
242 SkOpContour* prev = this;
243 SkOpContour* next;
244 while ((next = prev->next()) != contour) {
245 SkASSERT(next);
246 prev = next;
247 }
248 SkASSERT(prev);
249 prev->setNext(NULL);
250 }
251
caryclark@google.com07393ca2013-04-08 11:47:37 +0000252 void reset() {
caryclarkccec0f92015-03-24 07:28:17 -0700253 fTail = NULL;
254 fNext = NULL;
255 fCount = 0;
256 fDone = false;
257 SkDEBUGCODE(fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin));
258 SkDEBUGCODE(fFirstSorted = -1);
259 PATH_OPS_DEBUG_CODE(fIndent = 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000260 }
261
caryclarkccec0f92015-03-24 07:28:17 -0700262 void setBounds() {
263 SkASSERT(fCount > 0);
264 const SkOpSegment* segment = &fHead;
265 fBounds = segment->bounds();
266 while ((segment = segment->next())) {
267 fBounds.add(segment->bounds());
268 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000269 }
270
caryclarkccec0f92015-03-24 07:28:17 -0700271 void setGlobalState(SkOpGlobalState* state) {
272 fState = state;
273 }
274
275 void setNext(SkOpContour* contour) {
276 SkASSERT(!fNext == !!contour);
277 fNext = contour;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000278 }
279
280 void setOperand(bool isOp) {
281 fOperand = isOp;
282 }
283
284 void setOppXor(bool isOppXor) {
285 fOppXor = isOppXor;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000286 }
287
288 void setXor(bool isXor) {
289 fXor = isXor;
290 }
291
caryclarkccec0f92015-03-24 07:28:17 -0700292 SkPath::Verb simplifyCubic(SkPoint pts[4]);
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000293
caryclarkccec0f92015-03-24 07:28:17 -0700294 void sortAngles() {
295 SkASSERT(fCount > 0);
296 SkOpSegment* segment = &fHead;
297 do {
298 segment->sortAngles();
299 } while ((segment = segment->next()));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000300 }
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000301
caryclarkccec0f92015-03-24 07:28:17 -0700302 void sortSegments() {
303 SkOpSegment* segment = &fHead;
304 do {
305 *fSortedSegments.append() = segment;
306 } while ((segment = segment->next()));
307 SkTQSort<SkOpSegment>(fSortedSegments.begin(), fSortedSegments.end() - 1);
308 fFirstSorted = 0;
309 }
310
311 const SkPoint& start() const {
312 return fHead.pts()[0];
313 }
skia.committer@gmail.com32840172013-04-09 07:01:27 +0000314
caryclark@google.com07393ca2013-04-08 11:47:37 +0000315 void toPartialBackward(SkPathWriter* path) const {
caryclarkccec0f92015-03-24 07:28:17 -0700316 const SkOpSegment* segment = fTail;
317 do {
318 segment->addCurveTo(segment->tail(), segment->head(), path, true);
319 } while ((segment = segment->prev()));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000320 }
321
322 void toPartialForward(SkPathWriter* path) const {
caryclarkccec0f92015-03-24 07:28:17 -0700323 const SkOpSegment* segment = &fHead;
324 do {
325 segment->addCurveTo(segment->head(), segment->tail(), path, true);
326 } while ((segment = segment->next()));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000327 }
328
caryclarkccec0f92015-03-24 07:28:17 -0700329 void toPath(SkPathWriter* path) const;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000330 void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment** topStart);
caryclarkccec0f92015-03-24 07:28:17 -0700331 SkOpSegment* undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000332
caryclark@google.com07393ca2013-04-08 11:47:37 +0000333private:
caryclarkccec0f92015-03-24 07:28:17 -0700334 SkOpGlobalState* fState;
335 SkOpSegment fHead;
336 SkOpSegment* fTail;
337 SkOpContour* fNext;
338 SkTDArray<SkOpSegment*> fSortedSegments; // set by find top segment
caryclark@google.com07393ca2013-04-08 11:47:37 +0000339 SkPathOpsBounds fBounds;
caryclarkccec0f92015-03-24 07:28:17 -0700340 int fCount;
341 int fFirstSorted;
342 bool fDone; // set by find top segment
caryclark@google.com07393ca2013-04-08 11:47:37 +0000343 bool fOperand; // true for the second argument to a binary operator
caryclarkccec0f92015-03-24 07:28:17 -0700344 bool fXor; // set if original path had even-odd fill
345 bool fOppXor; // set if opposite path had even-odd fill
346 PATH_OPS_DEBUG_CODE(int fID);
347 PATH_OPS_DEBUG_CODE(int fIndent);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000348};
349
350#endif