1 /* 2 * Copyright 2014 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 #include "SkOpCoincidence.h" 8 #include "SkOpContour.h" 9 #include "SkOpSegment.h" 10 #include "SkPathWriter.h" 11 12 bool SkOpPtT::alias() const { 13 return this->span()->ptT() != this; 14 } 15 16 bool SkOpPtT::collapsed(const SkOpPtT* check) const { 17 if (fPt != check->fPt) { 18 return false; 19 } 20 SkASSERT(this != check); 21 const SkOpSegment* segment = this->segment(); 22 SkASSERT(segment == check->segment()); 23 return segment->collapsed(); 24 } 25 26 bool SkOpPtT::contains(const SkOpPtT* check) const { 27 SkASSERT(this != check); 28 const SkOpPtT* ptT = this; 29 const SkOpPtT* stopPtT = ptT; 30 while ((ptT = ptT->next()) != stopPtT) { 31 if (ptT == check) { 32 return true; 33 } 34 } 35 return false; 36 } 37 38 SkOpPtT* SkOpPtT::contains(const SkOpSegment* check) { 39 SkASSERT(this->segment() != check); 40 SkOpPtT* ptT = this; 41 const SkOpPtT* stopPtT = ptT; 42 while ((ptT = ptT->next()) != stopPtT) { 43 if (ptT->segment() == check) { 44 return ptT; 45 } 46 } 47 return nullptr; 48 } 49 50 SkOpContour* SkOpPtT::contour() const { 51 return segment()->contour(); 52 } 53 54 SkOpPtT* SkOpPtT::doppelganger() { 55 SkASSERT(fDeleted); 56 SkOpPtT* ptT = fNext; 57 while (ptT->fDeleted) { 58 ptT = ptT->fNext; 59 } 60 const SkOpPtT* stopPtT = ptT; 61 do { 62 if (ptT->fSpan == fSpan) { 63 return ptT; 64 } 65 ptT = ptT->fNext; 66 } while (stopPtT != ptT); 67 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; 82 } 83 84 SkOpGlobalState* SkOpPtT::globalState() const { 85 return contour()->globalState(); 86 } 87 88 void SkOpPtT::init(SkOpSpanBase* span, double t, const SkPoint& pt, bool duplicate) { 89 fT = t; 90 fPt = pt; 91 fSpan = span; 92 fNext = this; 93 fDuplicatePt = duplicate; 94 fDeleted = false; 95 SkDEBUGCODE(fID = span->globalState()->nextPtTID()); 96 } 97 98 bool SkOpPtT::onEnd() const { 99 const SkOpSpanBase* span = this->span(); 100 if (span->ptT() != this) { 101 return false; 102 } 103 const SkOpSegment* segment = this->segment(); 104 return span == segment->head() || span == segment->tail(); 105 } 106 107 SkOpPtT* SkOpPtT::prev() { 108 SkOpPtT* result = this; 109 SkOpPtT* next = this; 110 while ((next = next->fNext) != this) { 111 result = next; 112 } 113 SkASSERT(result->fNext == this); 114 return result; 115 } 116 117 SkOpPtT* SkOpPtT::remove() { 118 SkOpPtT* prev = this; 119 do { 120 SkOpPtT* next = prev->fNext; 121 if (next == this) { 122 prev->removeNext(this); 123 SkASSERT(prev->fNext != prev); 124 fDeleted = true; 125 return prev; 126 } 127 prev = next; 128 } while (prev != this); 129 SkASSERT(0); 130 return nullptr; 131 } 132 133 void SkOpPtT::removeNext(SkOpPtT* kept) { 134 SkASSERT(this->fNext); 135 SkOpPtT* next = this->fNext; 136 SkASSERT(this != next->fNext); 137 this->fNext = next->fNext; 138 SkOpSpanBase* span = next->span(); 139 next->setDeleted(); 140 if (span->ptT() == next) { 141 span->upCast()->detach(kept); 142 } 143 } 144 145 const SkOpSegment* SkOpPtT::segment() const { 146 return span()->segment(); 147 } 148 149 SkOpSegment* SkOpPtT::segment() { 150 return span()->segment(); 151 } 152 153 void SkOpSpanBase::align() { 154 if (this->fAligned) { 155 return; 156 } 157 SkASSERT(!zero_or_one(this->fPtT.fT)); 158 SkASSERT(this->fPtT.next()); 159 // if a linked pt/t pair has a t of zero or one, use it as the base for alignment 160 SkOpPtT* ptT = &this->fPtT, * stopPtT = ptT; 161 while ((ptT = ptT->next()) != stopPtT) { 162 if (zero_or_one(ptT->fT)) { 163 SkOpSegment* segment = ptT->segment(); 164 SkASSERT(this->segment() != segment); 165 SkASSERT(segment->head()->ptT() == ptT || segment->tail()->ptT() == ptT); 166 if (ptT->fT) { 167 segment->tail()->alignEnd(1, segment->lastPt()); 168 } else { 169 segment->head()->alignEnd(0, segment->pts()[0]); 170 } 171 return; 172 } 173 } 174 alignInner(); 175 this->fAligned = true; 176 } 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, *test)) { 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 } 233 234 bool SkOpSpanBase::contains(const SkOpSpanBase* span) const { 235 const SkOpPtT* start = &fPtT; 236 const SkOpPtT* check = &span->fPtT; 237 SkASSERT(start != check); 238 const SkOpPtT* walk = start; 239 while ((walk = walk->next()) != start) { 240 if (walk == check) { 241 return true; 242 } 243 } 244 return false; 245 } 246 247 SkOpPtT* SkOpSpanBase::contains(const SkOpSegment* segment) { 248 SkOpPtT* start = &fPtT; 249 SkOpPtT* walk = start; 250 while ((walk = walk->next()) != start) { 251 if (walk->segment() == segment) { 252 return walk; 253 } 254 } 255 return nullptr; 256 } 257 258 bool SkOpSpanBase::containsCoinEnd(const SkOpSegment* segment) const { 259 SkASSERT(this->segment() != segment); 260 const SkOpSpanBase* next = this; 261 while ((next = next->fCoinEnd) != this) { 262 if (next->segment() == segment) { 263 return true; 264 } 265 } 266 return false; 267 } 268 269 SkOpContour* SkOpSpanBase::contour() const { 270 return segment()->contour(); 271 } 272 273 SkOpGlobalState* SkOpSpanBase::globalState() const { 274 return contour()->globalState(); 275 } 276 277 void SkOpSpanBase::initBase(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) { 278 fSegment = segment; 279 fPtT.init(this, t, pt, false); 280 fCoinEnd = this; 281 fFromAngle = nullptr; 282 fPrev = prev; 283 fSpanAdds = 0; 284 fAligned = true; 285 fChased = false; 286 SkDEBUGCODE(fCount = 1); 287 SkDEBUGCODE(fID = globalState()->nextSpanID()); 288 } 289 290 // 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 292 void SkOpSpanBase::merge(SkOpSpan* span) { 293 SkOpPtT* spanPtT = span->ptT(); 294 SkASSERT(this->t() != spanPtT->fT); 295 SkASSERT(!zero_or_one(spanPtT->fT)); 296 span->detach(this->ptT()); 297 SkOpPtT* remainder = spanPtT->next(); 298 ptT()->insert(spanPtT); 299 while (remainder != spanPtT) { 300 SkOpPtT* next = remainder->next(); 301 SkOpPtT* compare = spanPtT->next(); 302 while (compare != spanPtT) { 303 SkOpPtT* nextC = compare->next(); 304 if (nextC->span() == remainder->span() && nextC->fT == remainder->fT) { 305 goto tryNextRemainder; 306 } 307 compare = nextC; 308 } 309 spanPtT->insert(remainder); 310 tryNextRemainder: 311 remainder = next; 312 } 313 fSpanAdds += span->fSpanAdds; 314 } 315 316 int SkOpSpan::computeWindSum() { 317 SkOpGlobalState* globals = this->globalState(); 318 SkOpContour* contourHead = globals->contourHead(); 319 int windTry = 0; 320 while (!this->sortableTop(contourHead) && ++windTry < SkOpGlobalState::kMaxWindingTries) { 321 ; 322 } 323 return this->windSum(); 324 } 325 326 bool SkOpSpan::containsCoincidence(const SkOpSegment* segment) const { 327 SkASSERT(this->segment() != segment); 328 const SkOpSpan* next = fCoincident; 329 do { 330 if (next->segment() == segment) { 331 return true; 332 } 333 } while ((next = next->fCoincident) != this); 334 return false; 335 } 336 337 void SkOpSpan::detach(SkOpPtT* kept) { 338 SkASSERT(!final()); 339 SkOpSpan* prev = this->prev(); 340 SkASSERT(prev); 341 SkOpSpanBase* next = this->next(); 342 SkASSERT(next); 343 prev->setNext(next); 344 next->setPrev(prev); 345 this->segment()->detach(this); 346 SkOpCoincidence* coincidence = this->globalState()->coincidence(); 347 if (coincidence) { 348 coincidence->fixUp(this->ptT(), kept); 349 } 350 this->ptT()->setDeleted(); 351 } 352 353 void SkOpSpan::init(SkOpSegment* segment, SkOpSpan* prev, double t, const SkPoint& pt) { 354 SkASSERT(t != 1); 355 initBase(segment, prev, t, pt); 356 fCoincident = this; 357 fToAngle = nullptr; 358 fWindSum = fOppSum = SK_MinS32; 359 fWindValue = 1; 360 fOppValue = 0; 361 fTopTTry = 0; 362 fChased = fDone = false; 363 segment->bumpCount(); 364 fAlreadyAdded = false; 365 } 366 367 void SkOpSpan::setOppSum(int oppSum) { 368 SkASSERT(!final()); 369 if (fOppSum != SK_MinS32 && fOppSum != oppSum) { 370 this->globalState()->setWindingFailed(); 371 return; 372 } 373 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(oppSum) <= DEBUG_LIMIT_WIND_SUM); 374 fOppSum = oppSum; 375 } 376 377 void SkOpSpan::setWindSum(int windSum) { 378 SkASSERT(!final()); 379 if (fWindSum != SK_MinS32 && fWindSum != windSum) { 380 this->globalState()->setWindingFailed(); 381 return; 382 } 383 SkASSERT(!DEBUG_LIMIT_WIND_SUM || SkTAbs(windSum) <= DEBUG_LIMIT_WIND_SUM); 384 fWindSum = windSum; 385 } 386