1 /* 2 * Copyright 2015 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 "SkOpSegment.h" 9 #include "SkPathOpsTSect.h" 10 11 bool SkOpCoincidence::extend(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart, 12 SkOpPtT* oppPtTEnd) { 13 // if there is an existing pair that overlaps the addition, extend it 14 SkCoincidentSpans* coinRec = fHead; 15 if (coinRec) { 16 do { 17 if (coinRec->fCoinPtTStart->segment() != coinPtTStart->segment()) { 18 continue; 19 } 20 if (coinRec->fOppPtTStart->segment() != oppPtTStart->segment()) { 21 continue; 22 } 23 if (coinRec->fCoinPtTStart->fT > coinPtTEnd->fT) { 24 continue; 25 } 26 if (coinRec->fCoinPtTEnd->fT < coinPtTStart->fT) { 27 continue; 28 } 29 if (coinRec->fCoinPtTStart->fT > coinPtTStart->fT) { 30 coinRec->fCoinPtTStart = coinPtTStart; 31 coinRec->fOppPtTStart = oppPtTStart; 32 } 33 if (coinRec->fCoinPtTEnd->fT < coinPtTEnd->fT) { 34 coinRec->fCoinPtTEnd = coinPtTEnd; 35 coinRec->fOppPtTEnd = oppPtTEnd; 36 } 37 return true; 38 } while ((coinRec = coinRec->fNext)); 39 } 40 return false; 41 } 42 43 void SkOpCoincidence::add(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart, 44 SkOpPtT* oppPtTEnd, SkChunkAlloc* allocator) { 45 SkASSERT(coinPtTStart->fT < coinPtTEnd->fT); 46 bool flipped = oppPtTStart->fT > oppPtTEnd->fT; 47 SkCoincidentSpans* coinRec = SkOpTAllocator<SkCoincidentSpans>::Allocate(allocator); 48 coinRec->fNext = this->fHead; 49 coinRec->fCoinPtTStart = coinPtTStart; 50 coinRec->fCoinPtTEnd = coinPtTEnd; 51 coinRec->fOppPtTStart = oppPtTStart; 52 coinRec->fOppPtTEnd = oppPtTEnd; 53 coinRec->fFlipped = flipped; 54 this->fHead = coinRec; 55 } 56 57 static void t_range(const SkOpPtT* overS, const SkOpPtT* overE, double tStart, double tEnd, 58 const SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, double* coinTs, double* coinTe) { 59 double denom = overE->fT - overS->fT; 60 double start = 0 < denom ? tStart : tEnd; 61 double end = 0 < denom ? tEnd : tStart; 62 double sRatio = (start - overS->fT) / denom; 63 double eRatio = (end - overS->fT) / denom; 64 *coinTs = coinPtTStart->fT + (coinPtTEnd->fT - coinPtTStart->fT) * sRatio; 65 *coinTe = coinPtTStart->fT + (coinPtTEnd->fT - coinPtTStart->fT) * eRatio; 66 } 67 68 bool SkOpCoincidence::addIfMissing(const SkOpPtT* over1s, const SkOpPtT* over1e, 69 const SkOpPtT* over2s, const SkOpPtT* over2e, double tStart, double tEnd, 70 SkOpPtT* coinPtTStart, const SkOpPtT* coinPtTEnd, 71 SkOpPtT* oppPtTStart, const SkOpPtT* oppPtTEnd, SkChunkAlloc* allocator) { 72 double coinTs, coinTe, oppTs, oppTe; 73 t_range(over1s, over1e, tStart, tEnd, coinPtTStart, coinPtTEnd, &coinTs, &coinTe); 74 t_range(over2s, over2e, tStart, tEnd, oppPtTStart, oppPtTEnd, &oppTs, &oppTe); 75 SkOpSegment* coinSeg = coinPtTStart->segment(); 76 SkOpSegment* oppSeg = oppPtTStart->segment(); 77 SkASSERT(coinSeg != oppSeg); 78 SkCoincidentSpans* check = this->fHead; 79 do { 80 const SkOpSegment* checkCoinSeg = check->fCoinPtTStart->segment(); 81 if (checkCoinSeg != coinSeg && checkCoinSeg != oppSeg) { 82 continue; 83 } 84 const SkOpSegment* checkOppSeg = check->fOppPtTStart->segment(); 85 if (checkOppSeg != coinSeg && checkOppSeg != oppSeg) { 86 continue; 87 } 88 int cTs = coinTs; 89 int cTe = coinTe; 90 int oTs = oppTs; 91 int oTe = oppTe; 92 if (checkCoinSeg != coinSeg) { 93 SkASSERT(checkOppSeg != oppSeg); 94 SkTSwap(cTs, oTs); 95 SkTSwap(cTe, oTe); 96 } 97 int tweenCount = (int) between(check->fCoinPtTStart->fT, cTs, check->fCoinPtTEnd->fT) 98 + (int) between(check->fCoinPtTStart->fT, cTe, check->fCoinPtTEnd->fT) 99 + (int) between(check->fOppPtTStart->fT, oTs, check->fOppPtTEnd->fT) 100 + (int) between(check->fOppPtTStart->fT, oTe, check->fOppPtTEnd->fT); 101 // SkASSERT(tweenCount == 0 || tweenCount == 4); 102 if (tweenCount) { 103 return true; 104 } 105 } while ((check = check->fNext)); 106 if ((over1s->fT < over1e->fT) != (over2s->fT < over2e->fT)) { 107 SkTSwap(oppTs, oppTe); 108 } 109 if (coinTs > coinTe) { 110 SkTSwap(coinTs, coinTe); 111 SkTSwap(oppTs, oppTe); 112 } 113 SkOpPtT* cs = coinSeg->addMissing(coinTs, oppSeg, allocator); 114 SkOpPtT* ce = coinSeg->addMissing(coinTe, oppSeg, allocator); 115 if (cs == ce) { 116 return false; 117 } 118 SkOpPtT* os = oppSeg->addMissing(oppTs, coinSeg, allocator); 119 SkOpPtT* oe = oppSeg->addMissing(oppTe, coinSeg, allocator); 120 SkASSERT(os != oe); 121 cs->addOpp(os); 122 ce->addOpp(oe); 123 this->add(cs, ce, os, oe, allocator); 124 return true; 125 } 126 127 bool SkOpCoincidence::addMissing(SkChunkAlloc* allocator) { 128 SkCoincidentSpans* outer = this->fHead; 129 if (!outer) { 130 return true; 131 } 132 do { 133 SkCoincidentSpans* inner = outer; 134 while ((inner = inner->fNext)) { 135 double overS, overE; 136 if (this->overlap(outer->fCoinPtTStart, outer->fCoinPtTEnd, 137 inner->fCoinPtTStart, inner->fCoinPtTEnd, &overS, &overE)) { 138 if (!this->addIfMissing(outer->fCoinPtTStart, outer->fCoinPtTEnd, 139 inner->fCoinPtTStart, inner->fCoinPtTEnd, overS, overE, 140 outer->fOppPtTStart, outer->fOppPtTEnd, 141 inner->fOppPtTStart, inner->fOppPtTEnd, allocator)) { 142 return false; 143 } 144 } else if (this->overlap(outer->fCoinPtTStart, outer->fCoinPtTEnd, 145 inner->fOppPtTStart, inner->fOppPtTEnd, &overS, &overE)) { 146 if (!this->addIfMissing(outer->fCoinPtTStart, outer->fCoinPtTEnd, 147 inner->fOppPtTStart, inner->fOppPtTEnd, overS, overE, 148 outer->fOppPtTStart, outer->fOppPtTEnd, 149 inner->fCoinPtTStart, inner->fCoinPtTEnd, allocator)) { 150 return false; 151 } 152 } else if (this->overlap(outer->fOppPtTStart, outer->fOppPtTEnd, 153 inner->fCoinPtTStart, inner->fCoinPtTEnd, &overS, &overE)) { 154 if (!this->addIfMissing(outer->fOppPtTStart, outer->fOppPtTEnd, 155 inner->fCoinPtTStart, inner->fCoinPtTEnd, overS, overE, 156 outer->fCoinPtTStart, outer->fCoinPtTEnd, 157 inner->fOppPtTStart, inner->fOppPtTEnd, allocator)) { 158 return false; 159 } 160 } else if (this->overlap(outer->fOppPtTStart, outer->fOppPtTEnd, 161 inner->fOppPtTStart, inner->fOppPtTEnd, &overS, &overE)) { 162 if (!this->addIfMissing(outer->fOppPtTStart, outer->fOppPtTEnd, 163 inner->fOppPtTStart, inner->fOppPtTEnd, overS, overE, 164 outer->fCoinPtTStart, outer->fCoinPtTEnd, 165 inner->fCoinPtTStart, inner->fCoinPtTEnd, allocator)) { 166 return false; 167 } 168 } 169 } 170 171 } while ((outer = outer->fNext)); 172 return true; 173 } 174 175 bool SkOpCoincidence::contains(SkOpPtT* coinPtTStart, SkOpPtT* coinPtTEnd, SkOpPtT* oppPtTStart, 176 SkOpPtT* oppPtTEnd, bool flipped) { 177 SkCoincidentSpans* coin = fHead; 178 if (!coin) { 179 return false; 180 } 181 do { 182 if (coin->fCoinPtTStart == coinPtTStart && coin->fCoinPtTEnd == coinPtTEnd 183 && coin->fOppPtTStart == oppPtTStart && coin->fOppPtTEnd == oppPtTEnd 184 && coin->fFlipped == flipped) { 185 return true; 186 } 187 } while ((coin = coin->fNext)); 188 return false; 189 } 190 191 // walk span sets in parallel, moving winding from one to the other 192 bool SkOpCoincidence::apply() { 193 SkCoincidentSpans* coin = fHead; 194 if (!coin) { 195 return true; 196 } 197 do { 198 SkOpSpan* start = coin->fCoinPtTStart->span()->upCast(); 199 if (start->deleted()) { 200 continue; 201 } 202 SkOpSpanBase* end = coin->fCoinPtTEnd->span(); 203 SkASSERT(start == start->starter(end)); 204 bool flipped = coin->fFlipped; 205 SkOpSpan* oStart = (flipped ? coin->fOppPtTEnd : coin->fOppPtTStart)->span()->upCast(); 206 if (oStart->deleted()) { 207 continue; 208 } 209 SkOpSpanBase* oEnd = (flipped ? coin->fOppPtTStart : coin->fOppPtTEnd)->span(); 210 SkASSERT(oStart == oStart->starter(oEnd)); 211 SkOpSegment* segment = start->segment(); 212 SkOpSegment* oSegment = oStart->segment(); 213 bool operandSwap = segment->operand() != oSegment->operand(); 214 if (flipped) { 215 do { 216 SkOpSpanBase* oNext = oStart->next(); 217 if (oNext == oEnd) { 218 break; 219 } 220 oStart = oNext->upCast(); 221 } while (true); 222 } 223 do { 224 int windValue = start->windValue(); 225 int oppValue = start->oppValue(); 226 int oWindValue = oStart->windValue(); 227 int oOppValue = oStart->oppValue(); 228 // winding values are added or subtracted depending on direction and wind type 229 // same or opposite values are summed depending on the operand value 230 int windDiff = operandSwap ? oOppValue : oWindValue; 231 int oWindDiff = operandSwap ? oppValue : windValue; 232 if (!flipped) { 233 windDiff = -windDiff; 234 oWindDiff = -oWindDiff; 235 } 236 if (windValue && (windValue > windDiff || (windValue == windDiff 237 && oWindValue <= oWindDiff))) { 238 if (operandSwap) { 239 SkTSwap(oWindValue, oOppValue); 240 } 241 if (flipped) { 242 windValue -= oWindValue; 243 oppValue -= oOppValue; 244 } else { 245 windValue += oWindValue; 246 oppValue += oOppValue; 247 } 248 if (segment->isXor()) { 249 windValue &= 1; 250 } 251 if (segment->oppXor()) { 252 oppValue &= 1; 253 } 254 oWindValue = oOppValue = 0; 255 } else { 256 if (operandSwap) { 257 SkTSwap(windValue, oppValue); 258 } 259 if (flipped) { 260 oWindValue -= windValue; 261 oOppValue -= oppValue; 262 } else { 263 oWindValue += windValue; 264 oOppValue += oppValue; 265 } 266 if (oSegment->isXor()) { 267 oWindValue &= 1; 268 } 269 if (oSegment->oppXor()) { 270 oOppValue &= 1; 271 } 272 windValue = oppValue = 0; 273 } 274 start->setWindValue(windValue); 275 start->setOppValue(oppValue); 276 oStart->setWindValue(oWindValue); 277 oStart->setOppValue(oOppValue); 278 if (!windValue && !oppValue) { 279 segment->markDone(start); 280 } 281 if (!oWindValue && !oOppValue) { 282 oSegment->markDone(oStart); 283 } 284 SkOpSpanBase* next = start->next(); 285 SkOpSpanBase* oNext = flipped ? oStart->prev() : oStart->next(); 286 if (next == end) { 287 break; 288 } 289 start = next->upCast(); 290 // if the opposite ran out too soon, just reuse the last span 291 if (!oNext || !oNext->upCastable()) { 292 oNext = oStart; 293 } 294 oStart = oNext->upCast(); 295 } while (true); 296 } while ((coin = coin->fNext)); 297 return true; 298 } 299 300 void SkOpCoincidence::detach(SkCoincidentSpans* remove) { 301 SkCoincidentSpans* coin = fHead; 302 SkCoincidentSpans* prev = NULL; 303 SkCoincidentSpans* next; 304 do { 305 next = coin->fNext; 306 if (coin == remove) { 307 if (prev) { 308 prev->fNext = next; 309 } else { 310 fHead = next; 311 } 312 break; 313 } 314 prev = coin; 315 } while ((coin = next)); 316 SkASSERT(coin); 317 } 318 319 void SkOpCoincidence::expand() { 320 SkCoincidentSpans* coin = fHead; 321 if (!coin) { 322 return; 323 } 324 do { 325 SkOpSpan* start = coin->fCoinPtTStart->span()->upCast(); 326 SkOpSpanBase* end = coin->fCoinPtTEnd->span(); 327 SkOpSegment* segment = coin->fCoinPtTStart->segment(); 328 SkOpSegment* oppSegment = coin->fOppPtTStart->segment(); 329 SkOpSpan* prev = start->prev(); 330 SkOpPtT* oppPtT; 331 if (prev && (oppPtT = prev->contains(oppSegment))) { 332 double midT = (prev->t() + start->t()) / 2; 333 if (segment->isClose(midT, oppSegment)) { 334 coin->fCoinPtTStart = prev->ptT(); 335 coin->fOppPtTStart = oppPtT; 336 } 337 } 338 SkOpSpanBase* next = end->final() ? NULL : end->upCast()->next(); 339 if (next && (oppPtT = next->contains(oppSegment))) { 340 double midT = (end->t() + next->t()) / 2; 341 if (segment->isClose(midT, oppSegment)) { 342 coin->fCoinPtTEnd = next->ptT(); 343 coin->fOppPtTEnd = oppPtT; 344 } 345 } 346 } while ((coin = coin->fNext)); 347 } 348 349 void SkOpCoincidence::fixUp(SkOpPtT* deleted, SkOpPtT* kept) { 350 SkCoincidentSpans* coin = fHead; 351 if (!coin) { 352 return; 353 } 354 do { 355 if (coin->fCoinPtTStart == deleted) { 356 if (coin->fCoinPtTEnd->span() == kept->span()) { 357 return this->detach(coin); 358 } 359 coin->fCoinPtTStart = kept; 360 } 361 if (coin->fCoinPtTEnd == deleted) { 362 if (coin->fCoinPtTStart->span() == kept->span()) { 363 return this->detach(coin); 364 } 365 coin->fCoinPtTEnd = kept; 366 } 367 if (coin->fOppPtTStart == deleted) { 368 if (coin->fOppPtTEnd->span() == kept->span()) { 369 return this->detach(coin); 370 } 371 coin->fOppPtTStart = kept; 372 } 373 if (coin->fOppPtTEnd == deleted) { 374 if (coin->fOppPtTStart->span() == kept->span()) { 375 return this->detach(coin); 376 } 377 coin->fOppPtTEnd = kept; 378 } 379 } while ((coin = coin->fNext)); 380 } 381 382 void SkOpCoincidence::mark() { 383 SkCoincidentSpans* coin = fHead; 384 if (!coin) { 385 return; 386 } 387 do { 388 SkOpSpanBase* end = coin->fCoinPtTEnd->span(); 389 SkOpSpanBase* oldEnd = end; 390 SkOpSpan* start = coin->fCoinPtTStart->span()->starter(&end); 391 SkOpSpanBase* oEnd = coin->fOppPtTEnd->span(); 392 SkOpSpanBase* oOldEnd = oEnd; 393 SkOpSpanBase* oStart = coin->fOppPtTStart->span()->starter(&oEnd); 394 bool flipped = (end == oldEnd) != (oEnd == oOldEnd); 395 if (flipped) { 396 SkTSwap(oStart, oEnd); 397 } 398 SkOpSpanBase* next = start; 399 SkOpSpanBase* oNext = oStart; 400 // check to see if coincident span could be bigger 401 402 do { 403 next = next->upCast()->next(); 404 oNext = flipped ? oNext->prev() : oNext->upCast()->next(); 405 if (next == end || oNext == oEnd) { 406 break; 407 } 408 if (!next->containsCoinEnd(oNext)) { 409 next->insertCoinEnd(oNext); 410 } 411 SkOpSpan* nextSpan = next->upCast(); 412 SkOpSpan* oNextSpan = oNext->upCast(); 413 if (!nextSpan->containsCoincidence(oNextSpan)) { 414 nextSpan->insertCoincidence(oNextSpan); 415 } 416 } while (true); 417 } while ((coin = coin->fNext)); 418 } 419 420 bool SkOpCoincidence::overlap(const SkOpPtT* coin1s, const SkOpPtT* coin1e, 421 const SkOpPtT* coin2s, const SkOpPtT* coin2e, double* overS, double* overE) const { 422 if (coin1s->segment() != coin2s->segment()) { 423 return false; 424 } 425 *overS = SkTMax(SkTMin(coin1s->fT, coin1e->fT), SkTMin(coin2s->fT, coin2e->fT)); 426 *overE = SkTMin(SkTMax(coin1s->fT, coin1e->fT), SkTMax(coin2s->fT, coin2e->fT)); 427 return *overS < *overE; 428 } 429