• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 SkOpContour_DEFINED
8 #define SkOpContour_DEFINED
9 
10 #include "SkOpSegment.h"
11 #include "SkTArray.h"
12 
13 class SkIntersections;
14 class SkOpContour;
15 class SkPathWriter;
16 
17 struct SkCoincidence {
18     SkOpContour* fOther;
19     int fSegments[2];
20     double fTs[2][2];
21     SkPoint fPts[2];
22 };
23 
24 class SkOpContour {
25 public:
SkOpContour()26     SkOpContour() {
27         reset();
28 #ifdef SK_DEBUG
29         fID = ++SkPathOpsDebug::gContourID;
30 #endif
31     }
32 
33     bool operator<(const SkOpContour& rh) const {
34         return fBounds.fTop == rh.fBounds.fTop
35                 ? fBounds.fLeft < rh.fBounds.fLeft
36                 : fBounds.fTop < rh.fBounds.fTop;
37     }
38 
39     bool addCoincident(int index, SkOpContour* other, int otherIndex,
40                        const SkIntersections& ts, bool swap);
41     void addCoincidentPoints();
42 
addCross(const SkOpContour * crosser)43     void addCross(const SkOpContour* crosser) {
44 #ifdef DEBUG_CROSS
45         for (int index = 0; index < fCrosses.count(); ++index) {
46             SkASSERT(fCrosses[index] != crosser);
47         }
48 #endif
49         fCrosses.push_back(crosser);
50     }
51 
addCubic(const SkPoint pts[4])52     void addCubic(const SkPoint pts[4]) {
53         fSegments.push_back().addCubic(pts, fOperand, fXor);
54         fContainsCurves = fContainsCubics = true;
55     }
56 
addLine(const SkPoint pts[2])57     int addLine(const SkPoint pts[2]) {
58         fSegments.push_back().addLine(pts, fOperand, fXor);
59         return fSegments.count();
60     }
61 
addOtherT(int segIndex,int tIndex,double otherT,int otherIndex)62     void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) {
63         fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex);
64     }
65 
66     bool addPartialCoincident(int index, SkOpContour* other, int otherIndex,
67                        const SkIntersections& ts, int ptIndex, bool swap);
68 
addQuad(const SkPoint pts[3])69     int addQuad(const SkPoint pts[3]) {
70         fSegments.push_back().addQuad(pts, fOperand, fXor);
71         fContainsCurves = true;
72         return fSegments.count();
73     }
74 
addT(int segIndex,SkOpContour * other,int otherIndex,const SkPoint & pt,double newT)75     int addT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt, double newT) {
76         setContainsIntercepts();
77         return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT);
78     }
79 
addSelfT(int segIndex,SkOpContour * other,int otherIndex,const SkPoint & pt,double newT)80     int addSelfT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt, double newT) {
81         setContainsIntercepts();
82         return fSegments[segIndex].addSelfT(&other->fSegments[otherIndex], pt, newT);
83     }
84 
bounds()85     const SkPathOpsBounds& bounds() const {
86         return fBounds;
87     }
88 
89     void calcCoincidentWinding();
90     void calcPartialCoincidentWinding();
91 
checkEnds()92     void checkEnds() {
93         if (!fContainsCurves) {
94             return;
95         }
96         int segmentCount = fSegments.count();
97         for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
98             SkOpSegment* segment = &fSegments[sIndex];
99             if (segment->verb() == SkPath::kLine_Verb) {
100                 continue;
101             }
102             if (segment->done()) {
103                 continue;   // likely coincident, nothing to do
104             }
105             segment->checkEnds();
106         }
107     }
108 
109     // if same point has different T values, choose a common T
checkTiny()110     void checkTiny() {
111         int segmentCount = fSegments.count();
112         if (segmentCount <= 2) {
113             return;
114         }
115         for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
116             fSegments[sIndex].checkTiny();
117         }
118     }
119 
complete()120     void complete() {
121         setBounds();
122         fContainsIntercepts = false;
123     }
124 
containsCubics()125     bool containsCubics() const {
126         return fContainsCubics;
127     }
128 
crosses(const SkOpContour * crosser)129     bool crosses(const SkOpContour* crosser) const {
130         for (int index = 0; index < fCrosses.count(); ++index) {
131             if (fCrosses[index] == crosser) {
132                 return true;
133             }
134         }
135         return false;
136     }
137 
done()138     bool done() const {
139         return fDone;
140     }
141 
end()142     const SkPoint& end() const {
143         const SkOpSegment& segment = fSegments.back();
144         return segment.pts()[SkPathOpsVerbToPoints(segment.verb())];
145     }
146 
fixOtherTIndex()147     void fixOtherTIndex() {
148         int segmentCount = fSegments.count();
149         for (int sIndex = 0; sIndex < segmentCount; ++sIndex) {
150             fSegments[sIndex].fixOtherTIndex();
151         }
152     }
153 
joinCoincidence()154     void joinCoincidence() {
155         joinCoincidence(fCoincidences, false);
156         joinCoincidence(fPartialCoincidences, true);
157     }
158 
159     SkOpSegment* nonVerticalSegment(int* start, int* end);
160 
operand()161     bool operand() const {
162         return fOperand;
163     }
164 
reset()165     void reset() {
166         fSegments.reset();
167         fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax);
168         fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = false;
169     }
170 
segments()171     SkTArray<SkOpSegment>& segments() {
172         return fSegments;
173     }
174 
setContainsIntercepts()175     void setContainsIntercepts() {
176         fContainsIntercepts = true;
177     }
178 
setOperand(bool isOp)179     void setOperand(bool isOp) {
180         fOperand = isOp;
181     }
182 
setOppXor(bool isOppXor)183     void setOppXor(bool isOppXor) {
184         fOppXor = isOppXor;
185         int segmentCount = fSegments.count();
186         for (int test = 0; test < segmentCount; ++test) {
187             fSegments[test].setOppXor(isOppXor);
188         }
189     }
190 
setXor(bool isXor)191     void setXor(bool isXor) {
192         fXor = isXor;
193     }
194 
195     void sortSegments();
196 
start()197     const SkPoint& start() const {
198         return fSegments.front().pts()[0];
199     }
200 
201     void toPath(SkPathWriter* path) const;
202 
toPartialBackward(SkPathWriter * path)203     void toPartialBackward(SkPathWriter* path) const {
204         int segmentCount = fSegments.count();
205         for (int test = segmentCount - 1; test >= 0; --test) {
206             fSegments[test].addCurveTo(1, 0, path, true);
207         }
208     }
209 
toPartialForward(SkPathWriter * path)210     void toPartialForward(SkPathWriter* path) const {
211         int segmentCount = fSegments.count();
212         for (int test = 0; test < segmentCount; ++test) {
213             fSegments[test].addCurveTo(0, 1, path, true);
214         }
215     }
216 
217     void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment** topStart);
218     SkOpSegment* undoneSegment(int* start, int* end);
219 
updateSegment(int index,const SkPoint * pts)220     int updateSegment(int index, const SkPoint* pts) {
221         SkOpSegment& segment = fSegments[index];
222         segment.updatePts(pts);
223         return SkPathOpsVerbToPoints(segment.verb()) + 1;
224     }
225 
226 #if DEBUG_TEST
debugSegments()227     SkTArray<SkOpSegment>& debugSegments() {
228         return fSegments;
229     }
230 #endif
231 
232 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY
debugShowActiveSpans()233     void debugShowActiveSpans() {
234         for (int index = 0; index < fSegments.count(); ++index) {
235             fSegments[index].debugShowActiveSpans();
236         }
237     }
238 #endif
239 
240 #if DEBUG_SHOW_WINDING
241     int debugShowWindingValues(int totalSegments, int ofInterest);
242     static void debugShowWindingValues(const SkTArray<SkOpContour*, true>& contourList);
243 #endif
244 
245 private:
246     void calcCommonCoincidentWinding(const SkCoincidence& );
247     void joinCoincidence(const SkTArray<SkCoincidence, true>& , bool partial);
248     void setBounds();
249 
250     SkTArray<SkOpSegment> fSegments;
251     SkTArray<SkOpSegment*, true> fSortedSegments;
252     int fFirstSorted;
253     SkTArray<SkCoincidence, true> fCoincidences;
254     SkTArray<SkCoincidence, true> fPartialCoincidences;
255     SkTArray<const SkOpContour*, true> fCrosses;
256     SkPathOpsBounds fBounds;
257     bool fContainsIntercepts;  // FIXME: is this used by anybody?
258     bool fContainsCubics;
259     bool fContainsCurves;
260     bool fDone;
261     bool fOperand;  // true for the second argument to a binary operator
262     bool fXor;
263     bool fOppXor;
264 #ifdef SK_DEBUG
265     int fID;
266 #endif
267 };
268 
269 #endif
270