1 /*
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 SkOpCoincidence_DEFINED
8 #define SkOpCoincidence_DEFINED
9 
10 #include "include/private/SkTDArray.h"
11 #include "src/core/SkArenaAlloc.h"
12 #include "src/pathops/SkOpSpan.h"
13 #include "src/pathops/SkPathOpsTypes.h"
14 
15 class SkOpPtT;
16 class SkOpSpanBase;
17 
18 class SkCoincidentSpans {
19 public:
20     const SkOpPtT* coinPtTEnd() const;
21     const SkOpPtT* coinPtTStart() const;
22 
23     // These return non-const pointers so that, as copies, they can be added
24     // to a new span pair
coinPtTEndWritable()25     SkOpPtT* coinPtTEndWritable() const { return const_cast<SkOpPtT*>(fCoinPtTEnd); }
coinPtTStartWritable()26     SkOpPtT* coinPtTStartWritable() const { return const_cast<SkOpPtT*>(fCoinPtTStart); }
27 
28     bool collapsed(const SkOpPtT* ) const;
29     bool contains(const SkOpPtT* s, const SkOpPtT* e) const;
30     void correctEnds();
31     void correctOneEnd(const SkOpPtT* (SkCoincidentSpans::* getEnd)() const,
32                        void (SkCoincidentSpans::* setEnd)(const SkOpPtT* ptT) );
33 
34 #if DEBUG_COIN
35     void debugCorrectEnds(SkPathOpsDebug::GlitchLog* log) const;
36     void debugCorrectOneEnd(SkPathOpsDebug::GlitchLog* log,
37                             const SkOpPtT* (SkCoincidentSpans::* getEnd)() const,
38                             void (SkCoincidentSpans::* setEnd)(const SkOpPtT* ptT) const) const;
39     bool debugExpand(SkPathOpsDebug::GlitchLog* log) const;
40 #endif
41 
debugID()42     const char* debugID() const {
43 #if DEBUG_COIN
44         return fGlobalState->debugCoinDictEntry().fFunctionName;
45 #else
46         return nullptr;
47 #endif
48     }
49 
50     void debugShow() const;
51 #ifdef SK_DEBUG
52     void debugStartCheck(const SkOpSpanBase* outer, const SkOpSpanBase* over,
53             const SkOpGlobalState* debugState) const;
54 #endif
55     void dump() const;
56     bool expand();
57     bool extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
58                 const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd);
flipped()59     bool flipped() const { return fOppPtTStart->fT > fOppPtTEnd->fT; }
SkDEBUGCODE(SkOpGlobalState * globalState (){ return fGlobalState; })60     SkDEBUGCODE(SkOpGlobalState* globalState() { return fGlobalState; })
61 
62     void init(SkDEBUGCODE(SkOpGlobalState* globalState)) {
63         sk_bzero(this, sizeof(*this));
64         SkDEBUGCODE(fGlobalState = globalState);
65     }
66 
next()67     SkCoincidentSpans* next() { return fNext; }
next()68     const SkCoincidentSpans* next() const { return fNext; }
nextPtr()69     SkCoincidentSpans** nextPtr() { return &fNext; }
70     const SkOpPtT* oppPtTStart() const;
71     const SkOpPtT* oppPtTEnd() const;
72     // These return non-const pointers so that, as copies, they can be added
73     // to a new span pair
oppPtTStartWritable()74     SkOpPtT* oppPtTStartWritable() const { return const_cast<SkOpPtT*>(fOppPtTStart); }
oppPtTEndWritable()75     SkOpPtT* oppPtTEndWritable() const { return const_cast<SkOpPtT*>(fOppPtTEnd); }
76     bool ordered(bool* result) const;
77 
78     void set(SkCoincidentSpans* next, const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
79             const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd);
80 
setCoinPtTEnd(const SkOpPtT * ptT)81     void setCoinPtTEnd(const SkOpPtT* ptT) {
82         SkOPASSERT(ptT == ptT->span()->ptT());
83         SkOPASSERT(!fCoinPtTStart || ptT->fT != fCoinPtTStart->fT);
84         SkASSERT(!fCoinPtTStart || fCoinPtTStart->segment() == ptT->segment());
85         fCoinPtTEnd = ptT;
86         ptT->setCoincident();
87     }
88 
setCoinPtTStart(const SkOpPtT * ptT)89     void setCoinPtTStart(const SkOpPtT* ptT) {
90         SkOPASSERT(ptT == ptT->span()->ptT());
91         SkOPASSERT(!fCoinPtTEnd || ptT->fT != fCoinPtTEnd->fT);
92         SkASSERT(!fCoinPtTEnd || fCoinPtTEnd->segment() == ptT->segment());
93         fCoinPtTStart = ptT;
94         ptT->setCoincident();
95     }
96 
setEnds(const SkOpPtT * coinPtTEnd,const SkOpPtT * oppPtTEnd)97     void setEnds(const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTEnd) {
98         this->setCoinPtTEnd(coinPtTEnd);
99         this->setOppPtTEnd(oppPtTEnd);
100     }
101 
setOppPtTEnd(const SkOpPtT * ptT)102     void setOppPtTEnd(const SkOpPtT* ptT) {
103         SkOPASSERT(ptT == ptT->span()->ptT());
104         SkOPASSERT(!fOppPtTStart || ptT->fT != fOppPtTStart->fT);
105         SkASSERT(!fOppPtTStart || fOppPtTStart->segment() == ptT->segment());
106         fOppPtTEnd = ptT;
107         ptT->setCoincident();
108     }
109 
setOppPtTStart(const SkOpPtT * ptT)110     void setOppPtTStart(const SkOpPtT* ptT) {
111         SkOPASSERT(ptT == ptT->span()->ptT());
112         SkOPASSERT(!fOppPtTEnd || ptT->fT != fOppPtTEnd->fT);
113         SkASSERT(!fOppPtTEnd || fOppPtTEnd->segment() == ptT->segment());
114         fOppPtTStart = ptT;
115         ptT->setCoincident();
116     }
117 
setStarts(const SkOpPtT * coinPtTStart,const SkOpPtT * oppPtTStart)118     void setStarts(const SkOpPtT* coinPtTStart, const SkOpPtT* oppPtTStart) {
119         this->setCoinPtTStart(coinPtTStart);
120         this->setOppPtTStart(oppPtTStart);
121     }
122 
setNext(SkCoincidentSpans * next)123     void setNext(SkCoincidentSpans* next) { fNext = next; }
124 
125 private:
126     SkCoincidentSpans* fNext;
127     const SkOpPtT* fCoinPtTStart;
128     const SkOpPtT* fCoinPtTEnd;
129     const SkOpPtT* fOppPtTStart;
130     const SkOpPtT* fOppPtTEnd;
131     SkDEBUGCODE(SkOpGlobalState* fGlobalState);
132 };
133 
134 class SkOpCoincidence {
135 public:
SkOpCoincidence(SkOpGlobalState * globalState)136     SkOpCoincidence(SkOpGlobalState* globalState)
137         : fHead(nullptr)
138         , fTop(nullptr)
139         , fGlobalState(globalState)
140         , fContinue(false)
141         , fSpanDeleted(false)
142         , fPtAllocated(false)
143         , fCoinExtended(false)
144         , fSpanMerged(false) {
145         globalState->setCoincidence(this);
146     }
147 
148     void add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart,
149              SkOpPtT* oppPtTEnd);
150     bool addEndMovedSpans(DEBUG_COIN_DECLARE_ONLY_PARAMS());
151     bool addExpanded(DEBUG_COIN_DECLARE_ONLY_PARAMS());
152     bool addMissing(bool* added  DEBUG_COIN_DECLARE_PARAMS());
153     bool apply(DEBUG_COIN_DECLARE_ONLY_PARAMS());
154     bool contains(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd,
155                   const SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd) const;
156     void correctEnds(DEBUG_COIN_DECLARE_ONLY_PARAMS());
157 
158 #if DEBUG_COIN
159     void debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* log) const;
160     void debugAddExpanded(SkPathOpsDebug::GlitchLog* ) const;
161     void debugAddMissing(SkPathOpsDebug::GlitchLog* , bool* added) const;
162     void debugAddOrOverlap(SkPathOpsDebug::GlitchLog* log,
163                            const SkOpSegment* coinSeg, const SkOpSegment* oppSeg,
164                            double coinTs, double coinTe, double oppTs, double oppTe,
165                            bool* added) const;
166 #endif
167 
debugAngle(int id)168     const SkOpAngle* debugAngle(int id) const {
169         return SkDEBUGRELEASE(fGlobalState->debugAngle(id), nullptr);
170     }
171 
172     void debugCheckBetween() const;
173 
174 #if DEBUG_COIN
175     void debugCheckValid(SkPathOpsDebug::GlitchLog* log) const;
176 #endif
177 
debugContour(int id)178     SkOpContour* debugContour(int id) const {
179         return SkDEBUGRELEASE(fGlobalState->debugContour(id), nullptr);
180     }
181 
182 #if DEBUG_COIN
183     void debugCorrectEnds(SkPathOpsDebug::GlitchLog* log) const;
184     bool debugExpand(SkPathOpsDebug::GlitchLog* ) const;
185     void debugMark(SkPathOpsDebug::GlitchLog* ) const;
186     void debugMarkCollapsed(SkPathOpsDebug::GlitchLog* ,
187                             const SkCoincidentSpans* coin, const SkOpPtT* test) const;
188     void debugMarkCollapsed(SkPathOpsDebug::GlitchLog* , const SkOpPtT* test) const;
189 #endif
190 
debugPtT(int id)191     const SkOpPtT* debugPtT(int id) const {
192         return SkDEBUGRELEASE(fGlobalState->debugPtT(id), nullptr);
193     }
194 
debugSegment(int id)195     const SkOpSegment* debugSegment(int id) const {
196         return SkDEBUGRELEASE(fGlobalState->debugSegment(id), nullptr);
197     }
198 
199 #if DEBUG_COIN
200     void debugRelease(SkPathOpsDebug::GlitchLog* , const SkCoincidentSpans* ,
201                       const SkCoincidentSpans* ) const;
202     void debugRelease(SkPathOpsDebug::GlitchLog* , const SkOpSegment* ) const;
203 #endif
204     void debugShowCoincidence() const;
205 
debugSpan(int id)206     const SkOpSpanBase* debugSpan(int id) const {
207         return SkDEBUGRELEASE(fGlobalState->debugSpan(id), nullptr);
208     }
209 
210     void debugValidate() const;
211     void dump() const;
212     bool expand(DEBUG_COIN_DECLARE_ONLY_PARAMS());
213     bool extend(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart,
214                 const SkOpPtT* oppPtTEnd);
215     bool findOverlaps(SkOpCoincidence*  DEBUG_COIN_DECLARE_PARAMS()) const;
216     void fixUp(SkOpPtT* deleted, const SkOpPtT* kept);
217 
globalState()218     SkOpGlobalState* globalState() {
219         return fGlobalState;
220     }
221 
globalState()222     const SkOpGlobalState* globalState() const {
223         return fGlobalState;
224     }
225 
isEmpty()226     bool isEmpty() const {
227         return !fHead && !fTop;
228     }
229 
230     bool mark(DEBUG_COIN_DECLARE_ONLY_PARAMS());
231     void markCollapsed(SkOpPtT* );
232 
Ordered(const SkOpPtT * coinPtTStart,const SkOpPtT * oppPtTStart)233     static bool Ordered(const SkOpPtT* coinPtTStart, const SkOpPtT* oppPtTStart) {
234       return Ordered(coinPtTStart->segment(), oppPtTStart->segment());
235     }
236 
237     static bool Ordered(const SkOpSegment* coin, const SkOpSegment* opp);
238     void release(const SkOpSegment* );
239     void releaseDeleted();
240 
241 private:
add(const SkOpPtT * coinPtTStart,const SkOpPtT * coinPtTEnd,const SkOpPtT * oppPtTStart,const SkOpPtT * oppPtTEnd)242     void add(const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, const SkOpPtT* oppPtTStart,
243              const SkOpPtT* oppPtTEnd) {
244         this->add(const_cast<SkOpPtT*>(coinPtTStart), const_cast<SkOpPtT*>(coinPtTEnd),
245             const_cast<SkOpPtT*>(oppPtTStart), const_cast<SkOpPtT*>(oppPtTEnd));
246     }
247 
248     bool addEndMovedSpans(const SkOpSpan* base, const SkOpSpanBase* testSpan);
249     bool addEndMovedSpans(const SkOpPtT* ptT);
250 
251     bool addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over2s,
252                       double tStart, double tEnd, SkOpSegment* coinSeg, SkOpSegment* oppSeg,
253                       bool* added
254                       SkDEBUGPARAMS(const SkOpPtT* over1e) SkDEBUGPARAMS(const SkOpPtT* over2e));
255     bool addOrOverlap(SkOpSegment* coinSeg, SkOpSegment* oppSeg,
256                       double coinTs, double coinTe, double oppTs, double oppTe, bool* added);
257     bool addOverlap(const SkOpSegment* seg1, const SkOpSegment* seg1o,
258                     const SkOpSegment* seg2, const SkOpSegment* seg2o,
259                     const SkOpPtT* overS, const SkOpPtT* overE);
260     bool checkOverlap(SkCoincidentSpans* check,
261                       const SkOpSegment* coinSeg, const SkOpSegment* oppSeg,
262                       double coinTs, double coinTe, double oppTs, double oppTe,
263                       SkTDArray<SkCoincidentSpans*>* overlaps) const;
264     bool contains(const SkOpSegment* seg, const SkOpSegment* opp, double oppT) const;
265     bool contains(const SkCoincidentSpans* coin, const SkOpSegment* seg,
266                   const SkOpSegment* opp, double oppT) const;
267 #if DEBUG_COIN
268     void debugAddIfMissing(SkPathOpsDebug::GlitchLog* ,
269                            const SkCoincidentSpans* outer, const SkOpPtT* over1s,
270                            const SkOpPtT* over1e) const;
271     void debugAddIfMissing(SkPathOpsDebug::GlitchLog* ,
272                            const SkOpPtT* over1s, const SkOpPtT* over2s,
273                            double tStart, double tEnd,
274                            const SkOpSegment* coinSeg, const SkOpSegment* oppSeg, bool* added,
275                            const SkOpPtT* over1e, const SkOpPtT* over2e) const;
276     void debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* ,
277                                const SkOpSpan* base, const SkOpSpanBase* testSpan) const;
278     void debugAddEndMovedSpans(SkPathOpsDebug::GlitchLog* ,
279                                const SkOpPtT* ptT) const;
280 #endif
281     void fixUp(SkCoincidentSpans* coin, SkOpPtT* deleted, const SkOpPtT* kept);
282     void markCollapsed(SkCoincidentSpans* head, SkOpPtT* test);
283     bool overlap(const SkOpPtT* coinStart1, const SkOpPtT* coinEnd1,
284                  const SkOpPtT* coinStart2, const SkOpPtT* coinEnd2,
285                  double* overS, double* overE) const;
286     bool release(SkCoincidentSpans* coin, SkCoincidentSpans* );
287     void releaseDeleted(SkCoincidentSpans* );
288     void restoreHead();
289     // return coinPtT->segment()->t mapped from overS->fT <= t <= overE->fT
290     static double TRange(const SkOpPtT* overS, double t, const SkOpSegment* coinPtT
291                          SkDEBUGPARAMS(const SkOpPtT* overE));
292 
293     SkCoincidentSpans* fHead;
294     SkCoincidentSpans* fTop;
295     SkOpGlobalState* fGlobalState;
296     bool fContinue;
297     bool fSpanDeleted;
298     bool fPtAllocated;
299     bool fCoinExtended;
300     bool fSpanMerged;
301 };
302 
303 #endif
304