OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2013 Google Inc. | 2 * Copyright 2013 Google Inc. |
3 * | 3 * |
4 * Use of this source code is governed by a BSD-style license that can be | 4 * Use of this source code is governed by a BSD-style license that can be |
5 * found in the LICENSE file. | 5 * found in the LICENSE file. |
6 */ | 6 */ |
7 #ifndef SkOpContour_DEFINED | 7 #ifndef SkOpContour_DEFINED |
8 #define SkOpContour_DEFINED | 8 #define SkOpContour_DEFINED |
9 | 9 |
10 #include "SkOpSegment.h" | 10 #include "SkOpSegment.h" |
11 #include "SkTArray.h" | 11 #include "SkTDArray.h" |
| 12 #include "SkTSort.h" |
12 | 13 |
13 #if defined(SK_DEBUG) || !FORCE_RELEASE | 14 class SkChunkAlloc; |
14 #include "SkThread.h" | |
15 #endif | |
16 | |
17 class SkIntersections; | |
18 class SkOpContour; | |
19 class SkPathWriter; | 15 class SkPathWriter; |
20 | 16 |
21 struct SkCoincidence { | |
22 SkOpContour* fOther; | |
23 int fSegments[2]; | |
24 double fTs[2][2]; | |
25 SkPoint fPts[2][2]; | |
26 int fNearly[2]; | |
27 }; | |
28 | |
29 class SkOpContour { | 17 class SkOpContour { |
30 public: | 18 public: |
31 SkOpContour() { | 19 SkOpContour() { |
32 reset(); | 20 reset(); |
33 #if defined(SK_DEBUG) || !FORCE_RELEASE | 21 } |
34 fID = sk_atomic_inc(&SkPathOpsDebug::gContourID); | 22 |
35 #endif | 23 ~SkOpContour() { |
| 24 if (fNext) { |
| 25 fNext->~SkOpContour(); |
| 26 } |
36 } | 27 } |
37 | 28 |
38 bool operator<(const SkOpContour& rh) const { | 29 bool operator<(const SkOpContour& rh) const { |
39 return fBounds.fTop == rh.fBounds.fTop | 30 return fBounds.fTop == rh.fBounds.fTop |
40 ? fBounds.fLeft < rh.fBounds.fLeft | 31 ? fBounds.fLeft < rh.fBounds.fLeft |
41 : fBounds.fTop < rh.fBounds.fTop; | 32 : fBounds.fTop < rh.fBounds.fTop; |
42 } | 33 } |
43 | 34 |
44 bool addCoincident(int index, SkOpContour* other, int otherIndex, | 35 void addCubic(SkPoint pts[4], SkChunkAlloc* allocator) { |
45 const SkIntersections& ts, bool swap); | 36 appendSegment(allocator).addCubic(pts, this); |
46 void addCoincidentPoints(); | 37 } |
47 | 38 |
48 void addCross(const SkOpContour* crosser) { | 39 void addCurve(SkPath::Verb verb, const SkPoint pts[4], SkChunkAlloc* allocat
or); |
49 #ifdef DEBUG_CROSS | 40 |
50 for (int index = 0; index < fCrosses.count(); ++index) { | 41 void addLine(SkPoint pts[2], SkChunkAlloc* allocator) { |
51 SkASSERT(fCrosses[index] != crosser); | 42 appendSegment(allocator).addLine(pts, this); |
52 } | 43 } |
53 #endif | 44 |
54 fCrosses.push_back(crosser); | 45 void addQuad(SkPoint pts[3], SkChunkAlloc* allocator) { |
55 } | 46 appendSegment(allocator).addQuad(pts, this); |
56 | 47 } |
57 void addCubic(const SkPoint pts[4]) { | 48 |
58 fSegments.push_back().addCubic(pts, fOperand, fXor); | 49 void align() { |
59 fContainsCurves = fContainsCubics = true; | 50 SkASSERT(fCount > 0); |
60 } | 51 SkOpSegment* segment = &fHead; |
61 | 52 do { |
62 int addLine(const SkPoint pts[2]) { | 53 segment->align(); |
63 fSegments.push_back().addLine(pts, fOperand, fXor); | 54 } while ((segment = segment->next())); |
64 return fSegments.count(); | 55 } |
65 } | 56 |
66 | 57 SkOpSegment& appendSegment(SkChunkAlloc* allocator) { |
67 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) { | 58 SkOpSegment* result = fCount++ |
68 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex); | 59 ? SkOpTAllocator<SkOpSegment>::Allocate(allocator) : &fHead; |
69 } | 60 result->setPrev(fTail); |
70 | 61 if (fTail) { |
71 bool addPartialCoincident(int index, SkOpContour* other, int otherIndex, | 62 fTail->setNext(result); |
72 const SkIntersections& ts, int ptIndex, bool swap); | 63 } |
73 | 64 fTail = result; |
74 int addQuad(const SkPoint pts[3]) { | 65 return *result; |
75 fSegments.push_back().addQuad(pts, fOperand, fXor); | 66 } |
76 fContainsCurves = true; | 67 |
77 return fSegments.count(); | 68 SkOpContour* appendContour(SkChunkAlloc* allocator) { |
78 } | 69 SkOpContour* contour = SkOpTAllocator<SkOpContour>::New(allocator); |
79 | 70 contour->setNext(NULL); |
80 int addT(int segIndex, SkOpContour* other, int otherIndex, const SkPoint& pt
, double newT) { | 71 SkOpContour* prev = this; |
81 setContainsIntercepts(); | 72 SkOpContour* next; |
82 return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT)
; | 73 while ((next = prev->next())) { |
83 } | 74 prev = next; |
84 | 75 } |
85 int addSelfT(int segIndex, const SkPoint& pt, double newT) { | 76 prev->setNext(contour); |
86 setContainsIntercepts(); | 77 return contour; |
87 return fSegments[segIndex].addSelfT(pt, newT); | 78 } |
88 } | 79 |
89 | |
90 void align(const SkOpSegment::AlignedSpan& aligned, bool swap, SkCoincidence
* coincidence); | |
91 void alignCoincidence(const SkOpSegment::AlignedSpan& aligned, | |
92 SkTArray<SkCoincidence, true>* coincidences); | |
93 | |
94 void alignCoincidence(const SkOpSegment::AlignedSpan& aligned) { | |
95 alignCoincidence(aligned, &fCoincidences); | |
96 alignCoincidence(aligned, &fPartialCoincidences); | |
97 } | |
98 | |
99 void alignMultiples(SkTDArray<SkOpSegment::AlignedSpan>* aligned) { | |
100 int segmentCount = fSegments.count(); | |
101 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { | |
102 SkOpSegment& segment = fSegments[sIndex]; | |
103 if (segment.hasMultiples()) { | |
104 segment.alignMultiples(aligned); | |
105 } | |
106 } | |
107 } | |
108 | |
109 void alignTPt(int segmentIndex, const SkOpContour* other, int otherIndex, | |
110 bool swap, int tIndex, SkIntersections* ts, SkPoint* point) co
nst; | |
111 | |
112 const SkPathOpsBounds& bounds() const { | 80 const SkPathOpsBounds& bounds() const { |
113 return fBounds; | 81 return fBounds; |
114 } | 82 } |
115 | 83 |
116 bool calcAngles(); | 84 void calcAngles(SkChunkAlloc* allocator) { |
117 bool calcCoincidentWinding(); | 85 SkASSERT(fCount > 0); |
118 void calcPartialCoincidentWinding(); | 86 SkOpSegment* segment = &fHead; |
119 | 87 do { |
120 void checkDuplicates() { | 88 segment->calcAngles(allocator); |
121 int segmentCount = fSegments.count(); | 89 } while ((segment = segment->next())); |
122 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { | 90 } |
123 SkOpSegment& segment = fSegments[sIndex]; | 91 |
124 if (segment.count() > 2) { | 92 void complete() { |
125 segment.checkDuplicates(); | 93 setBounds(); |
| 94 } |
| 95 |
| 96 int count() const { |
| 97 return fCount; |
| 98 } |
| 99 |
| 100 int debugID() const { |
| 101 return PATH_OPS_DEBUG_RELEASE(fID, -1); |
| 102 } |
| 103 |
| 104 int debugIndent() const { |
| 105 return PATH_OPS_DEBUG_RELEASE(fIndent, 0); |
| 106 } |
| 107 |
| 108 #if DEBUG_ACTIVE_SPANS |
| 109 void debugShowActiveSpans() { |
| 110 SkOpSegment* segment = &fHead; |
| 111 do { |
| 112 segment->debugShowActiveSpans(); |
| 113 } while ((segment = segment->next())); |
| 114 } |
| 115 #endif |
| 116 |
| 117 const SkOpAngle* debugAngle(int id) const { |
| 118 return PATH_OPS_DEBUG_RELEASE(globalState()->debugAngle(id), NULL); |
| 119 } |
| 120 |
| 121 SkOpContour* debugContour(int id) { |
| 122 return PATH_OPS_DEBUG_RELEASE(globalState()->debugContour(id), NULL); |
| 123 } |
| 124 |
| 125 const SkOpPtT* debugPtT(int id) const { |
| 126 return PATH_OPS_DEBUG_RELEASE(globalState()->debugPtT(id), NULL); |
| 127 } |
| 128 |
| 129 const SkOpSegment* debugSegment(int id) const { |
| 130 return PATH_OPS_DEBUG_RELEASE(globalState()->debugSegment(id), NULL); |
| 131 } |
| 132 |
| 133 const SkOpSpanBase* debugSpan(int id) const { |
| 134 return PATH_OPS_DEBUG_RELEASE(globalState()->debugSpan(id), NULL); |
| 135 } |
| 136 |
| 137 SkOpGlobalState* globalState() const { |
| 138 return fState; |
| 139 } |
| 140 |
| 141 void debugValidate() const { |
| 142 #if DEBUG_VALIDATE |
| 143 const SkOpSegment* segment = &fHead; |
| 144 const SkOpSegment* prior = NULL; |
| 145 do { |
| 146 segment->debugValidate(); |
| 147 SkASSERT(segment->prev() == prior); |
| 148 prior = segment; |
| 149 } while ((segment = segment->next())); |
| 150 SkASSERT(prior == fTail); |
| 151 #endif |
| 152 } |
| 153 |
| 154 bool done() const { |
| 155 return fDone; |
| 156 } |
| 157 |
| 158 void dump(); |
| 159 void dumpAll(); |
| 160 void dumpAngles() const; |
| 161 void dumpPt(int ) const; |
| 162 void dumpPts() const; |
| 163 void dumpPtsX() const; |
| 164 void dumpSegment(int ) const; |
| 165 void dumpSegments(SkPathOp op) const; |
| 166 void dumpSpan(int ) const; |
| 167 void dumpSpans() const; |
| 168 |
| 169 const SkPoint& end() const { |
| 170 return fTail->pts()[SkPathOpsVerbToPoints(fTail->verb())]; |
| 171 } |
| 172 |
| 173 SkOpSegment* first() { |
| 174 SkASSERT(fCount > 0); |
| 175 return &fHead; |
| 176 } |
| 177 |
| 178 const SkOpSegment* first() const { |
| 179 SkASSERT(fCount > 0); |
| 180 return &fHead; |
| 181 } |
| 182 |
| 183 void indentDump() { |
| 184 PATH_OPS_DEBUG_CODE(fIndent += 2); |
| 185 } |
| 186 |
| 187 void init(SkOpGlobalState* globalState, bool operand, bool isXor) { |
| 188 fState = globalState; |
| 189 fOperand = operand; |
| 190 fXor = isXor; |
| 191 } |
| 192 |
| 193 bool isXor() const { |
| 194 return fXor; |
| 195 } |
| 196 |
| 197 void missingCoincidence(SkOpCoincidence* coincidences, SkChunkAlloc* allocat
or) { |
| 198 SkASSERT(fCount > 0); |
| 199 SkOpSegment* segment = &fHead; |
| 200 do { |
| 201 if (fState->angleCoincidence()) { |
| 202 segment->checkAngleCoin(coincidences, allocator); |
| 203 } else { |
| 204 segment->missingCoincidence(coincidences, allocator); |
126 } | 205 } |
127 } | 206 } while ((segment = segment->next())); |
128 } | 207 } |
129 | 208 |
130 bool checkEnds() { | 209 bool moveNearby() { |
131 if (!fContainsCurves) { | 210 SkASSERT(fCount > 0); |
132 return true; | 211 SkOpSegment* segment = &fHead; |
133 } | 212 do { |
134 int segmentCount = fSegments.count(); | 213 if (!segment->moveNearby()) { |
135 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { | |
136 SkOpSegment* segment = &fSegments[sIndex]; | |
137 if (segment->verb() == SkPath::kLine_Verb) { | |
138 continue; | |
139 } | |
140 if (segment->done()) { | |
141 continue; // likely coincident, nothing to do | |
142 } | |
143 if (!segment->checkEnds()) { | |
144 return false; | 214 return false; |
145 } | 215 } |
146 } | 216 } while ((segment = segment->next())); |
147 return true; | 217 return true; |
148 } | 218 } |
149 | 219 |
150 void checkMultiples() { | 220 SkOpContour* next() { |
151 int segmentCount = fSegments.count(); | 221 return fNext; |
152 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { | 222 } |
153 SkOpSegment& segment = fSegments[sIndex]; | 223 |
154 if (segment.count() > 2) { | 224 const SkOpContour* next() const { |
155 segment.checkMultiples(); | 225 return fNext; |
156 fMultiples |= segment.hasMultiples(); | 226 } |
157 } | 227 |
158 } | 228 SkOpSegment* nonVerticalSegment(SkOpSpanBase** start, SkOpSpanBase** end); |
159 } | |
160 | |
161 void checkSmall() { | |
162 int segmentCount = fSegments.count(); | |
163 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { | |
164 SkOpSegment& segment = fSegments[sIndex]; | |
165 // OPTIMIZATION : skip segments that are done? | |
166 if (segment.hasSmall()) { | |
167 segment.checkSmall(); | |
168 } | |
169 } | |
170 } | |
171 | |
172 // if same point has different T values, choose a common T | |
173 void checkTiny() { | |
174 int segmentCount = fSegments.count(); | |
175 if (segmentCount <= 2) { | |
176 return; | |
177 } | |
178 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { | |
179 SkOpSegment& segment = fSegments[sIndex]; | |
180 if (segment.hasTiny()) { | |
181 segment.checkTiny(); | |
182 } | |
183 } | |
184 } | |
185 | |
186 void complete() { | |
187 setBounds(); | |
188 fContainsIntercepts = false; | |
189 } | |
190 | |
191 bool containsCubics() const { | |
192 return fContainsCubics; | |
193 } | |
194 | |
195 bool crosses(const SkOpContour* crosser) const { | |
196 for (int index = 0; index < fCrosses.count(); ++index) { | |
197 if (fCrosses[index] == crosser) { | |
198 return true; | |
199 } | |
200 } | |
201 return false; | |
202 } | |
203 | |
204 bool done() const { | |
205 return fDone; | |
206 } | |
207 | |
208 const SkPoint& end() const { | |
209 const SkOpSegment& segment = fSegments.back(); | |
210 return segment.pts()[SkPathOpsVerbToPoints(segment.verb())]; | |
211 } | |
212 | |
213 void fixOtherTIndex() { | |
214 int segmentCount = fSegments.count(); | |
215 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { | |
216 fSegments[sIndex].fixOtherTIndex(); | |
217 } | |
218 } | |
219 | |
220 bool hasMultiples() const { | |
221 return fMultiples; | |
222 } | |
223 | |
224 void joinCoincidence() { | |
225 joinCoincidence(fCoincidences, false); | |
226 joinCoincidence(fPartialCoincidences, true); | |
227 } | |
228 | |
229 SkOpSegment* nonVerticalSegment(int* start, int* end); | |
230 | 229 |
231 bool operand() const { | 230 bool operand() const { |
232 return fOperand; | 231 return fOperand; |
233 } | 232 } |
234 | 233 |
| 234 bool oppXor() const { |
| 235 return fOppXor; |
| 236 } |
| 237 |
| 238 void outdentDump() { |
| 239 PATH_OPS_DEBUG_CODE(fIndent -= 2); |
| 240 } |
| 241 |
| 242 void remove(SkOpContour* contour) { |
| 243 if (contour == this) { |
| 244 SkASSERT(fCount == 0); |
| 245 return; |
| 246 } |
| 247 SkASSERT(contour->fNext == NULL); |
| 248 SkOpContour* prev = this; |
| 249 SkOpContour* next; |
| 250 while ((next = prev->next()) != contour) { |
| 251 SkASSERT(next); |
| 252 prev = next; |
| 253 } |
| 254 SkASSERT(prev); |
| 255 prev->setNext(NULL); |
| 256 } |
| 257 |
235 void reset() { | 258 void reset() { |
236 fSegments.reset(); | 259 fTail = NULL; |
237 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax); | 260 fNext = NULL; |
238 fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = fMulti
ples = false; | 261 fCount = 0; |
239 } | 262 fDone = false; |
240 | 263 SkDEBUGCODE(fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_Sca
larMin)); |
241 void resolveNearCoincidence(); | 264 SkDEBUGCODE(fFirstSorted = -1); |
242 | 265 PATH_OPS_DEBUG_CODE(fIndent = 0); |
243 SkTArray<SkOpSegment>& segments() { | 266 } |
244 return fSegments; | 267 |
245 } | 268 void setBounds() { |
246 | 269 SkASSERT(fCount > 0); |
247 void setContainsIntercepts() { | 270 const SkOpSegment* segment = &fHead; |
248 fContainsIntercepts = true; | 271 fBounds = segment->bounds(); |
| 272 while ((segment = segment->next())) { |
| 273 fBounds.add(segment->bounds()); |
| 274 } |
| 275 } |
| 276 |
| 277 void setGlobalState(SkOpGlobalState* state) { |
| 278 fState = state; |
| 279 } |
| 280 |
| 281 void setNext(SkOpContour* contour) { |
| 282 // SkASSERT(!fNext == !!contour); |
| 283 fNext = contour; |
249 } | 284 } |
250 | 285 |
251 void setOperand(bool isOp) { | 286 void setOperand(bool isOp) { |
252 fOperand = isOp; | 287 fOperand = isOp; |
253 } | 288 } |
254 | 289 |
255 void setOppXor(bool isOppXor) { | 290 void setOppXor(bool isOppXor) { |
256 fOppXor = isOppXor; | 291 fOppXor = isOppXor; |
257 int segmentCount = fSegments.count(); | |
258 for (int test = 0; test < segmentCount; ++test) { | |
259 fSegments[test].setOppXor(isOppXor); | |
260 } | |
261 } | 292 } |
262 | 293 |
263 void setXor(bool isXor) { | 294 void setXor(bool isXor) { |
264 fXor = isXor; | 295 fXor = isXor; |
265 } | 296 } |
266 | 297 |
267 void sortAngles(); | 298 SkPath::Verb simplifyCubic(SkPoint pts[4]); |
268 void sortSegments(); | 299 |
| 300 void sortAngles() { |
| 301 SkASSERT(fCount > 0); |
| 302 SkOpSegment* segment = &fHead; |
| 303 do { |
| 304 segment->sortAngles(); |
| 305 } while ((segment = segment->next())); |
| 306 } |
| 307 |
| 308 void sortSegments() { |
| 309 SkOpSegment* segment = &fHead; |
| 310 do { |
| 311 *fSortedSegments.append() = segment; |
| 312 } while ((segment = segment->next())); |
| 313 SkTQSort<SkOpSegment>(fSortedSegments.begin(), fSortedSegments.end() - 1
); |
| 314 fFirstSorted = 0; |
| 315 } |
269 | 316 |
270 const SkPoint& start() const { | 317 const SkPoint& start() const { |
271 return fSegments.front().pts()[0]; | 318 return fHead.pts()[0]; |
| 319 } |
| 320 |
| 321 void toPartialBackward(SkPathWriter* path) const { |
| 322 const SkOpSegment* segment = fTail; |
| 323 do { |
| 324 segment->addCurveTo(segment->tail(), segment->head(), path, true); |
| 325 } while ((segment = segment->prev())); |
| 326 } |
| 327 |
| 328 void toPartialForward(SkPathWriter* path) const { |
| 329 const SkOpSegment* segment = &fHead; |
| 330 do { |
| 331 segment->addCurveTo(segment->head(), segment->tail(), path, true); |
| 332 } while ((segment = segment->next())); |
272 } | 333 } |
273 | 334 |
274 void toPath(SkPathWriter* path) const; | 335 void toPath(SkPathWriter* path) const; |
275 | |
276 void toPartialBackward(SkPathWriter* path) const { | |
277 int segmentCount = fSegments.count(); | |
278 for (int test = segmentCount - 1; test >= 0; --test) { | |
279 fSegments[test].addCurveTo(1, 0, path, true); | |
280 } | |
281 } | |
282 | |
283 void toPartialForward(SkPathWriter* path) const { | |
284 int segmentCount = fSegments.count(); | |
285 for (int test = 0; test < segmentCount; ++test) { | |
286 fSegments[test].addCurveTo(0, 1, path, true); | |
287 } | |
288 } | |
289 | |
290 void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment
** topStart); | 336 void topSortableSegment(const SkPoint& topLeft, SkPoint* bestXY, SkOpSegment
** topStart); |
291 SkOpSegment* undoneSegment(int* start, int* end); | 337 SkOpSegment* undoneSegment(SkOpSpanBase** startPtr, SkOpSpanBase** endPtr); |
292 | |
293 int updateSegment(int index, const SkPoint* pts) { | |
294 SkOpSegment& segment = fSegments[index]; | |
295 segment.updatePts(pts); | |
296 return SkPathOpsVerbToPoints(segment.verb()) + 1; | |
297 } | |
298 | |
299 #if DEBUG_TEST | |
300 SkTArray<SkOpSegment>& debugSegments() { | |
301 return fSegments; | |
302 } | |
303 #endif | |
304 | |
305 #if DEBUG_ACTIVE_SPANS || DEBUG_ACTIVE_SPANS_FIRST_ONLY | |
306 void debugShowActiveSpans() { | |
307 for (int index = 0; index < fSegments.count(); ++index) { | |
308 fSegments[index].debugShowActiveSpans(); | |
309 } | |
310 } | |
311 #endif | |
312 | |
313 #if DEBUG_SHOW_WINDING | |
314 int debugShowWindingValues(int totalSegments, int ofInterest); | |
315 static void debugShowWindingValues(const SkTArray<SkOpContour*, true>& conto
urList); | |
316 #endif | |
317 | |
318 // available to test routines only | |
319 void dump() const; | |
320 void dumpAngles() const; | |
321 void dumpCoincidence(const SkCoincidence& ) const; | |
322 void dumpCoincidences() const; | |
323 void dumpPt(int ) const; | |
324 void dumpPts() const; | |
325 void dumpSpan(int ) const; | |
326 void dumpSpans() const; | |
327 | 338 |
328 private: | 339 private: |
329 void alignPt(int index, SkPoint* point, int zeroPt) const; | 340 SkOpGlobalState* fState; |
330 int alignT(bool swap, int tIndex, SkIntersections* ts) const; | 341 SkOpSegment fHead; |
331 bool calcCommonCoincidentWinding(const SkCoincidence& ); | 342 SkOpSegment* fTail; |
332 void checkCoincidentPair(const SkCoincidence& oneCoin, int oneIdx, | 343 SkOpContour* fNext; |
333 const SkCoincidence& twoCoin, int twoIdx, bool part
ial); | 344 SkTDArray<SkOpSegment*> fSortedSegments; // set by find top segment |
334 void joinCoincidence(const SkTArray<SkCoincidence, true>& , bool partial); | 345 SkPathOpsBounds fBounds; |
335 void setBounds(); | 346 int fCount; |
336 | |
337 SkTArray<SkOpSegment> fSegments; | |
338 SkTArray<SkOpSegment*, true> fSortedSegments; | |
339 int fFirstSorted; | 347 int fFirstSorted; |
340 SkTArray<SkCoincidence, true> fCoincidences; | 348 bool fDone; // set by find top segment |
341 SkTArray<SkCoincidence, true> fPartialCoincidences; | |
342 SkTArray<const SkOpContour*, true> fCrosses; | |
343 SkPathOpsBounds fBounds; | |
344 bool fContainsIntercepts; // FIXME: is this used by anybody? | |
345 bool fContainsCubics; | |
346 bool fContainsCurves; | |
347 bool fDone; | |
348 bool fMultiples; // set if some segment has multiple identical intersection
s with other curves | |
349 bool fOperand; // true for the second argument to a binary operator | 349 bool fOperand; // true for the second argument to a binary operator |
350 bool fXor; | 350 bool fXor; // set if original path had even-odd fill |
351 bool fOppXor; | 351 bool fOppXor; // set if opposite path had even-odd fill |
352 #if defined(SK_DEBUG) || !FORCE_RELEASE | 352 PATH_OPS_DEBUG_CODE(int fID); |
353 int debugID() const { return fID; } | 353 PATH_OPS_DEBUG_CODE(int fIndent); |
354 int fID; | |
355 #else | |
356 int debugID() const { return -1; } | |
357 #endif | |
358 }; | 354 }; |
359 | 355 |
360 #endif | 356 #endif |
OLD | NEW |