| 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 |