xref: /aosp_15_r20/external/skia/src/pathops/SkOpContour.h (revision c8dee2aa9b3f27cf6c858bd81872bdeb2c07ed17)
1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker  * Copyright 2013 Google Inc.
3*c8dee2aaSAndroid Build Coastguard Worker  *
4*c8dee2aaSAndroid Build Coastguard Worker  * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker  * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker  */
7*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkOpContour_DEFINED
8*c8dee2aaSAndroid Build Coastguard Worker #define SkOpContour_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker 
10*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPath.h"
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkPoint.h"
12*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkScalar.h"
13*c8dee2aaSAndroid Build Coastguard Worker #include "include/core/SkTypes.h"
14*c8dee2aaSAndroid Build Coastguard Worker #include "include/pathops/SkPathOps.h"
15*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkDebug.h"
16*c8dee2aaSAndroid Build Coastguard Worker #include "src/base/SkArenaAlloc.h"
17*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkOpSegment.h"
18*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkOpSpan.h"
19*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsBounds.h"
20*c8dee2aaSAndroid Build Coastguard Worker #include "src/pathops/SkPathOpsTypes.h"
21*c8dee2aaSAndroid Build Coastguard Worker 
22*c8dee2aaSAndroid Build Coastguard Worker class SkOpAngle;
23*c8dee2aaSAndroid Build Coastguard Worker class SkOpCoincidence;
24*c8dee2aaSAndroid Build Coastguard Worker class SkPathWriter;
25*c8dee2aaSAndroid Build Coastguard Worker enum class SkOpRayDir;
26*c8dee2aaSAndroid Build Coastguard Worker struct SkOpRayHit;
27*c8dee2aaSAndroid Build Coastguard Worker 
28*c8dee2aaSAndroid Build Coastguard Worker class SkOpContour {
29*c8dee2aaSAndroid Build Coastguard Worker public:
SkOpContour()30*c8dee2aaSAndroid Build Coastguard Worker     SkOpContour() {
31*c8dee2aaSAndroid Build Coastguard Worker         reset();
32*c8dee2aaSAndroid Build Coastguard Worker     }
33*c8dee2aaSAndroid Build Coastguard Worker 
34*c8dee2aaSAndroid Build Coastguard Worker     bool operator<(const SkOpContour& rh) const {
35*c8dee2aaSAndroid Build Coastguard Worker         return fBounds.fTop == rh.fBounds.fTop
36*c8dee2aaSAndroid Build Coastguard Worker             ? fBounds.fLeft < rh.fBounds.fLeft
37*c8dee2aaSAndroid Build Coastguard Worker             : fBounds.fTop < rh.fBounds.fTop;
38*c8dee2aaSAndroid Build Coastguard Worker     }
39*c8dee2aaSAndroid Build Coastguard Worker 
addConic(SkPoint pts[3],SkScalar weight)40*c8dee2aaSAndroid Build Coastguard Worker     void addConic(SkPoint pts[3], SkScalar weight) {
41*c8dee2aaSAndroid Build Coastguard Worker         appendSegment().addConic(pts, weight, this);
42*c8dee2aaSAndroid Build Coastguard Worker     }
43*c8dee2aaSAndroid Build Coastguard Worker 
addCubic(SkPoint pts[4])44*c8dee2aaSAndroid Build Coastguard Worker     void addCubic(SkPoint pts[4]) {
45*c8dee2aaSAndroid Build Coastguard Worker         appendSegment().addCubic(pts, this);
46*c8dee2aaSAndroid Build Coastguard Worker     }
47*c8dee2aaSAndroid Build Coastguard Worker 
addLine(SkPoint pts[2])48*c8dee2aaSAndroid Build Coastguard Worker     SkOpSegment* addLine(SkPoint pts[2]) {
49*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(pts[0] != pts[1]);
50*c8dee2aaSAndroid Build Coastguard Worker         return appendSegment().addLine(pts, this);
51*c8dee2aaSAndroid Build Coastguard Worker     }
52*c8dee2aaSAndroid Build Coastguard Worker 
addQuad(SkPoint pts[3])53*c8dee2aaSAndroid Build Coastguard Worker     void addQuad(SkPoint pts[3]) {
54*c8dee2aaSAndroid Build Coastguard Worker         appendSegment().addQuad(pts, this);
55*c8dee2aaSAndroid Build Coastguard Worker     }
56*c8dee2aaSAndroid Build Coastguard Worker 
appendSegment()57*c8dee2aaSAndroid Build Coastguard Worker     SkOpSegment& appendSegment() {
58*c8dee2aaSAndroid Build Coastguard Worker         SkOpSegment* result = fCount++ ? this->globalState()->allocator()->make<SkOpSegment>()
59*c8dee2aaSAndroid Build Coastguard Worker                                        : &fHead;
60*c8dee2aaSAndroid Build Coastguard Worker         result->setPrev(fTail);
61*c8dee2aaSAndroid Build Coastguard Worker         if (fTail) {
62*c8dee2aaSAndroid Build Coastguard Worker             fTail->setNext(result);
63*c8dee2aaSAndroid Build Coastguard Worker         }
64*c8dee2aaSAndroid Build Coastguard Worker         fTail = result;
65*c8dee2aaSAndroid Build Coastguard Worker         return *result;
66*c8dee2aaSAndroid Build Coastguard Worker     }
67*c8dee2aaSAndroid Build Coastguard Worker 
bounds()68*c8dee2aaSAndroid Build Coastguard Worker     const SkPathOpsBounds& bounds() const {
69*c8dee2aaSAndroid Build Coastguard Worker         return fBounds;
70*c8dee2aaSAndroid Build Coastguard Worker     }
71*c8dee2aaSAndroid Build Coastguard Worker 
calcAngles()72*c8dee2aaSAndroid Build Coastguard Worker     void calcAngles() {
73*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fCount > 0);
74*c8dee2aaSAndroid Build Coastguard Worker         SkOpSegment* segment = &fHead;
75*c8dee2aaSAndroid Build Coastguard Worker         do {
76*c8dee2aaSAndroid Build Coastguard Worker             segment->calcAngles();
77*c8dee2aaSAndroid Build Coastguard Worker         } while ((segment = segment->next()));
78*c8dee2aaSAndroid Build Coastguard Worker     }
79*c8dee2aaSAndroid Build Coastguard Worker 
complete()80*c8dee2aaSAndroid Build Coastguard Worker     void complete() {
81*c8dee2aaSAndroid Build Coastguard Worker         setBounds();
82*c8dee2aaSAndroid Build Coastguard Worker     }
83*c8dee2aaSAndroid Build Coastguard Worker 
count()84*c8dee2aaSAndroid Build Coastguard Worker     int count() const {
85*c8dee2aaSAndroid Build Coastguard Worker         return fCount;
86*c8dee2aaSAndroid Build Coastguard Worker     }
87*c8dee2aaSAndroid Build Coastguard Worker 
debugID()88*c8dee2aaSAndroid Build Coastguard Worker     int debugID() const {
89*c8dee2aaSAndroid Build Coastguard Worker         return SkDEBUGRELEASE(fID, -1);
90*c8dee2aaSAndroid Build Coastguard Worker     }
91*c8dee2aaSAndroid Build Coastguard Worker 
debugIndent()92*c8dee2aaSAndroid Build Coastguard Worker     int debugIndent() const {
93*c8dee2aaSAndroid Build Coastguard Worker         return SkDEBUGRELEASE(fDebugIndent, 0);
94*c8dee2aaSAndroid Build Coastguard Worker     }
95*c8dee2aaSAndroid Build Coastguard Worker 
debugAngle(int id)96*c8dee2aaSAndroid Build Coastguard Worker     const SkOpAngle* debugAngle(int id) const {
97*c8dee2aaSAndroid Build Coastguard Worker         return SkDEBUGRELEASE(this->globalState()->debugAngle(id), nullptr);
98*c8dee2aaSAndroid Build Coastguard Worker     }
99*c8dee2aaSAndroid Build Coastguard Worker 
debugCoincidence()100*c8dee2aaSAndroid Build Coastguard Worker     const SkOpCoincidence* debugCoincidence() const {
101*c8dee2aaSAndroid Build Coastguard Worker         return this->globalState()->coincidence();
102*c8dee2aaSAndroid Build Coastguard Worker     }
103*c8dee2aaSAndroid Build Coastguard Worker 
104*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_COIN
105*c8dee2aaSAndroid Build Coastguard Worker     void debugCheckHealth(SkPathOpsDebug::GlitchLog* ) const;
106*c8dee2aaSAndroid Build Coastguard Worker #endif
107*c8dee2aaSAndroid Build Coastguard Worker 
debugContour(int id)108*c8dee2aaSAndroid Build Coastguard Worker     SkOpContour* debugContour(int id) const {
109*c8dee2aaSAndroid Build Coastguard Worker         return SkDEBUGRELEASE(this->globalState()->debugContour(id), nullptr);
110*c8dee2aaSAndroid Build Coastguard Worker     }
111*c8dee2aaSAndroid Build Coastguard Worker 
112*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_COIN
113*c8dee2aaSAndroid Build Coastguard Worker     void debugMissingCoincidence(SkPathOpsDebug::GlitchLog* log) const;
114*c8dee2aaSAndroid Build Coastguard Worker     void debugMoveMultiples(SkPathOpsDebug::GlitchLog* ) const;
115*c8dee2aaSAndroid Build Coastguard Worker     void debugMoveNearby(SkPathOpsDebug::GlitchLog* log) const;
116*c8dee2aaSAndroid Build Coastguard Worker #endif
117*c8dee2aaSAndroid Build Coastguard Worker 
debugPtT(int id)118*c8dee2aaSAndroid Build Coastguard Worker     const SkOpPtT* debugPtT(int id) const {
119*c8dee2aaSAndroid Build Coastguard Worker         return SkDEBUGRELEASE(this->globalState()->debugPtT(id), nullptr);
120*c8dee2aaSAndroid Build Coastguard Worker     }
121*c8dee2aaSAndroid Build Coastguard Worker 
debugSegment(int id)122*c8dee2aaSAndroid Build Coastguard Worker     const SkOpSegment* debugSegment(int id) const {
123*c8dee2aaSAndroid Build Coastguard Worker         return SkDEBUGRELEASE(this->globalState()->debugSegment(id), nullptr);
124*c8dee2aaSAndroid Build Coastguard Worker     }
125*c8dee2aaSAndroid Build Coastguard Worker 
126*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_ACTIVE_SPANS
debugShowActiveSpans(SkString * str)127*c8dee2aaSAndroid Build Coastguard Worker     void debugShowActiveSpans(SkString* str) {
128*c8dee2aaSAndroid Build Coastguard Worker         SkOpSegment* segment = &fHead;
129*c8dee2aaSAndroid Build Coastguard Worker         do {
130*c8dee2aaSAndroid Build Coastguard Worker             segment->debugShowActiveSpans(str);
131*c8dee2aaSAndroid Build Coastguard Worker         } while ((segment = segment->next()));
132*c8dee2aaSAndroid Build Coastguard Worker     }
133*c8dee2aaSAndroid Build Coastguard Worker #endif
134*c8dee2aaSAndroid Build Coastguard Worker 
debugSpan(int id)135*c8dee2aaSAndroid Build Coastguard Worker     const SkOpSpanBase* debugSpan(int id) const {
136*c8dee2aaSAndroid Build Coastguard Worker         return SkDEBUGRELEASE(this->globalState()->debugSpan(id), nullptr);
137*c8dee2aaSAndroid Build Coastguard Worker     }
138*c8dee2aaSAndroid Build Coastguard Worker 
globalState()139*c8dee2aaSAndroid Build Coastguard Worker     SkOpGlobalState* globalState() const {
140*c8dee2aaSAndroid Build Coastguard Worker         return fState;
141*c8dee2aaSAndroid Build Coastguard Worker     }
142*c8dee2aaSAndroid Build Coastguard Worker 
debugValidate()143*c8dee2aaSAndroid Build Coastguard Worker     void debugValidate() const {
144*c8dee2aaSAndroid Build Coastguard Worker #if DEBUG_VALIDATE
145*c8dee2aaSAndroid Build Coastguard Worker         const SkOpSegment* segment = &fHead;
146*c8dee2aaSAndroid Build Coastguard Worker         const SkOpSegment* prior = nullptr;
147*c8dee2aaSAndroid Build Coastguard Worker         do {
148*c8dee2aaSAndroid Build Coastguard Worker             segment->debugValidate();
149*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(segment->prev() == prior);
150*c8dee2aaSAndroid Build Coastguard Worker             prior = segment;
151*c8dee2aaSAndroid Build Coastguard Worker         } while ((segment = segment->next()));
152*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(prior == fTail);
153*c8dee2aaSAndroid Build Coastguard Worker #endif
154*c8dee2aaSAndroid Build Coastguard Worker     }
155*c8dee2aaSAndroid Build Coastguard Worker 
done()156*c8dee2aaSAndroid Build Coastguard Worker     bool done() const {
157*c8dee2aaSAndroid Build Coastguard Worker         return fDone;
158*c8dee2aaSAndroid Build Coastguard Worker     }
159*c8dee2aaSAndroid Build Coastguard Worker 
160*c8dee2aaSAndroid Build Coastguard Worker     void dump() const;
161*c8dee2aaSAndroid Build Coastguard Worker     void dumpAll() const;
162*c8dee2aaSAndroid Build Coastguard Worker     void dumpAngles() const;
163*c8dee2aaSAndroid Build Coastguard Worker     void dumpContours() const;
164*c8dee2aaSAndroid Build Coastguard Worker     void dumpContoursAll() const;
165*c8dee2aaSAndroid Build Coastguard Worker     void dumpContoursAngles() const;
166*c8dee2aaSAndroid Build Coastguard Worker     void dumpContoursPts() const;
167*c8dee2aaSAndroid Build Coastguard Worker     void dumpContoursPt(int segmentID) const;
168*c8dee2aaSAndroid Build Coastguard Worker     void dumpContoursSegment(int segmentID) const;
169*c8dee2aaSAndroid Build Coastguard Worker     void dumpContoursSpan(int segmentID) const;
170*c8dee2aaSAndroid Build Coastguard Worker     void dumpContoursSpans() const;
171*c8dee2aaSAndroid Build Coastguard Worker     void dumpPt(int ) const;
172*c8dee2aaSAndroid Build Coastguard Worker     void dumpPts(const char* prefix = "seg") const;
173*c8dee2aaSAndroid Build Coastguard Worker     void dumpPtsX(const char* prefix) const;
174*c8dee2aaSAndroid Build Coastguard Worker     void dumpSegment(int ) const;
175*c8dee2aaSAndroid Build Coastguard Worker     void dumpSegments(const char* prefix = "seg", SkPathOp op = (SkPathOp) -1) const;
176*c8dee2aaSAndroid Build Coastguard Worker     void dumpSpan(int ) const;
177*c8dee2aaSAndroid Build Coastguard Worker     void dumpSpans() const;
178*c8dee2aaSAndroid Build Coastguard Worker 
end()179*c8dee2aaSAndroid Build Coastguard Worker     const SkPoint& end() const {
180*c8dee2aaSAndroid Build Coastguard Worker         return fTail->pts()[SkPathOpsVerbToPoints(fTail->verb())];
181*c8dee2aaSAndroid Build Coastguard Worker     }
182*c8dee2aaSAndroid Build Coastguard Worker 
183*c8dee2aaSAndroid Build Coastguard Worker     SkOpSpan* findSortableTop(SkOpContour* );
184*c8dee2aaSAndroid Build Coastguard Worker 
first()185*c8dee2aaSAndroid Build Coastguard Worker     SkOpSegment* first() {
186*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fCount > 0);
187*c8dee2aaSAndroid Build Coastguard Worker         return &fHead;
188*c8dee2aaSAndroid Build Coastguard Worker     }
189*c8dee2aaSAndroid Build Coastguard Worker 
first()190*c8dee2aaSAndroid Build Coastguard Worker     const SkOpSegment* first() const {
191*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fCount > 0);
192*c8dee2aaSAndroid Build Coastguard Worker         return &fHead;
193*c8dee2aaSAndroid Build Coastguard Worker     }
194*c8dee2aaSAndroid Build Coastguard Worker 
indentDump()195*c8dee2aaSAndroid Build Coastguard Worker     void indentDump() const {
196*c8dee2aaSAndroid Build Coastguard Worker         SkDEBUGCODE(fDebugIndent += 2);
197*c8dee2aaSAndroid Build Coastguard Worker     }
198*c8dee2aaSAndroid Build Coastguard Worker 
init(SkOpGlobalState * globalState,bool operand,bool isXor)199*c8dee2aaSAndroid Build Coastguard Worker     void init(SkOpGlobalState* globalState, bool operand, bool isXor) {
200*c8dee2aaSAndroid Build Coastguard Worker         fState = globalState;
201*c8dee2aaSAndroid Build Coastguard Worker         fOperand = operand;
202*c8dee2aaSAndroid Build Coastguard Worker         fXor = isXor;
203*c8dee2aaSAndroid Build Coastguard Worker         SkDEBUGCODE(fID = globalState->nextContourID());
204*c8dee2aaSAndroid Build Coastguard Worker     }
205*c8dee2aaSAndroid Build Coastguard Worker 
isCcw()206*c8dee2aaSAndroid Build Coastguard Worker     int isCcw() const {
207*c8dee2aaSAndroid Build Coastguard Worker         return fCcw;
208*c8dee2aaSAndroid Build Coastguard Worker     }
209*c8dee2aaSAndroid Build Coastguard Worker 
isXor()210*c8dee2aaSAndroid Build Coastguard Worker     bool isXor() const {
211*c8dee2aaSAndroid Build Coastguard Worker         return fXor;
212*c8dee2aaSAndroid Build Coastguard Worker     }
213*c8dee2aaSAndroid Build Coastguard Worker 
joinSegments()214*c8dee2aaSAndroid Build Coastguard Worker     void joinSegments() {
215*c8dee2aaSAndroid Build Coastguard Worker         SkOpSegment* segment = &fHead;
216*c8dee2aaSAndroid Build Coastguard Worker         SkOpSegment* next;
217*c8dee2aaSAndroid Build Coastguard Worker         do {
218*c8dee2aaSAndroid Build Coastguard Worker             next = segment->next();
219*c8dee2aaSAndroid Build Coastguard Worker             segment->joinEnds(next ? next : &fHead);
220*c8dee2aaSAndroid Build Coastguard Worker         } while ((segment = next));
221*c8dee2aaSAndroid Build Coastguard Worker     }
222*c8dee2aaSAndroid Build Coastguard Worker 
markAllDone()223*c8dee2aaSAndroid Build Coastguard Worker     void markAllDone() {
224*c8dee2aaSAndroid Build Coastguard Worker         SkOpSegment* segment = &fHead;
225*c8dee2aaSAndroid Build Coastguard Worker         do {
226*c8dee2aaSAndroid Build Coastguard Worker             segment->markAllDone();
227*c8dee2aaSAndroid Build Coastguard Worker         } while ((segment = segment->next()));
228*c8dee2aaSAndroid Build Coastguard Worker     }
229*c8dee2aaSAndroid Build Coastguard Worker 
230*c8dee2aaSAndroid Build Coastguard Worker     // Please keep this aligned with debugMissingCoincidence()
missingCoincidence()231*c8dee2aaSAndroid Build Coastguard Worker     bool missingCoincidence() {
232*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fCount > 0);
233*c8dee2aaSAndroid Build Coastguard Worker         SkOpSegment* segment = &fHead;
234*c8dee2aaSAndroid Build Coastguard Worker         bool result = false;
235*c8dee2aaSAndroid Build Coastguard Worker         do {
236*c8dee2aaSAndroid Build Coastguard Worker             if (segment->missingCoincidence()) {
237*c8dee2aaSAndroid Build Coastguard Worker                 result = true;
238*c8dee2aaSAndroid Build Coastguard Worker             }
239*c8dee2aaSAndroid Build Coastguard Worker             segment = segment->next();
240*c8dee2aaSAndroid Build Coastguard Worker         } while (segment);
241*c8dee2aaSAndroid Build Coastguard Worker         return result;
242*c8dee2aaSAndroid Build Coastguard Worker     }
243*c8dee2aaSAndroid Build Coastguard Worker 
moveMultiples()244*c8dee2aaSAndroid Build Coastguard Worker     bool moveMultiples() {
245*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fCount > 0);
246*c8dee2aaSAndroid Build Coastguard Worker         SkOpSegment* segment = &fHead;
247*c8dee2aaSAndroid Build Coastguard Worker         do {
248*c8dee2aaSAndroid Build Coastguard Worker             if (!segment->moveMultiples()) {
249*c8dee2aaSAndroid Build Coastguard Worker                 return false;
250*c8dee2aaSAndroid Build Coastguard Worker             }
251*c8dee2aaSAndroid Build Coastguard Worker         } while ((segment = segment->next()));
252*c8dee2aaSAndroid Build Coastguard Worker         return true;
253*c8dee2aaSAndroid Build Coastguard Worker     }
254*c8dee2aaSAndroid Build Coastguard Worker 
moveNearby()255*c8dee2aaSAndroid Build Coastguard Worker     bool moveNearby() {
256*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fCount > 0);
257*c8dee2aaSAndroid Build Coastguard Worker         SkOpSegment* segment = &fHead;
258*c8dee2aaSAndroid Build Coastguard Worker         do {
259*c8dee2aaSAndroid Build Coastguard Worker             if (!segment->moveNearby()) {
260*c8dee2aaSAndroid Build Coastguard Worker                 return false;
261*c8dee2aaSAndroid Build Coastguard Worker             }
262*c8dee2aaSAndroid Build Coastguard Worker         } while ((segment = segment->next()));
263*c8dee2aaSAndroid Build Coastguard Worker         return true;
264*c8dee2aaSAndroid Build Coastguard Worker     }
265*c8dee2aaSAndroid Build Coastguard Worker 
next()266*c8dee2aaSAndroid Build Coastguard Worker     SkOpContour* next() {
267*c8dee2aaSAndroid Build Coastguard Worker         return fNext;
268*c8dee2aaSAndroid Build Coastguard Worker     }
269*c8dee2aaSAndroid Build Coastguard Worker 
next()270*c8dee2aaSAndroid Build Coastguard Worker     const SkOpContour* next() const {
271*c8dee2aaSAndroid Build Coastguard Worker         return fNext;
272*c8dee2aaSAndroid Build Coastguard Worker     }
273*c8dee2aaSAndroid Build Coastguard Worker 
operand()274*c8dee2aaSAndroid Build Coastguard Worker     bool operand() const {
275*c8dee2aaSAndroid Build Coastguard Worker         return fOperand;
276*c8dee2aaSAndroid Build Coastguard Worker     }
277*c8dee2aaSAndroid Build Coastguard Worker 
oppXor()278*c8dee2aaSAndroid Build Coastguard Worker     bool oppXor() const {
279*c8dee2aaSAndroid Build Coastguard Worker         return fOppXor;
280*c8dee2aaSAndroid Build Coastguard Worker     }
281*c8dee2aaSAndroid Build Coastguard Worker 
outdentDump()282*c8dee2aaSAndroid Build Coastguard Worker     void outdentDump() const {
283*c8dee2aaSAndroid Build Coastguard Worker         SkDEBUGCODE(fDebugIndent -= 2);
284*c8dee2aaSAndroid Build Coastguard Worker     }
285*c8dee2aaSAndroid Build Coastguard Worker 
286*c8dee2aaSAndroid Build Coastguard Worker     void rayCheck(const SkOpRayHit& base, SkOpRayDir dir, SkOpRayHit** hits, SkArenaAlloc*);
287*c8dee2aaSAndroid Build Coastguard Worker 
reset()288*c8dee2aaSAndroid Build Coastguard Worker     void reset() {
289*c8dee2aaSAndroid Build Coastguard Worker         fTail = nullptr;
290*c8dee2aaSAndroid Build Coastguard Worker         fNext = nullptr;
291*c8dee2aaSAndroid Build Coastguard Worker         fCount = 0;
292*c8dee2aaSAndroid Build Coastguard Worker         fDone = false;
293*c8dee2aaSAndroid Build Coastguard Worker         SkDEBUGCODE(fBounds.setLTRB(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin));
294*c8dee2aaSAndroid Build Coastguard Worker         SkDEBUGCODE(fFirstSorted = -1);
295*c8dee2aaSAndroid Build Coastguard Worker         SkDEBUGCODE(fDebugIndent = 0);
296*c8dee2aaSAndroid Build Coastguard Worker     }
297*c8dee2aaSAndroid Build Coastguard Worker 
resetReverse()298*c8dee2aaSAndroid Build Coastguard Worker     void resetReverse() {
299*c8dee2aaSAndroid Build Coastguard Worker         SkOpContour* next = this;
300*c8dee2aaSAndroid Build Coastguard Worker         do {
301*c8dee2aaSAndroid Build Coastguard Worker             if (!next->count()) {
302*c8dee2aaSAndroid Build Coastguard Worker                 continue;
303*c8dee2aaSAndroid Build Coastguard Worker             }
304*c8dee2aaSAndroid Build Coastguard Worker             next->fCcw = -1;
305*c8dee2aaSAndroid Build Coastguard Worker             next->fReverse = false;
306*c8dee2aaSAndroid Build Coastguard Worker         } while ((next = next->next()));
307*c8dee2aaSAndroid Build Coastguard Worker     }
308*c8dee2aaSAndroid Build Coastguard Worker 
reversed()309*c8dee2aaSAndroid Build Coastguard Worker     bool reversed() const {
310*c8dee2aaSAndroid Build Coastguard Worker         return fReverse;
311*c8dee2aaSAndroid Build Coastguard Worker     }
312*c8dee2aaSAndroid Build Coastguard Worker 
setBounds()313*c8dee2aaSAndroid Build Coastguard Worker     void setBounds() {
314*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fCount > 0);
315*c8dee2aaSAndroid Build Coastguard Worker         const SkOpSegment* segment = &fHead;
316*c8dee2aaSAndroid Build Coastguard Worker         fBounds = segment->bounds();
317*c8dee2aaSAndroid Build Coastguard Worker         while ((segment = segment->next())) {
318*c8dee2aaSAndroid Build Coastguard Worker             fBounds.add(segment->bounds());
319*c8dee2aaSAndroid Build Coastguard Worker         }
320*c8dee2aaSAndroid Build Coastguard Worker     }
321*c8dee2aaSAndroid Build Coastguard Worker 
setCcw(int ccw)322*c8dee2aaSAndroid Build Coastguard Worker     void setCcw(int ccw) {
323*c8dee2aaSAndroid Build Coastguard Worker         fCcw = ccw;
324*c8dee2aaSAndroid Build Coastguard Worker     }
325*c8dee2aaSAndroid Build Coastguard Worker 
setGlobalState(SkOpGlobalState * state)326*c8dee2aaSAndroid Build Coastguard Worker     void setGlobalState(SkOpGlobalState* state) {
327*c8dee2aaSAndroid Build Coastguard Worker         fState = state;
328*c8dee2aaSAndroid Build Coastguard Worker     }
329*c8dee2aaSAndroid Build Coastguard Worker 
setNext(SkOpContour * contour)330*c8dee2aaSAndroid Build Coastguard Worker     void setNext(SkOpContour* contour) {
331*c8dee2aaSAndroid Build Coastguard Worker //        SkASSERT(!fNext == !!contour);
332*c8dee2aaSAndroid Build Coastguard Worker         fNext = contour;
333*c8dee2aaSAndroid Build Coastguard Worker     }
334*c8dee2aaSAndroid Build Coastguard Worker 
setOperand(bool isOp)335*c8dee2aaSAndroid Build Coastguard Worker     void setOperand(bool isOp) {
336*c8dee2aaSAndroid Build Coastguard Worker         fOperand = isOp;
337*c8dee2aaSAndroid Build Coastguard Worker     }
338*c8dee2aaSAndroid Build Coastguard Worker 
setOppXor(bool isOppXor)339*c8dee2aaSAndroid Build Coastguard Worker     void setOppXor(bool isOppXor) {
340*c8dee2aaSAndroid Build Coastguard Worker         fOppXor = isOppXor;
341*c8dee2aaSAndroid Build Coastguard Worker     }
342*c8dee2aaSAndroid Build Coastguard Worker 
setReverse()343*c8dee2aaSAndroid Build Coastguard Worker     void setReverse() {
344*c8dee2aaSAndroid Build Coastguard Worker         fReverse = true;
345*c8dee2aaSAndroid Build Coastguard Worker     }
346*c8dee2aaSAndroid Build Coastguard Worker 
setXor(bool isXor)347*c8dee2aaSAndroid Build Coastguard Worker     void setXor(bool isXor) {
348*c8dee2aaSAndroid Build Coastguard Worker         fXor = isXor;
349*c8dee2aaSAndroid Build Coastguard Worker     }
350*c8dee2aaSAndroid Build Coastguard Worker 
sortAngles()351*c8dee2aaSAndroid Build Coastguard Worker     bool sortAngles() {
352*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(fCount > 0);
353*c8dee2aaSAndroid Build Coastguard Worker         SkOpSegment* segment = &fHead;
354*c8dee2aaSAndroid Build Coastguard Worker         do {
355*c8dee2aaSAndroid Build Coastguard Worker             FAIL_IF(!segment->sortAngles());
356*c8dee2aaSAndroid Build Coastguard Worker         } while ((segment = segment->next()));
357*c8dee2aaSAndroid Build Coastguard Worker         return true;
358*c8dee2aaSAndroid Build Coastguard Worker     }
359*c8dee2aaSAndroid Build Coastguard Worker 
start()360*c8dee2aaSAndroid Build Coastguard Worker     const SkPoint& start() const {
361*c8dee2aaSAndroid Build Coastguard Worker         return fHead.pts()[0];
362*c8dee2aaSAndroid Build Coastguard Worker     }
363*c8dee2aaSAndroid Build Coastguard Worker 
toPartialBackward(SkPathWriter * path)364*c8dee2aaSAndroid Build Coastguard Worker     void toPartialBackward(SkPathWriter* path) const {
365*c8dee2aaSAndroid Build Coastguard Worker         const SkOpSegment* segment = fTail;
366*c8dee2aaSAndroid Build Coastguard Worker         do {
367*c8dee2aaSAndroid Build Coastguard Worker             SkAssertResult(segment->addCurveTo(segment->tail(), segment->head(), path));
368*c8dee2aaSAndroid Build Coastguard Worker         } while ((segment = segment->prev()));
369*c8dee2aaSAndroid Build Coastguard Worker     }
370*c8dee2aaSAndroid Build Coastguard Worker 
toPartialForward(SkPathWriter * path)371*c8dee2aaSAndroid Build Coastguard Worker     void toPartialForward(SkPathWriter* path) const {
372*c8dee2aaSAndroid Build Coastguard Worker         const SkOpSegment* segment = &fHead;
373*c8dee2aaSAndroid Build Coastguard Worker         do {
374*c8dee2aaSAndroid Build Coastguard Worker             SkAssertResult(segment->addCurveTo(segment->head(), segment->tail(), path));
375*c8dee2aaSAndroid Build Coastguard Worker         } while ((segment = segment->next()));
376*c8dee2aaSAndroid Build Coastguard Worker     }
377*c8dee2aaSAndroid Build Coastguard Worker 
378*c8dee2aaSAndroid Build Coastguard Worker     void toReversePath(SkPathWriter* path) const;
379*c8dee2aaSAndroid Build Coastguard Worker     void toPath(SkPathWriter* path) const;
380*c8dee2aaSAndroid Build Coastguard Worker     SkOpSpan* undoneSpan();
381*c8dee2aaSAndroid Build Coastguard Worker 
382*c8dee2aaSAndroid Build Coastguard Worker protected:
383*c8dee2aaSAndroid Build Coastguard Worker     SkOpGlobalState* fState;
384*c8dee2aaSAndroid Build Coastguard Worker     SkOpSegment fHead;
385*c8dee2aaSAndroid Build Coastguard Worker     SkOpSegment* fTail;
386*c8dee2aaSAndroid Build Coastguard Worker     SkOpContour* fNext;
387*c8dee2aaSAndroid Build Coastguard Worker     SkPathOpsBounds fBounds;
388*c8dee2aaSAndroid Build Coastguard Worker     int fCcw;
389*c8dee2aaSAndroid Build Coastguard Worker     int fCount;
390*c8dee2aaSAndroid Build Coastguard Worker     int fFirstSorted;
391*c8dee2aaSAndroid Build Coastguard Worker     bool fDone;  // set by find top segment
392*c8dee2aaSAndroid Build Coastguard Worker     bool fOperand;  // true for the second argument to a binary operator
393*c8dee2aaSAndroid Build Coastguard Worker     bool fReverse;  // true if contour should be reverse written to path (used only by fix winding)
394*c8dee2aaSAndroid Build Coastguard Worker     bool fXor;  // set if original path had even-odd fill
395*c8dee2aaSAndroid Build Coastguard Worker     bool fOppXor;  // set if opposite path had even-odd fill
396*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(int fID;)
397*c8dee2aaSAndroid Build Coastguard Worker     SkDEBUGCODE(mutable int fDebugIndent;)
398*c8dee2aaSAndroid Build Coastguard Worker };
399*c8dee2aaSAndroid Build Coastguard Worker 
400*c8dee2aaSAndroid Build Coastguard Worker class SkOpContourHead : public SkOpContour {
401*c8dee2aaSAndroid Build Coastguard Worker public:
appendContour()402*c8dee2aaSAndroid Build Coastguard Worker     SkOpContour* appendContour() {
403*c8dee2aaSAndroid Build Coastguard Worker         SkOpContour* contour = this->globalState()->allocator()->make<SkOpContour>();
404*c8dee2aaSAndroid Build Coastguard Worker         contour->setNext(nullptr);
405*c8dee2aaSAndroid Build Coastguard Worker         SkOpContour* prev = this;
406*c8dee2aaSAndroid Build Coastguard Worker         SkOpContour* next;
407*c8dee2aaSAndroid Build Coastguard Worker         while ((next = prev->next())) {
408*c8dee2aaSAndroid Build Coastguard Worker             prev = next;
409*c8dee2aaSAndroid Build Coastguard Worker         }
410*c8dee2aaSAndroid Build Coastguard Worker         prev->setNext(contour);
411*c8dee2aaSAndroid Build Coastguard Worker         return contour;
412*c8dee2aaSAndroid Build Coastguard Worker     }
413*c8dee2aaSAndroid Build Coastguard Worker 
joinAllSegments()414*c8dee2aaSAndroid Build Coastguard Worker     void joinAllSegments() {
415*c8dee2aaSAndroid Build Coastguard Worker         SkOpContour* next = this;
416*c8dee2aaSAndroid Build Coastguard Worker         do {
417*c8dee2aaSAndroid Build Coastguard Worker             if (!next->count()) {
418*c8dee2aaSAndroid Build Coastguard Worker                 continue;
419*c8dee2aaSAndroid Build Coastguard Worker             }
420*c8dee2aaSAndroid Build Coastguard Worker             next->joinSegments();
421*c8dee2aaSAndroid Build Coastguard Worker         } while ((next = next->next()));
422*c8dee2aaSAndroid Build Coastguard Worker     }
423*c8dee2aaSAndroid Build Coastguard Worker 
remove(SkOpContour * contour)424*c8dee2aaSAndroid Build Coastguard Worker     void remove(SkOpContour* contour) {
425*c8dee2aaSAndroid Build Coastguard Worker         if (contour == this) {
426*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(this->count() == 0);
427*c8dee2aaSAndroid Build Coastguard Worker             return;
428*c8dee2aaSAndroid Build Coastguard Worker         }
429*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(contour->next() == nullptr);
430*c8dee2aaSAndroid Build Coastguard Worker         SkOpContour* prev = this;
431*c8dee2aaSAndroid Build Coastguard Worker         SkOpContour* next;
432*c8dee2aaSAndroid Build Coastguard Worker         while ((next = prev->next()) != contour) {
433*c8dee2aaSAndroid Build Coastguard Worker             SkASSERT(next);
434*c8dee2aaSAndroid Build Coastguard Worker             prev = next;
435*c8dee2aaSAndroid Build Coastguard Worker         }
436*c8dee2aaSAndroid Build Coastguard Worker         SkASSERT(prev);
437*c8dee2aaSAndroid Build Coastguard Worker         prev->setNext(nullptr);
438*c8dee2aaSAndroid Build Coastguard Worker     }
439*c8dee2aaSAndroid Build Coastguard Worker };
440*c8dee2aaSAndroid Build Coastguard Worker 
441*c8dee2aaSAndroid Build Coastguard Worker class SkOpContourBuilder {
442*c8dee2aaSAndroid Build Coastguard Worker public:
SkOpContourBuilder(SkOpContour * contour)443*c8dee2aaSAndroid Build Coastguard Worker     SkOpContourBuilder(SkOpContour* contour)
444*c8dee2aaSAndroid Build Coastguard Worker         : fContour(contour)
445*c8dee2aaSAndroid Build Coastguard Worker         , fLastIsLine(false) {
446*c8dee2aaSAndroid Build Coastguard Worker     }
447*c8dee2aaSAndroid Build Coastguard Worker 
448*c8dee2aaSAndroid Build Coastguard Worker     void addConic(SkPoint pts[3], SkScalar weight);
449*c8dee2aaSAndroid Build Coastguard Worker     void addCubic(SkPoint pts[4]);
450*c8dee2aaSAndroid Build Coastguard Worker     void addCurve(SkPath::Verb verb, const SkPoint pts[4], SkScalar weight = 1);
451*c8dee2aaSAndroid Build Coastguard Worker     void addLine(const SkPoint pts[2]);
452*c8dee2aaSAndroid Build Coastguard Worker     void addQuad(SkPoint pts[3]);
453*c8dee2aaSAndroid Build Coastguard Worker     void flush();
contour()454*c8dee2aaSAndroid Build Coastguard Worker     SkOpContour* contour() { return fContour; }
setContour(SkOpContour * contour)455*c8dee2aaSAndroid Build Coastguard Worker     void setContour(SkOpContour* contour) { flush(); fContour = contour; }
456*c8dee2aaSAndroid Build Coastguard Worker protected:
457*c8dee2aaSAndroid Build Coastguard Worker     SkOpContour* fContour;
458*c8dee2aaSAndroid Build Coastguard Worker     SkPoint fLastLine[2];
459*c8dee2aaSAndroid Build Coastguard Worker     bool fLastIsLine;
460*c8dee2aaSAndroid Build Coastguard Worker };
461*c8dee2aaSAndroid Build Coastguard Worker 
462*c8dee2aaSAndroid Build Coastguard Worker #endif
463