OLD | NEW |
1 /* | 1 /* |
2 * Copyright 2014 Google Inc. | 2 * Copyright 2014 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 #include "SkOpCoincidence.h" | 7 #include "SkOpCoincidence.h" |
8 #include "SkOpContour.h" | 8 #include "SkOpContour.h" |
9 #include "SkOpSegment.h" | 9 #include "SkOpSegment.h" |
10 #include "SkPathWriter.h" | 10 #include "SkPathWriter.h" |
(...skipping 17 matching lines...) Expand all Loading... |
28 const SkOpPtT* ptT = this; | 28 const SkOpPtT* ptT = this; |
29 const SkOpPtT* stopPtT = ptT; | 29 const SkOpPtT* stopPtT = ptT; |
30 while ((ptT = ptT->next()) != stopPtT) { | 30 while ((ptT = ptT->next()) != stopPtT) { |
31 if (ptT == check) { | 31 if (ptT == check) { |
32 return true; | 32 return true; |
33 } | 33 } |
34 } | 34 } |
35 return false; | 35 return false; |
36 } | 36 } |
37 | 37 |
38 SkOpPtT* SkOpPtT::contains(const SkOpSegment* check) { | 38 bool SkOpPtT::contains(const SkOpSegment* segment, const SkPoint& pt) const { |
39 SkASSERT(this->segment() != check); | 39 SkASSERT(this->segment() != segment); |
40 SkOpPtT* ptT = this; | 40 const SkOpPtT* ptT = this; |
41 const SkOpPtT* stopPtT = ptT; | 41 const SkOpPtT* stopPtT = ptT; |
42 while ((ptT = ptT->next()) != stopPtT) { | 42 while ((ptT = ptT->next()) != stopPtT) { |
43 if (ptT->segment() == check) { | 43 if (ptT->fPt == pt && ptT->segment() == segment) { |
| 44 return true; |
| 45 } |
| 46 } |
| 47 return false; |
| 48 } |
| 49 |
| 50 bool SkOpPtT::contains(const SkOpSegment* segment, double t) const { |
| 51 const SkOpPtT* ptT = this; |
| 52 const SkOpPtT* stopPtT = ptT; |
| 53 while ((ptT = ptT->next()) != stopPtT) { |
| 54 if (ptT->fT == t && ptT->segment() == segment) { |
| 55 return true; |
| 56 } |
| 57 } |
| 58 return false; |
| 59 } |
| 60 |
| 61 const SkOpPtT* SkOpPtT::contains(const SkOpSegment* check) const { |
| 62 SkASSERT(this->segment() != check); |
| 63 const SkOpPtT* ptT = this; |
| 64 const SkOpPtT* stopPtT = ptT; |
| 65 while ((ptT = ptT->next()) != stopPtT) { |
| 66 if (ptT->segment() == check && !ptT->deleted()) { |
44 return ptT; | 67 return ptT; |
45 } | 68 } |
46 } | 69 } |
47 return nullptr; | 70 return nullptr; |
48 } | 71 } |
49 | 72 |
50 SkOpContour* SkOpPtT::contour() const { | 73 SkOpContour* SkOpPtT::contour() const { |
51 return segment()->contour(); | 74 return segment()->contour(); |
52 } | 75 } |
53 | 76 |
54 SkOpPtT* SkOpPtT::doppelganger() { | 77 const SkOpPtT* SkOpPtT::find(const SkOpSegment* segment) const { |
55 SkASSERT(fDeleted); | 78 const SkOpPtT* ptT = this; |
56 SkOpPtT* ptT = fNext; | |
57 while (ptT->fDeleted) { | |
58 ptT = ptT->fNext; | |
59 } | |
60 const SkOpPtT* stopPtT = ptT; | 79 const SkOpPtT* stopPtT = ptT; |
61 do { | 80 do { |
62 if (ptT->fSpan == fSpan) { | 81 if (ptT->segment() == segment && !ptT->deleted()) { |
63 return ptT; | 82 return ptT; |
64 } | 83 } |
65 ptT = ptT->fNext; | 84 ptT = ptT->fNext; |
66 } while (stopPtT != ptT); | 85 } while (stopPtT != ptT); |
67 SkASSERT(0); | 86 // SkASSERT(0); |
68 return nullptr; | |
69 } | |
70 | |
71 SkOpPtT* SkOpPtT::find(SkOpSegment* segment) { | |
72 SkOpPtT* ptT = this; | |
73 const SkOpPtT* stopPtT = ptT; | |
74 do { | |
75 if (ptT->segment() == segment) { | |
76 return ptT; | |
77 } | |
78 ptT = ptT->fNext; | |
79 } while (stopPtT != ptT); | |
80 SkASSERT(0); | |
81 return nullptr; | 87 return nullptr; |
82 } | 88 } |
83 | 89 |
84 SkOpGlobalState* SkOpPtT::globalState() const { | 90 SkOpGlobalState* SkOpPtT::globalState() const { |
85 return contour()->globalState(); | 91 return contour()->globalState(); |
86 } | 92 } |
87 | 93 |
88 void SkOpPtT::init(SkOpSpanBase* span, double t, const SkPoint& pt, bool duplica
te) { | 94 void SkOpPtT::init(SkOpSpanBase* span, double t, const SkPoint& pt, bool duplica
te) { |
89 fT = t; | 95 fT = t; |
90 fPt = pt; | 96 fPt = pt; |
91 fSpan = span; | 97 fSpan = span; |
92 fNext = this; | 98 fNext = this; |
93 fDuplicatePt = duplicate; | 99 fDuplicatePt = duplicate; |
94 fDeleted = false; | 100 fDeleted = false; |
| 101 fCoincident = false; |
95 SkDEBUGCODE(fID = span->globalState()->nextPtTID()); | 102 SkDEBUGCODE(fID = span->globalState()->nextPtTID()); |
96 } | 103 } |
97 | 104 |
98 bool SkOpPtT::onEnd() const { | 105 bool SkOpPtT::onEnd() const { |
99 const SkOpSpanBase* span = this->span(); | 106 const SkOpSpanBase* span = this->span(); |
100 if (span->ptT() != this) { | 107 if (span->ptT() != this) { |
101 return false; | 108 return false; |
102 } | 109 } |
103 const SkOpSegment* segment = this->segment(); | 110 const SkOpSegment* segment = this->segment(); |
104 return span == segment->head() || span == segment->tail(); | 111 return span == segment->head() || span == segment->tail(); |
105 } | 112 } |
106 | 113 |
| 114 bool SkOpPtT::ptAlreadySeen(const SkOpPtT* check) const { |
| 115 while (this != check) { |
| 116 if (this->fPt == check->fPt) { |
| 117 return true; |
| 118 } |
| 119 check = check->fNext; |
| 120 } |
| 121 return false; |
| 122 } |
| 123 |
107 SkOpPtT* SkOpPtT::prev() { | 124 SkOpPtT* SkOpPtT::prev() { |
108 SkOpPtT* result = this; | 125 SkOpPtT* result = this; |
109 SkOpPtT* next = this; | 126 SkOpPtT* next = this; |
110 while ((next = next->fNext) != this) { | 127 while ((next = next->fNext) != this) { |
111 result = next; | 128 result = next; |
112 } | 129 } |
113 SkASSERT(result->fNext == this); | 130 SkASSERT(result->fNext == this); |
114 return result; | 131 return result; |
115 } | 132 } |
116 | 133 |
117 SkOpPtT* SkOpPtT::remove() { | 134 SkOpPtT* SkOpPtT::remove(const SkOpPtT* kept) { |
118 SkOpPtT* prev = this; | 135 SkOpPtT* prev = this; |
119 do { | 136 do { |
120 SkOpPtT* next = prev->fNext; | 137 SkOpPtT* next = prev->fNext; |
121 if (next == this) { | 138 if (next == this) { |
122 prev->removeNext(this); | 139 prev->removeNext(kept); |
123 SkASSERT(prev->fNext != prev); | 140 SkASSERT(prev->fNext != prev); |
124 fDeleted = true; | 141 fDeleted = true; |
125 return prev; | 142 return prev; |
126 } | 143 } |
127 prev = next; | 144 prev = next; |
128 } while (prev != this); | 145 } while (prev != this); |
129 SkASSERT(0); | 146 SkASSERT(0); |
130 return nullptr; | 147 return nullptr; |
131 } | 148 } |
132 | 149 |
133 void SkOpPtT::removeNext(SkOpPtT* kept) { | 150 void SkOpPtT::removeNext(const SkOpPtT* kept) { |
134 SkASSERT(this->fNext); | 151 SkASSERT(this->fNext); |
135 SkOpPtT* next = this->fNext; | 152 SkOpPtT* next = this->fNext; |
136 SkASSERT(this != next->fNext); | 153 SkASSERT(this != next->fNext); |
137 this->fNext = next->fNext; | 154 this->fNext = next->fNext; |
138 SkOpSpanBase* span = next->span(); | 155 SkOpSpanBase* span = next->span(); |
| 156 SkOpCoincidence* coincidence = span->globalState()->coincidence(); |
| 157 if (coincidence) { |
| 158 coincidence->fixUp(next, kept); |
| 159 } |
139 next->setDeleted(); | 160 next->setDeleted(); |
140 if (span->ptT() == next) { | 161 if (span->ptT() == next) { |
141 span->upCast()->release(kept); | 162 span->upCast()->release(kept); |
142 } | 163 } |
143 } | 164 } |
144 | 165 |
145 const SkOpSegment* SkOpPtT::segment() const { | 166 const SkOpSegment* SkOpPtT::segment() const { |
146 return span()->segment(); | 167 return span()->segment(); |
147 } | 168 } |
148 | 169 |
149 SkOpSegment* SkOpPtT::segment() { | 170 SkOpSegment* SkOpPtT::segment() { |
150 return span()->segment(); | 171 return span()->segment(); |
151 } | 172 } |
152 | 173 |
153 void SkOpSpanBase::align() { | 174 void SkOpPtT::setDeleted() { |
154 if (this->fAligned) { | 175 SkASSERT(this->span()->debugDeleted() || this->span()->ptT() != this); |
| 176 SkASSERT(this->globalState()->debugSkipAssert() || !fDeleted); |
| 177 fDeleted = true; |
| 178 } |
| 179 |
| 180 // please keep this in sync with debugAddOppAndMerge |
| 181 // If the added points envelop adjacent spans, merge them in. |
| 182 void SkOpSpanBase::addOppAndMerge(SkOpSpanBase* opp) { |
| 183 if (this->ptT()->addOpp(opp->ptT())) { |
| 184 this->checkForCollapsedCoincidence(); |
| 185 } |
| 186 // compute bounds of points in span |
| 187 SkPathOpsBounds bounds; |
| 188 bounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMin, SK_ScalarMin); |
| 189 const SkOpPtT* head = this->ptT(); |
| 190 const SkOpPtT* nextPt = head; |
| 191 do { |
| 192 bounds.add(nextPt->fPt); |
| 193 } while ((nextPt = nextPt->next()) != head); |
| 194 if (!bounds.width() && !bounds.height()) { |
155 return; | 195 return; |
156 } | 196 } |
157 SkASSERT(!zero_or_one(this->fPtT.fT)); | 197 this->mergeContained(bounds); |
158 SkASSERT(this->fPtT.next()); | 198 opp->mergeContained(bounds); |
159 // if a linked pt/t pair has a t of zero or one, use it as the base for alig
nment | 199 } |
160 SkOpPtT* ptT = &this->fPtT, * stopPtT = ptT; | 200 |
161 while ((ptT = ptT->next()) != stopPtT) { | 201 // Please keep this in sync with debugMergeContained() |
162 if (zero_or_one(ptT->fT)) { | 202 void SkOpSpanBase::mergeContained(const SkPathOpsBounds& bounds) { |
163 SkOpSegment* segment = ptT->segment(); | 203 // while adjacent spans' points are contained by the bounds, merge them |
164 SkASSERT(this->segment() != segment); | 204 SkOpSpanBase* prev = this; |
165 SkASSERT(segment->head()->ptT() == ptT || segment->tail()->ptT() ==
ptT); | 205 SkOpSegment* seg = this->segment(); |
166 if (ptT->fT) { | 206 while ((prev = prev->prev()) && bounds.contains(prev->pt()) && !seg->ptsDisj
oint(prev, this)) { |
167 segment->tail()->alignEnd(1, segment->lastPt()); | 207 if (prev->prev()) { |
168 } else { | 208 this->merge(prev->upCast()); |
169 segment->head()->alignEnd(0, segment->pts()[0]); | 209 prev = this; |
170 } | 210 } else if (this->final()) { |
| 211 seg->clearAll(); |
| 212 return; |
| 213 } else { |
| 214 prev->merge(this->upCast()); |
| 215 } |
| 216 } |
| 217 SkOpSpanBase* current = this; |
| 218 SkOpSpanBase* next = this; |
| 219 while (next->upCastable() && (next = next->upCast()->next()) |
| 220 && bounds.contains(next->pt()) && !seg->ptsDisjoint(this, next)) { |
| 221 if (!current->prev() && next->final()) { |
| 222 seg->clearAll(); |
171 return; | 223 return; |
172 } | 224 } |
| 225 if (current->prev()) { |
| 226 next->merge(current->upCast()); |
| 227 current = next; |
| 228 } else { |
| 229 current->merge(next->upCast()); |
| 230 // extra line in debug version |
| 231 } |
173 } | 232 } |
174 alignInner(); | 233 #if DEBUG_COINCIDENCE |
175 this->fAligned = true; | 234 this->globalState()->coincidence()->debugValidate(); |
176 } | 235 #endif |
177 | |
178 | |
179 // FIXME: delete spans that collapse | |
180 // delete segments that collapse | |
181 // delete contours that collapse | |
182 void SkOpSpanBase::alignEnd(double t, const SkPoint& pt) { | |
183 SkASSERT(zero_or_one(t)); | |
184 SkOpSegment* segment = this->segment(); | |
185 SkASSERT(t ? segment->lastPt() == pt : segment->pts()[0] == pt); | |
186 alignInner(); | |
187 *segment->writablePt(!!t) = pt; | |
188 SkOpPtT* ptT = &this->fPtT; | |
189 SkASSERT(t == ptT->fT); | |
190 SkASSERT(pt == ptT->fPt); | |
191 SkOpPtT* test = ptT, * stopPtT = ptT; | |
192 while ((test = test->next()) != stopPtT) { | |
193 SkOpSegment* other = test->segment(); | |
194 if (other == this->segment()) { | |
195 continue; | |
196 } | |
197 if (!zero_or_one(test->fT)) { | |
198 continue; | |
199 } | |
200 *other->writablePt(!!test->fT) = pt; | |
201 } | |
202 this->fAligned = true; | |
203 } | |
204 | |
205 void SkOpSpanBase::alignInner() { | |
206 // force the spans to share points and t values | |
207 SkOpPtT* ptT = &this->fPtT, * stopPtT = ptT; | |
208 const SkPoint& pt = ptT->fPt; | |
209 do { | |
210 ptT->fPt = pt; | |
211 const SkOpSpanBase* span = ptT->span(); | |
212 SkOpPtT* test = ptT; | |
213 do { | |
214 SkOpPtT* prev = test; | |
215 if ((test = test->next()) == stopPtT) { | |
216 break; | |
217 } | |
218 if (span == test->span() && !span->segment()->ptsDisjoint(*ptT, *tes
t)) { | |
219 // omit aliases that alignment makes redundant | |
220 if ((!ptT->alias() || test->alias()) && (ptT->onEnd() || !test->
onEnd())) { | |
221 SkASSERT(test->alias()); | |
222 prev->removeNext(ptT); | |
223 test = prev; | |
224 } else { | |
225 SkASSERT(ptT->alias()); | |
226 stopPtT = ptT = ptT->remove(); | |
227 break; | |
228 } | |
229 } | |
230 } while (true); | |
231 } while ((ptT = ptT->next()) != stopPtT); | |
232 } | 236 } |
233 | 237 |
234 bool SkOpSpanBase::contains(const SkOpSpanBase* span) const { | 238 bool SkOpSpanBase::contains(const SkOpSpanBase* span) const { |
235 const SkOpPtT* start = &fPtT; | 239 const SkOpPtT* start = &fPtT; |
236 const SkOpPtT* check = &span->fPtT; | 240 const SkOpPtT* check = &span->fPtT; |
237 SkASSERT(start != check); | 241 SkASSERT(start != check); |
238 const SkOpPtT* walk = start; | 242 const SkOpPtT* walk = start; |
239 while ((walk = walk->next()) != start) { | 243 while ((walk = walk->next()) != start) { |
240 if (walk == check) { | 244 if (walk == check) { |
241 return true; | 245 return true; |
242 } | 246 } |
243 } | 247 } |
244 return false; | 248 return false; |
245 } | 249 } |
246 | 250 |
247 SkOpPtT* SkOpSpanBase::contains(const SkOpSegment* segment) { | 251 const SkOpPtT* SkOpSpanBase::contains(const SkOpSegment* segment) const { |
248 SkOpPtT* start = &fPtT; | 252 const SkOpPtT* start = &fPtT; |
249 SkOpPtT* walk = start; | 253 const SkOpPtT* walk = start; |
250 while ((walk = walk->next()) != start) { | 254 while ((walk = walk->next()) != start) { |
251 if (walk->segment() == segment) { | 255 if (walk->deleted()) { |
| 256 continue; |
| 257 } |
| 258 if (walk->segment() == segment && walk->span()->ptT() == walk) { |
252 return walk; | 259 return walk; |
253 } | 260 } |
254 } | 261 } |
255 return nullptr; | 262 return nullptr; |
256 } | 263 } |
257 | 264 |
258 bool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const { | 265 bool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const { |
259 SkASSERT(this->segment() != segment); | 266 SkASSERT(this->segment() != segment); |
260 const SkOpSpanBase* next = this; | 267 const SkOpSpanBase* next = this; |
261 while ((next = next->fCoinEnd) != this) { | 268 while ((next = next->fCoinEnd) != this) { |
262 if (next->segment() == segment) { | 269 if (next->segment() == segment) { |
263 return true; | 270 return true; |
264 } | 271 } |
265 } | 272 } |
266 return false; | 273 return false; |
267 } | 274 } |
268 | 275 |
269 SkOpContour* SkOpSpanBase::contour() const { | 276 SkOpContour* SkOpSpanBase::contour() const { |
270 return segment()->contour(); | 277 return segment()->contour(); |
271 } | 278 } |
272 | 279 |
273 SkOpGlobalState* SkOpSpanBase::globalState() const { | 280 SkOpGlobalState* SkOpSpanBase::globalState() const { |
274 return contour()->globalState(); | 281 return contour()->globalState(); |
275 } | 282 } |
276 | 283 |
277 void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, cons
t SkPoint& pt) { | 284 void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, cons
t SkPoint& pt) { |
278 fSegment = segment; | 285 fSegment = segment; |
279 fPtT.init(this, t, pt, false); | 286 fPtT.init(this, t, pt, false); |
280 fCoinEnd = this; | 287 fCoinEnd = this; |
281 fFromAngle = nullptr; | 288 fFromAngle = nullptr; |
282 fPrev = prev; | 289 fPrev = prev; |
283 fSpanAdds = 0; | 290 fSpanAdds = 0; |
284 fAligned = true; | 291 fAligned = true; |
285 fChased = false; | 292 fChased = false; |
286 SkDEBUGCODE(fCount = 1); | 293 SkDEBUGCODE(fCount = 1); |
287 SkDEBUGCODE(fID = globalState()->nextSpanID()); | 294 SkDEBUGCODE(fID = globalState()->nextSpanID()); |
| 295 SkDEBUGCODE(fDeleted = false); |
288 } | 296 } |
289 | 297 |
290 // this pair of spans share a common t value or point; merge them and eliminate
duplicates | 298 // this pair of spans share a common t value or point; merge them and eliminate
duplicates |
291 // this does not compute the best t or pt value; this merely moves all data into
a single list | 299 // this does not compute the best t or pt value; this merely moves all data into
a single list |
292 void SkOpSpanBase::merge(SkOpSpan* span) { | 300 void SkOpSpanBase::merge(SkOpSpan* span) { |
293 SkOpPtT* spanPtT = span->ptT(); | 301 SkOpPtT* spanPtT = span->ptT(); |
294 SkASSERT(this->t() != spanPtT->fT); | 302 SkASSERT(this->t() != spanPtT->fT); |
295 SkASSERT(!zero_or_one(spanPtT->fT)); | 303 SkASSERT(!zero_or_one(spanPtT->fT)); |
296 span->release(this->ptT()); | 304 span->release(this->ptT()); |
| 305 if (this->contains(span)) { |
| 306 return; // merge is already in the ptT loop |
| 307 } |
297 SkOpPtT* remainder = spanPtT->next(); | 308 SkOpPtT* remainder = spanPtT->next(); |
298 ptT()->insert(spanPtT); | 309 this->ptT()->insert(spanPtT); |
299 while (remainder != spanPtT) { | 310 while (remainder != spanPtT) { |
300 SkOpPtT* next = remainder->next(); | 311 SkOpPtT* next = remainder->next(); |
301 SkOpPtT* compare = spanPtT->next(); | 312 SkOpPtT* compare = spanPtT->next(); |
302 while (compare != spanPtT) { | 313 while (compare != spanPtT) { |
303 SkOpPtT* nextC = compare->next(); | 314 SkOpPtT* nextC = compare->next(); |
304 if (nextC->span() == remainder->span() && nextC->fT == remainder->fT
) { | 315 if (nextC->span() == remainder->span() && nextC->fT == remainder->fT
) { |
305 goto tryNextRemainder; | 316 goto tryNextRemainder; |
306 } | 317 } |
307 compare = nextC; | 318 compare = nextC; |
308 } | 319 } |
309 spanPtT->insert(remainder); | 320 spanPtT->insert(remainder); |
310 tryNextRemainder: | 321 tryNextRemainder: |
311 remainder = next; | 322 remainder = next; |
312 } | 323 } |
313 fSpanAdds += span->fSpanAdds; | 324 fSpanAdds += span->fSpanAdds; |
| 325 this->checkForCollapsedCoincidence(); |
| 326 } |
| 327 |
| 328 // please keep in sync with debugCheckForCollapsedCoincidence() |
| 329 void SkOpSpanBase::checkForCollapsedCoincidence() { |
| 330 SkOpCoincidence* coins = this->globalState()->coincidence(); |
| 331 if (coins->isEmpty()) { |
| 332 return; |
| 333 } |
| 334 // the insert above may have put both ends of a coincident run in the same span |
| 335 // for each coincident ptT in loop; see if its opposite in is also in the loop |
| 336 // this implementation is the motivation for marking that a ptT is referenced by
a coincident span |
| 337 SkOpPtT* head = this->ptT(); |
| 338 SkOpPtT* test = head; |
| 339 do { |
| 340 if (!test->coincident()) { |
| 341 continue; |
| 342 } |
| 343 coins->markCollapsed(test); |
| 344 } while ((test = test->next()) != head); |
314 } | 345 } |
315 | 346 |
316 int SkOpSpan::computeWindSum() { | 347 int SkOpSpan::computeWindSum() { |
317 SkOpGlobalState* globals = this->globalState(); | 348 SkOpGlobalState* globals = this->globalState(); |
318 SkOpContour* contourHead = globals->contourHead(); | 349 SkOpContour* contourHead = globals->contourHead(); |
319 int windTry = 0; | 350 int windTry = 0; |
320 while (!this->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxW
indingTries) { | 351 while (!this->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxW
indingTries) { |
321 ; | 352 ; |
322 } | 353 } |
323 return this->windSum(); | 354 return this->windSum(); |
324 } | 355 } |
325 | 356 |
326 bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const { | 357 bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const { |
327 SkASSERT(this->segment() != segment); | 358 SkASSERT(this->segment() != segment); |
328 const SkOpSpan* next = fCoincident; | 359 const SkOpSpan* next = fCoincident; |
329 do { | 360 do { |
330 if (next->segment() == segment) { | 361 if (next->segment() == segment) { |
331 return true; | 362 return true; |
332 } | 363 } |
333 } while ((next = next->fCoincident) != this); | 364 } while ((next = next->fCoincident) != this); |
334 return false; | 365 return false; |
335 } | 366 } |
336 | 367 |
337 void SkOpSpan::release(SkOpPtT* kept) { | 368 void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoin
t& pt) { |
| 369 SkASSERT(t != 1); |
| 370 initBase(segment, prev, t, pt); |
| 371 fCoincident = this; |
| 372 fToAngle = nullptr; |
| 373 fWindSum = fOppSum = SK_MinS32; |
| 374 fWindValue = 1; |
| 375 fOppValue = 0; |
| 376 fTopTTry = 0; |
| 377 fChased = fDone = false; |
| 378 segment->bumpCount(); |
| 379 fAlreadyAdded = false; |
| 380 } |
| 381 |
| 382 // Please keep this in sync with debugInsertCoincidence() |
| 383 bool SkOpSpan::insertCoincidence(const SkOpSegment* segment, bool flipped) { |
| 384 if (this->containsCoincidence(segment)) { |
| 385 return true; |
| 386 } |
| 387 SkOpPtT* next = &fPtT; |
| 388 while ((next = next->next()) != &fPtT) { |
| 389 if (next->segment() == segment) { |
| 390 SkOpSpan* span = flipped ? next->span()->prev() : next->span()->upCa
st(); |
| 391 if (!span) { |
| 392 return false; |
| 393 } |
| 394 this->insertCoincidence(span); |
| 395 return true; |
| 396 } |
| 397 } |
| 398 #if DEBUG_COINCIDENCE |
| 399 SkASSERT(0); // FIXME? if we get here, the span is missing its opposite segm
ent... |
| 400 #endif |
| 401 return true; |
| 402 } |
| 403 |
| 404 void SkOpSpan::release(const SkOpPtT* kept) { |
| 405 SkDEBUGCODE(fDeleted = true); |
| 406 SkASSERT(kept->span() != this); |
338 SkASSERT(!final()); | 407 SkASSERT(!final()); |
339 SkOpSpan* prev = this->prev(); | 408 SkOpSpan* prev = this->prev(); |
340 SkASSERT(prev); | 409 SkASSERT(prev); |
341 SkOpSpanBase* next = this->next(); | 410 SkOpSpanBase* next = this->next(); |
342 SkASSERT(next); | 411 SkASSERT(next); |
343 prev->setNext(next); | 412 prev->setNext(next); |
344 next->setPrev(prev); | 413 next->setPrev(prev); |
345 this->segment()->release(this); | 414 this->segment()->release(this); |
346 SkOpCoincidence* coincidence = this->globalState()->coincidence(); | 415 SkOpCoincidence* coincidence = this->globalState()->coincidence(); |
347 if (coincidence) { | 416 if (coincidence) { |
348 coincidence->fixUp(this->ptT(), kept); | 417 coincidence->fixUp(this->ptT(), kept); |
349 } | 418 } |
350 this->ptT()->setDeleted(); | 419 this->ptT()->setDeleted(); |
351 } | 420 SkOpPtT* stopPtT = this->ptT(); |
352 | 421 SkOpPtT* testPtT = stopPtT; |
353 void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoin
t& pt) { | 422 const SkOpSpanBase* keptSpan = kept->span(); |
354 SkASSERT(t != 1); | 423 do { |
355 initBase(segment, prev, t, pt); | 424 if (this == testPtT->span()) { |
356 fCoincident = this; | 425 testPtT->setSpan(keptSpan); |
357 fToAngle = nullptr; | 426 } |
358 fWindSum = fOppSum = SK_MinS32; | 427 } while ((testPtT = testPtT->next()) != stopPtT); |
359 fWindValue = 1; | |
360 fOppValue = 0; | |
361 fTopTTry = 0; | |
362 fChased = fDone = false; | |
363 segment->bumpCount(); | |
364 fAlreadyAdded = false; | |
365 } | 428 } |
366 | 429 |
367 void SkOpSpan::setOppSum(int oppSum) { | 430 void SkOpSpan::setOppSum(int oppSum) { |
368 SkASSERT(!final()); | 431 SkASSERT(!final()); |
369 if (fOppSum != SK_MinS32 && fOppSum != oppSum) { | 432 if (fOppSum != SK_MinS32 && fOppSum != oppSum) { |
370 this->globalState()->setWindingFailed(); | 433 this->globalState()->setWindingFailed(); |
371 return; | 434 return; |
372 } | 435 } |
373 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(oppSum) <= DEBUG_LIMIT_WIND_SUM); | 436 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(oppSum) <= DEBUG_LIMIT_WIND_SUM); |
374 fOppSum = oppSum; | 437 fOppSum = oppSum; |
375 } | 438 } |
376 | 439 |
377 void SkOpSpan::setWindSum(int windSum) { | 440 void SkOpSpan::setWindSum(int windSum) { |
378 SkASSERT(!final()); | 441 SkASSERT(!final()); |
379 if (fWindSum != SK_MinS32 && fWindSum != windSum) { | 442 if (fWindSum != SK_MinS32 && fWindSum != windSum) { |
380 this->globalState()->setWindingFailed(); | 443 this->globalState()->setWindingFailed(); |
381 return; | 444 return; |
382 } | 445 } |
383 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(windSum) <= DEBUG_LIMIT_WIND_SUM); | 446 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(windSum) <= DEBUG_LIMIT_WIND_SUM); |
384 fWindSum = windSum; | 447 fWindSum = windSum; |
385 } | 448 } |
OLD | NEW |