blob: b9f0b85af5dbe1ecfccf9eb1e2ca7b3730b73241 [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 {
caryclarkd78c0882016-02-24 09:03:07 -0800272 if (!segment->moveMultiples()) {
273 return false;
274 }
caryclark54359292015-03-26 07:52:43 -0700275 } while ((segment = segment->next()));
276 return true;
277 }
278
caryclark08bc8482015-04-24 09:08:57 -0700279 void moveNearby() {
280 SkASSERT(fCount > 0);
281 SkOpSegment* segment = &fHead;
282 do {
283 segment->moveNearby();
284 } while ((segment = segment->next()));
285 }
286
caryclark54359292015-03-26 07:52:43 -0700287 SkOpContour* next() {
288 return fNext;
289 }
290
291 const SkOpContour* next() const {
292 return fNext;
293 }
294
caryclark@google.com07393ca2013-04-08 11:47:37 +0000295 bool operand() const {
296 return fOperand;
297 }
298
caryclark54359292015-03-26 07:52:43 -0700299 bool oppXor() const {
300 return fOppXor;
301 }
302
caryclark624637c2015-05-11 07:21:27 -0700303 void outdentDump() const {
304 SkDEBUGCODE(fDebugIndent -= 2);
caryclark54359292015-03-26 07:52:43 -0700305 }
306
caryclark624637c2015-05-11 07:21:27 -0700307 void rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits, SkChunkAlloc* );
308
caryclark54359292015-03-26 07:52:43 -0700309 void remove(SkOpContour* contour) {
310 if (contour == this) {
311 SkASSERT(fCount == 0);
312 return;
313 }
halcanary96fcdcc2015-08-27 07:41:13 -0700314 SkASSERT(contour->fNext == nullptr);
caryclark54359292015-03-26 07:52:43 -0700315 SkOpContour* prev = this;
316 SkOpContour* next;
317 while ((next = prev->next()) != contour) {
318 SkASSERT(next);
319 prev = next;
320 }
321 SkASSERT(prev);
halcanary96fcdcc2015-08-27 07:41:13 -0700322 prev->setNext(nullptr);
caryclark54359292015-03-26 07:52:43 -0700323 }
324
caryclark@google.com07393ca2013-04-08 11:47:37 +0000325 void reset() {
halcanary96fcdcc2015-08-27 07:41:13 -0700326 fTail = nullptr;
327 fNext = nullptr;
caryclark54359292015-03-26 07:52:43 -0700328 fCount = 0;
329 fDone = false;
330 SkDEBUGCODE(fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin));
331 SkDEBUGCODE(fFirstSorted = -1);
caryclark624637c2015-05-11 07:21:27 -0700332 SkDEBUGCODE(fDebugIndent = 0);
caryclark@google.com07393ca2013-04-08 11:47:37 +0000333 }
334
caryclark5b5ddd72015-05-18 05:12:56 -0700335 void resetReverse() {
336 SkOpContour* next = this;
337 do {
338 next->fCcw = -1;
339 next->fReverse = false;
340 } while ((next = next->next()));
341 }
342
343 bool reversed() const {
344 return fReverse;
345 }
346
caryclark54359292015-03-26 07:52:43 -0700347 void setBounds() {
348 SkASSERT(fCount > 0);
349 const SkOpSegment* segment = &fHead;
350 fBounds = segment->bounds();
351 while ((segment = segment->next())) {
352 fBounds.add(segment->bounds());
353 }
caryclark@google.com07393ca2013-04-08 11:47:37 +0000354 }
355
caryclark5b5ddd72015-05-18 05:12:56 -0700356 void setCcw(int ccw) {
357 fCcw = ccw;
358 }
359
caryclark54359292015-03-26 07:52:43 -0700360 void setGlobalState(SkOpGlobalState* state) {
361 fState = state;
362 }
363
364 void setNext(SkOpContour* contour) {
365// SkASSERT(!fNext == !!contour);
366 fNext = contour;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000367 }
368
369 void setOperand(bool isOp) {
370 fOperand = isOp;
371 }
372
373 void setOppXor(bool isOppXor) {
374 fOppXor = isOppXor;
caryclark@google.com07393ca2013-04-08 11:47:37 +0000375 }
376
caryclark5b5ddd72015-05-18 05:12:56 -0700377 void setReverse() {
378 fReverse = true;
379 }
380
caryclark@google.com07393ca2013-04-08 11:47:37 +0000381 void setXor(bool isXor) {
382 fXor = isXor;
383 }
384
caryclark54359292015-03-26 07:52:43 -0700385 SkPath::Verb simplifyCubic(SkPoint pts[4]);
caryclarkccec0f92015-03-24 07:28:17 -0700386
caryclark54359292015-03-26 07:52:43 -0700387 void sortAngles() {
388 SkASSERT(fCount > 0);
389 SkOpSegment* segment = &fHead;
390 do {
391 segment->sortAngles();
392 } while ((segment = segment->next()));
caryclark@google.com07393ca2013-04-08 11:47:37 +0000393 }
394
caryclark54359292015-03-26 07:52:43 -0700395 const SkPoint& start() const {
396 return fHead.pts()[0];
397 }
reed0dc4dd62015-03-24 13:55:33 -0700398
399 void toPartialBackward(SkPathWriter* path) const {
caryclark54359292015-03-26 07:52:43 -0700400 const SkOpSegment* segment = fTail;
401 do {
caryclarkef784fb2015-10-30 12:03:06 -0700402 SkAssertResult(segment->addCurveTo(segment->tail(), segment->head(), path));
caryclark54359292015-03-26 07:52:43 -0700403 } while ((segment = segment->prev()));
reed0dc4dd62015-03-24 13:55:33 -0700404 }
405
406 void toPartialForward(SkPathWriter* path) const {
caryclark54359292015-03-26 07:52:43 -0700407 const SkOpSegment* segment = &fHead;
408 do {
caryclarkef784fb2015-10-30 12:03:06 -0700409 SkAssertResult(segment->addCurveTo(segment->head(), segment->tail(), path));
caryclark54359292015-03-26 07:52:43 -0700410 } while ((segment = segment->next()));
reed0dc4dd62015-03-24 13:55:33 -0700411 }
412
caryclark5b5ddd72015-05-18 05:12:56 -0700413 void toReversePath(SkPathWriter* path) const;
caryclark54359292015-03-26 07:52:43 -0700414 void toPath(SkPathWriter* path) const;
caryclark54359292015-03-26 07:52:43 -0700415 SkOpSegment* undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr);
commit-bot@chromium.org4431e772014-04-14 17:08:59 +0000416
caryclark@google.com07393ca2013-04-08 11:47:37 +0000417private:
caryclark54359292015-03-26 07:52:43 -0700418 SkOpGlobalState* fState;
419 SkOpSegment fHead;
420 SkOpSegment* fTail;
421 SkOpContour* fNext;
reed0dc4dd62015-03-24 13:55:33 -0700422 SkPathOpsBounds fBounds;
caryclark5b5ddd72015-05-18 05:12:56 -0700423 int fCcw;
caryclark54359292015-03-26 07:52:43 -0700424 int fCount;
425 int fFirstSorted;
426 bool fDone; // set by find top segment
caryclark@google.com07393ca2013-04-08 11:47:37 +0000427 bool fOperand; // true for the second argument to a binary operator
caryclark5b5ddd72015-05-18 05:12:56 -0700428 bool fReverse; // true if contour should be reverse written to path (used only by fix winding)
caryclark54359292015-03-26 07:52:43 -0700429 bool fXor; // set if original path had even-odd fill
430 bool fOppXor; // set if opposite path had even-odd fill
caryclark1049f122015-04-20 08:31:59 -0700431 SkDEBUGCODE(int fID);
caryclark624637c2015-05-11 07:21:27 -0700432 SkDEBUGCODE(mutable int fDebugIndent);
433};
434
435class SkOpContourHead : public SkOpContour {
caryclark@google.com07393ca2013-04-08 11:47:37 +0000436};
437
438#endif