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