1 /* 2 * Copyright 2012 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 "SkIntersections.h" 8 #include "SkOpContour.h" 9 #include "SkOpSegment.h" 10 #include "SkPathWriter.h" 11 #include "SkTSort.h" 12 13 #define F (false) // discard the edge 14 #define T (true) // keep the edge 15 16 static const bool gUnaryActiveEdge[2][2] = { 17 // from=0 from=1 18 // to=0,1 to=0,1 19 {F, T}, {T, F}, 20 }; 21 22 static const bool gActiveEdge[kXOR_PathOp + 1][2][2][2][2] = { 23 // miFrom=0 miFrom=1 24 // miTo=0 miTo=1 miTo=0 miTo=1 25 // suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1 26 // suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 27 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su 28 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su 29 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su 30 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su 31 }; 32 33 #undef F 34 #undef T 35 36 enum { 37 kOutsideTrackedTCount = 16, // FIXME: determine what this should be 38 kMissingSpanCount = 4, // FIXME: determine what this should be 39 }; 40 41 const SkOpAngle* SkOpSegment::activeAngle(int index, int* start, int* end, bool* done, 42 bool* sortable) const { 43 if (const SkOpAngle* result = activeAngleInner(index, start, end, done, sortable)) { 44 return result; 45 } 46 double referenceT = fTs[index].fT; 47 int lesser = index; 48 while (--lesser >= 0 49 && (precisely_negative(referenceT - fTs[lesser].fT) || fTs[lesser].fTiny)) { 50 if (const SkOpAngle* result = activeAngleOther(lesser, start, end, done, sortable)) { 51 return result; 52 } 53 } 54 do { 55 if (const SkOpAngle* result = activeAngleOther(index, start, end, done, sortable)) { 56 return result; 57 } 58 if (++index == fTs.count()) { 59 break; 60 } 61 if (fTs[index - 1].fTiny) { 62 referenceT = fTs[index].fT; 63 continue; 64 } 65 } while (precisely_negative(fTs[index].fT - referenceT)); 66 return NULL; 67 } 68 69 const SkOpAngle* SkOpSegment::activeAngleInner(int index, int* start, int* end, bool* done, 70 bool* sortable) const { 71 int next = nextExactSpan(index, 1); 72 if (next > 0) { 73 const SkOpSpan& upSpan = fTs[index]; 74 if (upSpan.fWindValue || upSpan.fOppValue) { 75 if (*end < 0) { 76 *start = index; 77 *end = next; 78 } 79 if (!upSpan.fDone) { 80 if (upSpan.fWindSum != SK_MinS32) { 81 return spanToAngle(index, next); 82 } 83 *done = false; 84 } 85 } else { 86 SkASSERT(upSpan.fDone); 87 } 88 } 89 int prev = nextExactSpan(index, -1); 90 // edge leading into junction 91 if (prev >= 0) { 92 const SkOpSpan& downSpan = fTs[prev]; 93 if (downSpan.fWindValue || downSpan.fOppValue) { 94 if (*end < 0) { 95 *start = index; 96 *end = prev; 97 } 98 if (!downSpan.fDone) { 99 if (downSpan.fWindSum != SK_MinS32) { 100 return spanToAngle(index, prev); 101 } 102 *done = false; 103 } 104 } else { 105 SkASSERT(downSpan.fDone); 106 } 107 } 108 return NULL; 109 } 110 111 const SkOpAngle* SkOpSegment::activeAngleOther(int index, int* start, int* end, bool* done, 112 bool* sortable) const { 113 const SkOpSpan* span = &fTs[index]; 114 SkOpSegment* other = span->fOther; 115 int oIndex = span->fOtherIndex; 116 return other->activeAngleInner(oIndex, start, end, done, sortable); 117 } 118 119 SkPoint SkOpSegment::activeLeftTop(int* firstT) const { 120 SkASSERT(!done()); 121 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax}; 122 int count = fTs.count(); 123 // see if either end is not done since we want smaller Y of the pair 124 bool lastDone = true; 125 double lastT = -1; 126 for (int index = 0; index < count; ++index) { 127 const SkOpSpan& span = fTs[index]; 128 if (span.fDone && lastDone) { 129 goto next; 130 } 131 if (approximately_negative(span.fT - lastT)) { 132 goto next; 133 } 134 { 135 const SkPoint& xy = xyAtT(&span); 136 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) { 137 topPt = xy; 138 if (firstT) { 139 *firstT = index; 140 } 141 } 142 if (fVerb != SkPath::kLine_Verb && !lastDone) { 143 SkPoint curveTop = (*CurveTop[SkPathOpsVerbToPoints(fVerb)])(fPts, lastT, span.fT); 144 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY 145 && topPt.fX > curveTop.fX)) { 146 topPt = curveTop; 147 if (firstT) { 148 *firstT = index; 149 } 150 } 151 } 152 lastT = span.fT; 153 } 154 next: 155 lastDone = span.fDone; 156 } 157 return topPt; 158 } 159 160 bool SkOpSegment::activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, SkPathOp op) { 161 int sumMiWinding = updateWinding(endIndex, index); 162 int sumSuWinding = updateOppWinding(endIndex, index); 163 if (fOperand) { 164 SkTSwap<int>(sumMiWinding, sumSuWinding); 165 } 166 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, &sumMiWinding, &sumSuWinding); 167 } 168 169 bool SkOpSegment::activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, SkPathOp op, 170 int* sumMiWinding, int* sumSuWinding) { 171 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; 172 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding, 173 &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); 174 bool miFrom; 175 bool miTo; 176 bool suFrom; 177 bool suTo; 178 if (operand()) { 179 miFrom = (oppMaxWinding & xorMiMask) != 0; 180 miTo = (oppSumWinding & xorMiMask) != 0; 181 suFrom = (maxWinding & xorSuMask) != 0; 182 suTo = (sumWinding & xorSuMask) != 0; 183 } else { 184 miFrom = (maxWinding & xorMiMask) != 0; 185 miTo = (sumWinding & xorMiMask) != 0; 186 suFrom = (oppMaxWinding & xorSuMask) != 0; 187 suTo = (oppSumWinding & xorSuMask) != 0; 188 } 189 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo]; 190 #if DEBUG_ACTIVE_OP 191 SkDebugf("%s id=%d t=%1.9g tEnd=%1.9g op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", 192 __FUNCTION__, debugID(), span(index).fT, span(endIndex).fT, 193 SkPathOpsDebug::kPathOpStr[op], miFrom, miTo, suFrom, suTo, result); 194 #endif 195 return result; 196 } 197 198 bool SkOpSegment::activeWinding(int index, int endIndex) { 199 int sumWinding = updateWinding(endIndex, index); 200 return activeWinding(index, endIndex, &sumWinding); 201 } 202 203 bool SkOpSegment::activeWinding(int index, int endIndex, int* sumWinding) { 204 int maxWinding; 205 setUpWinding(index, endIndex, &maxWinding, sumWinding); 206 bool from = maxWinding != 0; 207 bool to = *sumWinding != 0; 208 bool result = gUnaryActiveEdge[from][to]; 209 return result; 210 } 211 212 void SkOpSegment::addCancelOutsides(const SkPoint& startPt, const SkPoint& endPt, 213 SkOpSegment* other) { 214 int tIndex = -1; 215 int tCount = fTs.count(); 216 int oIndex = -1; 217 int oCount = other->fTs.count(); 218 do { 219 ++tIndex; 220 } while (startPt != fTs[tIndex].fPt && tIndex < tCount); 221 int tIndexStart = tIndex; 222 do { 223 ++oIndex; 224 } while (endPt != other->fTs[oIndex].fPt && oIndex < oCount); 225 int oIndexStart = oIndex; 226 const SkPoint* nextPt; 227 do { 228 nextPt = &fTs[++tIndex].fPt; 229 SkASSERT(fTs[tIndex].fT < 1 || startPt != *nextPt); 230 } while (startPt == *nextPt); 231 double nextT = fTs[tIndex].fT; 232 const SkPoint* oNextPt; 233 do { 234 oNextPt = &other->fTs[++oIndex].fPt; 235 SkASSERT(other->fTs[oIndex].fT < 1 || endPt != *oNextPt); 236 } while (endPt == *oNextPt); 237 double oNextT = other->fTs[oIndex].fT; 238 // at this point, spans before and after are at: 239 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex] 240 // if tIndexStart == 0, no prior span 241 // if nextT == 1, no following span 242 243 // advance the span with zero winding 244 // if the following span exists (not past the end, non-zero winding) 245 // connect the two edges 246 if (!fTs[tIndexStart].fWindValue) { 247 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) { 248 #if DEBUG_CONCIDENT 249 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", 250 __FUNCTION__, fID, other->fID, tIndexStart - 1, 251 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX, 252 xyAtT(tIndexStart).fY); 253 #endif 254 SkPoint copy = fTs[tIndexStart].fPt; // add t pair may move the point array 255 addTPair(fTs[tIndexStart].fT, other, other->fTs[oIndex].fT, false, copy); 256 } 257 if (nextT < 1 && fTs[tIndex].fWindValue) { 258 #if DEBUG_CONCIDENT 259 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", 260 __FUNCTION__, fID, other->fID, tIndex, 261 fTs[tIndex].fT, xyAtT(tIndex).fX, 262 xyAtT(tIndex).fY); 263 #endif 264 SkPoint copy = fTs[tIndex].fPt; // add t pair may move the point array 265 addTPair(fTs[tIndex].fT, other, other->fTs[oIndexStart].fT, false, copy); 266 } 267 } else { 268 SkASSERT(!other->fTs[oIndexStart].fWindValue); 269 if (oIndexStart > 0 && other->fTs[oIndexStart - 1].fWindValue) { 270 #if DEBUG_CONCIDENT 271 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", 272 __FUNCTION__, fID, other->fID, oIndexStart - 1, 273 other->fTs[oIndexStart].fT, other->xyAtT(oIndexStart).fX, 274 other->xyAtT(oIndexStart).fY); 275 other->debugAddTPair(other->fTs[oIndexStart].fT, *this, fTs[tIndex].fT); 276 #endif 277 } 278 if (oNextT < 1 && other->fTs[oIndex].fWindValue) { 279 #if DEBUG_CONCIDENT 280 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", 281 __FUNCTION__, fID, other->fID, oIndex, 282 other->fTs[oIndex].fT, other->xyAtT(oIndex).fX, 283 other->xyAtT(oIndex).fY); 284 other->debugAddTPair(other->fTs[oIndex].fT, *this, fTs[tIndexStart].fT); 285 #endif 286 } 287 } 288 } 289 290 void SkOpSegment::addCoinOutsides(const SkPoint& startPt, const SkPoint& endPt, 291 SkOpSegment* other) { 292 // walk this to startPt 293 // walk other to startPt 294 // if either is > 0, add a pointer to the other, copying adjacent winding 295 int tIndex = -1; 296 int oIndex = -1; 297 do { 298 ++tIndex; 299 } while (startPt != fTs[tIndex].fPt); 300 int ttIndex = tIndex; 301 bool checkOtherTMatch = false; 302 do { 303 const SkOpSpan& span = fTs[ttIndex]; 304 if (startPt != span.fPt) { 305 break; 306 } 307 if (span.fOther == other && span.fPt == startPt) { 308 checkOtherTMatch = true; 309 break; 310 } 311 } while (++ttIndex < count()); 312 do { 313 ++oIndex; 314 } while (startPt != other->fTs[oIndex].fPt); 315 bool skipAdd = false; 316 if (checkOtherTMatch) { 317 int ooIndex = oIndex; 318 do { 319 const SkOpSpan& oSpan = other->fTs[ooIndex]; 320 if (startPt != oSpan.fPt) { 321 break; 322 } 323 if (oSpan.fT == fTs[ttIndex].fOtherT) { 324 skipAdd = true; 325 break; 326 } 327 } while (++ooIndex < other->count()); 328 } 329 if ((tIndex > 0 || oIndex > 0 || fOperand != other->fOperand) && !skipAdd) { 330 addTPair(fTs[tIndex].fT, other, other->fTs[oIndex].fT, false, startPt); 331 } 332 SkPoint nextPt = startPt; 333 do { 334 const SkPoint* workPt; 335 do { 336 workPt = &fTs[++tIndex].fPt; 337 } while (nextPt == *workPt); 338 const SkPoint* oWorkPt; 339 do { 340 oWorkPt = &other->fTs[++oIndex].fPt; 341 } while (nextPt == *oWorkPt); 342 nextPt = *workPt; 343 double tStart = fTs[tIndex].fT; 344 double oStart = other->fTs[oIndex].fT; 345 if (tStart == 1 && oStart == 1 && fOperand == other->fOperand) { 346 break; 347 } 348 if (*workPt == *oWorkPt) { 349 addTPair(tStart, other, oStart, false, nextPt); 350 } 351 } while (endPt != nextPt); 352 } 353 354 void SkOpSegment::addCubic(const SkPoint pts[4], bool operand, bool evenOdd) { 355 init(pts, SkPath::kCubic_Verb, operand, evenOdd); 356 fBounds.setCubicBounds(pts); 357 } 358 359 void SkOpSegment::addCurveTo(int start, int end, SkPathWriter* path, bool active) const { 360 SkPoint edge[4]; 361 const SkPoint* ePtr; 362 int lastT = fTs.count() - 1; 363 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) { 364 ePtr = fPts; 365 } else { 366 // OPTIMIZE? if not active, skip remainder and return xyAtT(end) 367 subDivide(start, end, edge); 368 ePtr = edge; 369 } 370 if (active) { 371 bool reverse = ePtr == fPts && start != 0; 372 if (reverse) { 373 path->deferredMoveLine(ePtr[SkPathOpsVerbToPoints(fVerb)]); 374 switch (fVerb) { 375 case SkPath::kLine_Verb: 376 path->deferredLine(ePtr[0]); 377 break; 378 case SkPath::kQuad_Verb: 379 path->quadTo(ePtr[1], ePtr[0]); 380 break; 381 case SkPath::kCubic_Verb: 382 path->cubicTo(ePtr[2], ePtr[1], ePtr[0]); 383 break; 384 default: 385 SkASSERT(0); 386 } 387 // return ePtr[0]; 388 } else { 389 path->deferredMoveLine(ePtr[0]); 390 switch (fVerb) { 391 case SkPath::kLine_Verb: 392 path->deferredLine(ePtr[1]); 393 break; 394 case SkPath::kQuad_Verb: 395 path->quadTo(ePtr[1], ePtr[2]); 396 break; 397 case SkPath::kCubic_Verb: 398 path->cubicTo(ePtr[1], ePtr[2], ePtr[3]); 399 break; 400 default: 401 SkASSERT(0); 402 } 403 } 404 } 405 // return ePtr[SkPathOpsVerbToPoints(fVerb)]; 406 } 407 408 void SkOpSegment::addEndSpan(int endIndex) { 409 SkASSERT(span(endIndex).fT == 1 || (span(endIndex).fTiny 410 // && approximately_greater_than_one(span(endIndex).fT) 411 )); 412 int spanCount = fTs.count(); 413 int startIndex = endIndex - 1; 414 while (fTs[startIndex].fT == 1 || fTs[startIndex].fTiny) { 415 --startIndex; 416 SkASSERT(startIndex > 0); 417 --endIndex; 418 } 419 SkOpAngle& angle = fAngles.push_back(); 420 angle.set(this, spanCount - 1, startIndex); 421 #if DEBUG_ANGLE 422 debugCheckPointsEqualish(endIndex, spanCount); 423 #endif 424 setFromAngle(endIndex, &angle); 425 } 426 427 void SkOpSegment::setFromAngle(int endIndex, SkOpAngle* angle) { 428 int spanCount = fTs.count(); 429 do { 430 fTs[endIndex].fFromAngle = angle; 431 } while (++endIndex < spanCount); 432 } 433 434 void SkOpSegment::addLine(const SkPoint pts[2], bool operand, bool evenOdd) { 435 init(pts, SkPath::kLine_Verb, operand, evenOdd); 436 fBounds.set(pts, 2); 437 } 438 439 // add 2 to edge or out of range values to get T extremes 440 void SkOpSegment::addOtherT(int index, double otherT, int otherIndex) { 441 SkOpSpan& span = fTs[index]; 442 if (precisely_zero(otherT)) { 443 otherT = 0; 444 } else if (precisely_equal(otherT, 1)) { 445 otherT = 1; 446 } 447 span.fOtherT = otherT; 448 span.fOtherIndex = otherIndex; 449 } 450 451 void SkOpSegment::addQuad(const SkPoint pts[3], bool operand, bool evenOdd) { 452 init(pts, SkPath::kQuad_Verb, operand, evenOdd); 453 fBounds.setQuadBounds(pts); 454 } 455 456 SkOpAngle* SkOpSegment::addSingletonAngleDown(SkOpSegment** otherPtr, SkOpAngle** anglePtr) { 457 int spanIndex = count() - 1; 458 int startIndex = nextExactSpan(spanIndex, -1); 459 SkASSERT(startIndex >= 0); 460 SkOpAngle& angle = fAngles.push_back(); 461 *anglePtr = ∠ 462 angle.set(this, spanIndex, startIndex); 463 setFromAngle(spanIndex, &angle); 464 SkOpSegment* other; 465 int oStartIndex, oEndIndex; 466 do { 467 const SkOpSpan& span = fTs[spanIndex]; 468 SkASSERT(span.fT > 0); 469 other = span.fOther; 470 oStartIndex = span.fOtherIndex; 471 oEndIndex = other->nextExactSpan(oStartIndex, 1); 472 if (oEndIndex > 0 && other->span(oStartIndex).fWindValue) { 473 break; 474 } 475 oEndIndex = oStartIndex; 476 oStartIndex = other->nextExactSpan(oEndIndex, -1); 477 --spanIndex; 478 } while (oStartIndex < 0 || !other->span(oStartIndex).fWindSum); 479 SkOpAngle& oAngle = other->fAngles.push_back(); 480 oAngle.set(other, oStartIndex, oEndIndex); 481 other->setToAngle(oEndIndex, &oAngle); 482 *otherPtr = other; 483 return &oAngle; 484 } 485 486 SkOpAngle* SkOpSegment::addSingletonAngleUp(SkOpSegment** otherPtr, SkOpAngle** anglePtr) { 487 int endIndex = nextExactSpan(0, 1); 488 SkASSERT(endIndex > 0); 489 SkOpAngle& angle = fAngles.push_back(); 490 *anglePtr = ∠ 491 angle.set(this, 0, endIndex); 492 setToAngle(endIndex, &angle); 493 int spanIndex = 0; 494 SkOpSegment* other; 495 int oStartIndex, oEndIndex; 496 do { 497 const SkOpSpan& span = fTs[spanIndex]; 498 SkASSERT(span.fT < 1); 499 other = span.fOther; 500 oEndIndex = span.fOtherIndex; 501 oStartIndex = other->nextExactSpan(oEndIndex, -1); 502 if (oStartIndex >= 0 && other->span(oStartIndex).fWindValue) { 503 break; 504 } 505 oStartIndex = oEndIndex; 506 oEndIndex = other->nextExactSpan(oStartIndex, 1); 507 ++spanIndex; 508 } while (oEndIndex < 0 || !other->span(oStartIndex).fWindValue); 509 SkOpAngle& oAngle = other->fAngles.push_back(); 510 oAngle.set(other, oEndIndex, oStartIndex); 511 other->setFromAngle(oEndIndex, &oAngle); 512 *otherPtr = other; 513 return &oAngle; 514 } 515 516 SkOpAngle* SkOpSegment::addSingletonAngles(int step) { 517 SkOpSegment* other; 518 SkOpAngle* angle, * otherAngle; 519 if (step > 0) { 520 otherAngle = addSingletonAngleUp(&other, &angle); 521 } else { 522 otherAngle = addSingletonAngleDown(&other, &angle); 523 } 524 angle->insert(otherAngle); 525 return angle; 526 } 527 528 void SkOpSegment::addStartSpan(int endIndex) { 529 int index = 0; 530 SkOpAngle& angle = fAngles.push_back(); 531 angle.set(this, index, endIndex); 532 #if DEBUG_ANGLE 533 debugCheckPointsEqualish(index, endIndex); 534 #endif 535 setToAngle(endIndex, &angle); 536 } 537 538 void SkOpSegment::setToAngle(int endIndex, SkOpAngle* angle) { 539 int index = 0; 540 do { 541 fTs[index].fToAngle = angle; 542 } while (++index < endIndex); 543 } 544 545 // Defer all coincident edge processing until 546 // after normal intersections have been computed 547 548 // no need to be tricky; insert in normal T order 549 // resolve overlapping ts when considering coincidence later 550 551 // add non-coincident intersection. Resulting edges are sorted in T. 552 int SkOpSegment::addT(SkOpSegment* other, const SkPoint& pt, double newT) { 553 SkASSERT(this != other || fVerb == SkPath::kCubic_Verb); 554 #if 0 // this needs an even rougher association to be useful 555 SkASSERT(SkDPoint::RoughlyEqual(ptAtT(newT), pt)); 556 #endif 557 const SkPoint& firstPt = fPts[0]; 558 const SkPoint& lastPt = fPts[SkPathOpsVerbToPoints(fVerb)]; 559 SkASSERT(newT == 0 || !precisely_zero(newT)); 560 SkASSERT(newT == 1 || !precisely_equal(newT, 1)); 561 // FIXME: in the pathological case where there is a ton of intercepts, 562 // binary search? 563 int insertedAt = -1; 564 int tCount = fTs.count(); 565 for (int index = 0; index < tCount; ++index) { 566 // OPTIMIZATION: if there are three or more identical Ts, then 567 // the fourth and following could be further insertion-sorted so 568 // that all the edges are clockwise or counterclockwise. 569 // This could later limit segment tests to the two adjacent 570 // neighbors, although it doesn't help with determining which 571 // circular direction to go in. 572 const SkOpSpan& span = fTs[index]; 573 if (newT < span.fT) { 574 insertedAt = index; 575 break; 576 } 577 if (newT == span.fT) { 578 if (pt == span.fPt) { 579 insertedAt = index; 580 break; 581 } 582 if ((pt == firstPt && newT == 0) || (span.fPt == lastPt && newT == 1)) { 583 insertedAt = index; 584 break; 585 } 586 } 587 } 588 SkOpSpan* span; 589 if (insertedAt >= 0) { 590 span = fTs.insert(insertedAt); 591 } else { 592 insertedAt = tCount; 593 span = fTs.append(); 594 } 595 span->fT = newT; 596 span->fOtherT = -1; 597 span->fOther = other; 598 span->fPt = pt; 599 #if 0 600 // cubics, for instance, may not be exact enough to satisfy this check (e.g., cubicOp69d) 601 SkASSERT(approximately_equal(xyAtT(newT).fX, pt.fX) 602 && approximately_equal(xyAtT(newT).fY, pt.fY)); 603 #endif 604 span->fFromAngle = NULL; 605 span->fToAngle = NULL; 606 span->fWindSum = SK_MinS32; 607 span->fOppSum = SK_MinS32; 608 span->fWindValue = 1; 609 span->fOppValue = 0; 610 span->fChased = false; 611 span->fCoincident = false; 612 span->fLoop = false; 613 span->fNear = false; 614 span->fMultiple = false; 615 span->fSmall = false; 616 span->fTiny = false; 617 if ((span->fDone = newT == 1)) { 618 ++fDoneSpans; 619 } 620 int less = -1; 621 // FIXME: note that this relies on spans being a continguous array 622 // find range of spans with nearly the same point as this one 623 // FIXME: SkDPoint::ApproximatelyEqual is better but breaks tests at the moment 624 while (&span[less + 1] - fTs.begin() > 0 && AlmostEqualUlps(span[less].fPt, pt)) { 625 if (fVerb == SkPath::kCubic_Verb) { 626 double tInterval = newT - span[less].fT; 627 double tMid = newT - tInterval / 2; 628 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid); 629 if (!midPt.approximatelyEqual(xyAtT(span))) { 630 break; 631 } 632 } 633 --less; 634 } 635 int more = 1; 636 // FIXME: SkDPoint::ApproximatelyEqual is better but breaks tests at the moment 637 while (fTs.end() - &span[more - 1] > 1 && AlmostEqualUlps(span[more].fPt, pt)) { 638 if (fVerb == SkPath::kCubic_Verb) { 639 double tEndInterval = span[more].fT - newT; 640 double tMid = newT - tEndInterval / 2; 641 SkDPoint midEndPt = dcubic_xy_at_t(fPts, tMid); 642 if (!midEndPt.approximatelyEqual(xyAtT(span))) { 643 break; 644 } 645 } 646 ++more; 647 } 648 ++less; 649 --more; 650 while (more - 1 > less && span[more].fPt == span[more - 1].fPt 651 && span[more].fT == span[more - 1].fT) { 652 --more; 653 } 654 if (less == more) { 655 return insertedAt; 656 } 657 if (precisely_negative(span[more].fT - span[less].fT)) { 658 return insertedAt; 659 } 660 // if the total range of t values is big enough, mark all tiny 661 bool tiny = span[less].fPt == span[more].fPt; 662 int index = less; 663 do { 664 fSmall = span[index].fSmall = true; 665 fTiny |= span[index].fTiny = tiny; 666 if (!span[index].fDone) { 667 span[index].fDone = true; 668 ++fDoneSpans; 669 } 670 } while (++index < more); 671 return insertedAt; 672 } 673 674 // set spans from start to end to decrement by one 675 // note this walks other backwards 676 // FIXME: there's probably an edge case that can be constructed where 677 // two span in one segment are separated by float epsilon on one span but 678 // not the other, if one segment is very small. For this 679 // case the counts asserted below may or may not be enough to separate the 680 // spans. Even if the counts work out, what if the spans aren't correctly 681 // sorted? It feels better in such a case to match the span's other span 682 // pointer since both coincident segments must contain the same spans. 683 // FIXME? It seems that decrementing by one will fail for complex paths that 684 // have three or more coincident edges. Shouldn't this subtract the difference 685 // between the winding values? 686 /* |--> |--> 687 this 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>4 0>>>>1>>>>2>>>>3>>>4 688 other 2<<<<1<<<<0 2<<<<1<<<<0 2<<<<1<<<<0 689 ^ ^ <--| <--| 690 startPt endPt test/oTest first pos test/oTest final pos 691 */ 692 void SkOpSegment::addTCancel(const SkPoint& startPt, const SkPoint& endPt, SkOpSegment* other) { 693 bool binary = fOperand != other->fOperand; 694 int index = 0; 695 while (startPt != fTs[index].fPt) { 696 SkASSERT(index < fTs.count()); 697 ++index; 698 } 699 while (index > 0 && precisely_equal(fTs[index].fT, fTs[index - 1].fT)) { 700 --index; 701 } 702 bool oFoundEnd = false; 703 int oIndex = other->fTs.count(); 704 while (startPt != other->fTs[--oIndex].fPt) { // look for startPt match 705 SkASSERT(oIndex > 0); 706 } 707 double oStartT = other->fTs[oIndex].fT; 708 // look for first point beyond match 709 while (startPt == other->fTs[--oIndex].fPt || precisely_equal(oStartT, other->fTs[oIndex].fT)) { 710 if (!oIndex) { 711 return; // tiny spans may move in the wrong direction 712 } 713 } 714 SkOpSpan* test = &fTs[index]; 715 SkOpSpan* oTest = &other->fTs[oIndex]; 716 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts; 717 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; 718 bool decrement, track, bigger; 719 int originalWindValue; 720 const SkPoint* testPt; 721 const SkPoint* oTestPt; 722 do { 723 SkASSERT(test->fT < 1); 724 SkASSERT(oTest->fT < 1); 725 decrement = test->fWindValue && oTest->fWindValue; 726 track = test->fWindValue || oTest->fWindValue; 727 bigger = test->fWindValue >= oTest->fWindValue; 728 testPt = &test->fPt; 729 double testT = test->fT; 730 oTestPt = &oTest->fPt; 731 double oTestT = oTest->fT; 732 do { 733 if (decrement) { 734 if (binary && bigger) { 735 test->fOppValue--; 736 } else { 737 decrementSpan(test); 738 } 739 } else if (track) { 740 TrackOutsidePair(&outsidePts, *testPt, *oTestPt); 741 } 742 SkASSERT(index < fTs.count() - 1); 743 test = &fTs[++index]; 744 } while (*testPt == test->fPt || precisely_equal(testT, test->fT)); 745 originalWindValue = oTest->fWindValue; 746 do { 747 SkASSERT(oTest->fT < 1); 748 SkASSERT(originalWindValue == oTest->fWindValue); 749 if (decrement) { 750 if (binary && !bigger) { 751 oTest->fOppValue--; 752 } else { 753 other->decrementSpan(oTest); 754 } 755 } else if (track) { 756 TrackOutsidePair(&oOutsidePts, *oTestPt, *testPt); 757 } 758 if (!oIndex) { 759 break; 760 } 761 oFoundEnd |= endPt == oTest->fPt; 762 oTest = &other->fTs[--oIndex]; 763 } while (*oTestPt == oTest->fPt || precisely_equal(oTestT, oTest->fT)); 764 } while (endPt != test->fPt && test->fT < 1); 765 // FIXME: determine if canceled edges need outside ts added 766 if (!oFoundEnd) { 767 for (int oIdx2 = oIndex; oIdx2 >= 0; --oIdx2) { 768 SkOpSpan* oTst2 = &other->fTs[oIdx2]; 769 if (originalWindValue != oTst2->fWindValue) { 770 goto skipAdvanceOtherCancel; 771 } 772 if (!oTst2->fWindValue) { 773 goto skipAdvanceOtherCancel; 774 } 775 if (endPt == other->fTs[oIdx2].fPt) { 776 break; 777 } 778 } 779 do { 780 SkASSERT(originalWindValue == oTest->fWindValue); 781 if (decrement) { 782 if (binary && !bigger) { 783 oTest->fOppValue--; 784 } else { 785 other->decrementSpan(oTest); 786 } 787 } else if (track) { 788 TrackOutsidePair(&oOutsidePts, *oTestPt, *testPt); 789 } 790 if (!oIndex) { 791 break; 792 } 793 oTest = &other->fTs[--oIndex]; 794 oFoundEnd |= endPt == oTest->fPt; 795 } while (!oFoundEnd || endPt == oTest->fPt); 796 } 797 skipAdvanceOtherCancel: 798 int outCount = outsidePts.count(); 799 if (!done() && outCount) { 800 addCancelOutsides(outsidePts[0], outsidePts[1], other); 801 if (outCount > 2) { 802 addCancelOutsides(outsidePts[outCount - 2], outsidePts[outCount - 1], other); 803 } 804 } 805 if (!other->done() && oOutsidePts.count()) { 806 other->addCancelOutsides(oOutsidePts[0], oOutsidePts[1], this); 807 } 808 setCoincidentRange(startPt, endPt, other); 809 other->setCoincidentRange(startPt, endPt, this); 810 } 811 812 int SkOpSegment::addSelfT(const SkPoint& pt, double newT) { 813 // if the tail nearly intersects itself but not quite, the caller records this separately 814 int result = addT(this, pt, newT); 815 SkOpSpan* span = &fTs[result]; 816 fLoop = span->fLoop = true; 817 return result; 818 } 819 820 // find the starting or ending span with an existing loop of angles 821 // FIXME? replicate for all identical starting/ending spans? 822 // OPTIMIZE? remove the spans pointing to windValue==0 here or earlier? 823 // FIXME? assert that only one other span has a valid windValue or oppValue 824 void SkOpSegment::addSimpleAngle(int index) { 825 SkOpSpan* span = &fTs[index]; 826 int idx; 827 int start, end; 828 if (span->fT == 0) { 829 idx = 0; 830 span = &fTs[0]; 831 do { 832 if (span->fToAngle) { 833 SkASSERT(span->fToAngle->loopCount() == 2); 834 SkASSERT(!span->fFromAngle); 835 span->fFromAngle = span->fToAngle->next(); 836 return; 837 } 838 span = &fTs[++idx]; 839 } while (span->fT == 0); 840 SkASSERT(!fTs[0].fTiny && fTs[idx].fT > 0); 841 addStartSpan(idx); 842 start = 0; 843 end = idx; 844 } else { 845 idx = count() - 1; 846 span = &fTs[idx]; 847 do { 848 if (span->fFromAngle) { 849 SkASSERT(span->fFromAngle->loopCount() == 2); 850 SkASSERT(!span->fToAngle); 851 span->fToAngle = span->fFromAngle->next(); 852 return; 853 } 854 span = &fTs[--idx]; 855 } while (span->fT == 1); 856 SkASSERT(!fTs[idx].fTiny && fTs[idx].fT < 1); 857 addEndSpan(++idx); 858 start = idx; 859 end = count(); 860 } 861 SkOpSegment* other; 862 SkOpSpan* oSpan; 863 index = start; 864 do { 865 span = &fTs[index]; 866 other = span->fOther; 867 int oFrom = span->fOtherIndex; 868 oSpan = &other->fTs[oFrom]; 869 if (oSpan->fT < 1 && oSpan->fWindValue) { 870 break; 871 } 872 if (oSpan->fT == 0) { 873 continue; 874 } 875 oFrom = other->nextExactSpan(oFrom, -1); 876 SkOpSpan* oFromSpan = &other->fTs[oFrom]; 877 SkASSERT(oFromSpan->fT < 1); 878 if (oFromSpan->fWindValue) { 879 break; 880 } 881 } while (++index < end); 882 SkOpAngle* angle, * oAngle; 883 if (span->fT == 0) { 884 SkASSERT(span->fOtherIndex - 1 >= 0); 885 SkASSERT(span->fOtherT == 1); 886 SkDEBUGCODE(int oPriorIndex = other->nextExactSpan(span->fOtherIndex, -1)); 887 SkDEBUGCODE(const SkOpSpan& oPrior = other->span(oPriorIndex)); 888 SkASSERT(!oPrior.fTiny && oPrior.fT < 1); 889 other->addEndSpan(span->fOtherIndex); 890 angle = span->fToAngle; 891 oAngle = oSpan->fFromAngle; 892 } else { 893 SkASSERT(span->fOtherIndex + 1 < other->count()); 894 SkASSERT(span->fOtherT == 0); 895 SkASSERT(!oSpan->fTiny && (other->fTs[span->fOtherIndex + 1].fT > 0 896 || (other->fTs[span->fOtherIndex + 1].fFromAngle == NULL 897 && other->fTs[span->fOtherIndex + 1].fToAngle == NULL))); 898 int oIndex = 1; 899 do { 900 const SkOpSpan& osSpan = other->span(oIndex); 901 if (osSpan.fFromAngle || osSpan.fT > 0) { 902 break; 903 } 904 ++oIndex; 905 SkASSERT(oIndex < other->count()); 906 } while (true); 907 other->addStartSpan(oIndex); 908 angle = span->fFromAngle; 909 oAngle = oSpan->fToAngle; 910 } 911 angle->insert(oAngle); 912 } 913 914 void SkOpSegment::alignMultiples(SkTDArray<AlignedSpan>* alignedArray) { 915 debugValidate(); 916 int count = this->count(); 917 for (int index = 0; index < count; ++index) { 918 SkOpSpan& span = fTs[index]; 919 if (!span.fMultiple) { 920 continue; 921 } 922 int end = nextExactSpan(index, 1); 923 SkASSERT(end > index + 1); 924 const SkPoint& thisPt = span.fPt; 925 while (index < end - 1) { 926 SkOpSegment* other1 = span.fOther; 927 int oCnt = other1->count(); 928 for (int idx2 = index + 1; idx2 < end; ++idx2) { 929 SkOpSpan& span2 = fTs[idx2]; 930 SkOpSegment* other2 = span2.fOther; 931 for (int oIdx = 0; oIdx < oCnt; ++oIdx) { 932 SkOpSpan& oSpan = other1->fTs[oIdx]; 933 if (oSpan.fOther != other2) { 934 continue; 935 } 936 if (oSpan.fPt == thisPt) { 937 goto skipExactMatches; 938 } 939 } 940 for (int oIdx = 0; oIdx < oCnt; ++oIdx) { 941 SkOpSpan& oSpan = other1->fTs[oIdx]; 942 if (oSpan.fOther != other2) { 943 continue; 944 } 945 if (SkDPoint::RoughlyEqual(oSpan.fPt, thisPt)) { 946 SkOpSpan& oSpan2 = other2->fTs[oSpan.fOtherIndex]; 947 if (zero_or_one(span.fOtherT) || zero_or_one(oSpan.fT) 948 || zero_or_one(span2.fOtherT) || zero_or_one(oSpan2.fT)) { 949 return; 950 } 951 if (!way_roughly_equal(span.fOtherT, oSpan.fT) 952 || !way_roughly_equal(span2.fOtherT, oSpan2.fT) 953 || !way_roughly_equal(span2.fOtherT, oSpan.fOtherT) 954 || !way_roughly_equal(span.fOtherT, oSpan2.fOtherT)) { 955 return; 956 } 957 alignSpan(thisPt, span.fOtherT, other1, span2.fOtherT, 958 other2, &oSpan, alignedArray); 959 alignSpan(thisPt, span2.fOtherT, other2, span.fOtherT, 960 other1, &oSpan2, alignedArray); 961 break; 962 } 963 } 964 skipExactMatches: 965 ; 966 } 967 ++index; 968 } 969 } 970 debugValidate(); 971 } 972 973 void SkOpSegment::alignSpan(const SkPoint& newPt, double newT, const SkOpSegment* other, 974 double otherT, const SkOpSegment* other2, SkOpSpan* oSpan, 975 SkTDArray<AlignedSpan>* alignedArray) { 976 AlignedSpan* aligned = alignedArray->append(); 977 aligned->fOldPt = oSpan->fPt; 978 aligned->fPt = newPt; 979 aligned->fOldT = oSpan->fT; 980 aligned->fT = newT; 981 aligned->fSegment = this; // OPTIMIZE: may be unused, can remove 982 aligned->fOther1 = other; 983 aligned->fOther2 = other2; 984 SkASSERT(SkDPoint::RoughlyEqual(oSpan->fPt, newPt)); 985 oSpan->fPt = newPt; 986 // SkASSERT(way_roughly_equal(oSpan->fT, newT)); 987 oSpan->fT = newT; 988 // SkASSERT(way_roughly_equal(oSpan->fOtherT, otherT)); 989 oSpan->fOtherT = otherT; 990 } 991 992 bool SkOpSegment::alignSpan(int index, double thisT, const SkPoint& thisPt) { 993 bool aligned = false; 994 SkOpSpan* span = &fTs[index]; 995 SkOpSegment* other = span->fOther; 996 int oIndex = span->fOtherIndex; 997 SkOpSpan* oSpan = &other->fTs[oIndex]; 998 if (span->fT != thisT) { 999 span->fT = thisT; 1000 oSpan->fOtherT = thisT; 1001 aligned = true; 1002 } 1003 if (span->fPt != thisPt) { 1004 span->fPt = thisPt; 1005 oSpan->fPt = thisPt; 1006 aligned = true; 1007 } 1008 double oT = oSpan->fT; 1009 if (oT == 0) { 1010 return aligned; 1011 } 1012 int oStart = other->nextSpan(oIndex, -1) + 1; 1013 oSpan = &other->fTs[oStart]; 1014 int otherIndex = oStart; 1015 if (oT == 1) { 1016 if (aligned) { 1017 while (oSpan->fPt == thisPt && oSpan->fT != 1) { 1018 oSpan->fTiny = true; 1019 ++oSpan; 1020 } 1021 } 1022 return aligned; 1023 } 1024 oT = oSpan->fT; 1025 int oEnd = other->nextSpan(oIndex, 1); 1026 bool oAligned = false; 1027 if (oSpan->fPt != thisPt) { 1028 oAligned |= other->alignSpan(oStart, oT, thisPt); 1029 } 1030 while (++otherIndex < oEnd) { 1031 SkOpSpan* oNextSpan = &other->fTs[otherIndex]; 1032 if (oNextSpan->fT != oT || oNextSpan->fPt != thisPt) { 1033 oAligned |= other->alignSpan(otherIndex, oT, thisPt); 1034 } 1035 } 1036 if (oAligned) { 1037 other->alignSpanState(oStart, oEnd); 1038 } 1039 return aligned; 1040 } 1041 1042 void SkOpSegment::alignSpanState(int start, int end) { 1043 SkOpSpan* lastSpan = &fTs[--end]; 1044 bool allSmall = lastSpan->fSmall; 1045 bool allTiny = lastSpan->fTiny; 1046 bool allDone = lastSpan->fDone; 1047 SkDEBUGCODE(int winding = lastSpan->fWindValue); 1048 SkDEBUGCODE(int oppWinding = lastSpan->fOppValue); 1049 int index = start; 1050 while (index < end) { 1051 SkOpSpan* span = &fTs[index]; 1052 span->fSmall = allSmall; 1053 span->fTiny = allTiny; 1054 if (span->fDone != allDone) { 1055 span->fDone = allDone; 1056 fDoneSpans += allDone ? 1 : -1; 1057 } 1058 SkASSERT(span->fWindValue == winding); 1059 SkASSERT(span->fOppValue == oppWinding); 1060 ++index; 1061 } 1062 } 1063 1064 void SkOpSegment::blindCancel(const SkCoincidence& coincidence, SkOpSegment* other) { 1065 bool binary = fOperand != other->fOperand; 1066 int index = 0; 1067 int last = this->count(); 1068 do { 1069 SkOpSpan& span = this->fTs[--last]; 1070 if (span.fT != 1 && !span.fSmall) { 1071 break; 1072 } 1073 span.fCoincident = true; 1074 } while (true); 1075 int oIndex = other->count(); 1076 do { 1077 SkOpSpan& oSpan = other->fTs[--oIndex]; 1078 if (oSpan.fT != 1 && !oSpan.fSmall) { 1079 break; 1080 } 1081 oSpan.fCoincident = true; 1082 } while (true); 1083 do { 1084 SkOpSpan* test = &this->fTs[index]; 1085 int baseWind = test->fWindValue; 1086 int baseOpp = test->fOppValue; 1087 int endIndex = index; 1088 while (++endIndex <= last) { 1089 SkOpSpan* endSpan = &this->fTs[endIndex]; 1090 SkASSERT(endSpan->fT < 1); 1091 if (endSpan->fWindValue != baseWind || endSpan->fOppValue != baseOpp) { 1092 break; 1093 } 1094 endSpan->fCoincident = true; 1095 } 1096 SkOpSpan* oTest = &other->fTs[oIndex]; 1097 int oBaseWind = oTest->fWindValue; 1098 int oBaseOpp = oTest->fOppValue; 1099 int oStartIndex = oIndex; 1100 while (--oStartIndex >= 0) { 1101 SkOpSpan* oStartSpan = &other->fTs[oStartIndex]; 1102 if (oStartSpan->fWindValue != oBaseWind || oStartSpan->fOppValue != oBaseOpp) { 1103 break; 1104 } 1105 oStartSpan->fCoincident = true; 1106 } 1107 bool decrement = baseWind && oBaseWind; 1108 bool bigger = baseWind >= oBaseWind; 1109 do { 1110 SkASSERT(test->fT < 1); 1111 if (decrement) { 1112 if (binary && bigger) { 1113 test->fOppValue--; 1114 } else { 1115 decrementSpan(test); 1116 } 1117 } 1118 test->fCoincident = true; 1119 test = &fTs[++index]; 1120 } while (index < endIndex); 1121 do { 1122 SkASSERT(oTest->fT < 1); 1123 if (decrement) { 1124 if (binary && !bigger) { 1125 oTest->fOppValue--; 1126 } else { 1127 other->decrementSpan(oTest); 1128 } 1129 } 1130 oTest->fCoincident = true; 1131 oTest = &other->fTs[--oIndex]; 1132 } while (oIndex > oStartIndex); 1133 } while (index <= last && oIndex >= 0); 1134 SkASSERT(index > last); 1135 SkASSERT(oIndex < 0); 1136 } 1137 1138 void SkOpSegment::blindCoincident(const SkCoincidence& coincidence, SkOpSegment* other) { 1139 bool binary = fOperand != other->fOperand; 1140 int index = 0; 1141 int last = this->count(); 1142 do { 1143 SkOpSpan& span = this->fTs[--last]; 1144 if (span.fT != 1 && !span.fSmall) { 1145 break; 1146 } 1147 span.fCoincident = true; 1148 } while (true); 1149 int oIndex = 0; 1150 int oLast = other->count(); 1151 do { 1152 SkOpSpan& oSpan = other->fTs[--oLast]; 1153 if (oSpan.fT != 1 && !oSpan.fSmall) { 1154 break; 1155 } 1156 oSpan.fCoincident = true; 1157 } while (true); 1158 do { 1159 SkOpSpan* test = &this->fTs[index]; 1160 int baseWind = test->fWindValue; 1161 int baseOpp = test->fOppValue; 1162 int endIndex = index; 1163 SkOpSpan* endSpan; 1164 while (++endIndex <= last) { 1165 endSpan = &this->fTs[endIndex]; 1166 SkASSERT(endSpan->fT < 1); 1167 if (endSpan->fWindValue != baseWind || endSpan->fOppValue != baseOpp) { 1168 break; 1169 } 1170 endSpan->fCoincident = true; 1171 } 1172 SkOpSpan* oTest = &other->fTs[oIndex]; 1173 int oBaseWind = oTest->fWindValue; 1174 int oBaseOpp = oTest->fOppValue; 1175 int oEndIndex = oIndex; 1176 SkOpSpan* oEndSpan; 1177 while (++oEndIndex <= oLast) { 1178 oEndSpan = &this->fTs[oEndIndex]; 1179 SkASSERT(oEndSpan->fT < 1); 1180 if (oEndSpan->fWindValue != oBaseWind || oEndSpan->fOppValue != oBaseOpp) { 1181 break; 1182 } 1183 oEndSpan->fCoincident = true; 1184 } 1185 // consolidate the winding count even if done 1186 if ((test->fWindValue || test->fOppValue) && (oTest->fWindValue || oTest->fOppValue)) { 1187 if (!binary || test->fWindValue + oTest->fOppValue >= 0) { 1188 bumpCoincidentBlind(binary, index, endIndex); 1189 other->bumpCoincidentOBlind(oIndex, oEndIndex); 1190 } else { 1191 other->bumpCoincidentBlind(binary, oIndex, oEndIndex); 1192 bumpCoincidentOBlind(index, endIndex); 1193 } 1194 } 1195 index = endIndex; 1196 oIndex = oEndIndex; 1197 } while (index <= last && oIndex <= oLast); 1198 SkASSERT(index > last); 1199 SkASSERT(oIndex > oLast); 1200 } 1201 1202 void SkOpSegment::bumpCoincidentBlind(bool binary, int index, int endIndex) { 1203 const SkOpSpan& oTest = fTs[index]; 1204 int oWindValue = oTest.fWindValue; 1205 int oOppValue = oTest.fOppValue; 1206 if (binary) { 1207 SkTSwap<int>(oWindValue, oOppValue); 1208 } 1209 do { 1210 (void) bumpSpan(&fTs[index], oWindValue, oOppValue); 1211 } while (++index < endIndex); 1212 } 1213 1214 void SkOpSegment::bumpCoincidentThis(const SkOpSpan& oTest, bool binary, int* indexPtr, 1215 SkTArray<SkPoint, true>* outsideTs) { 1216 int index = *indexPtr; 1217 int oWindValue = oTest.fWindValue; 1218 int oOppValue = oTest.fOppValue; 1219 if (binary) { 1220 SkTSwap<int>(oWindValue, oOppValue); 1221 } 1222 SkOpSpan* const test = &fTs[index]; 1223 SkOpSpan* end = test; 1224 const SkPoint& oStartPt = oTest.fPt; 1225 do { 1226 if (bumpSpan(end, oWindValue, oOppValue)) { 1227 TrackOutside(outsideTs, oStartPt); 1228 } 1229 end = &fTs[++index]; 1230 } while ((end->fPt == test->fPt || precisely_equal(end->fT, test->fT)) && end->fT < 1); 1231 *indexPtr = index; 1232 } 1233 1234 void SkOpSegment::bumpCoincidentOBlind(int index, int endIndex) { 1235 do { 1236 zeroSpan(&fTs[index]); 1237 } while (++index < endIndex); 1238 } 1239 1240 // because of the order in which coincidences are resolved, this and other 1241 // may not have the same intermediate points. Compute the corresponding 1242 // intermediate T values (using this as the master, other as the follower) 1243 // and walk other conditionally -- hoping that it catches up in the end 1244 void SkOpSegment::bumpCoincidentOther(const SkOpSpan& test, int* oIndexPtr, 1245 SkTArray<SkPoint, true>* oOutsidePts) { 1246 int oIndex = *oIndexPtr; 1247 SkOpSpan* const oTest = &fTs[oIndex]; 1248 SkOpSpan* oEnd = oTest; 1249 const SkPoint& oStartPt = oTest->fPt; 1250 double oStartT = oTest->fT; 1251 #if 0 // FIXME : figure out what disabling this breaks 1252 const SkPoint& startPt = test.fPt; 1253 // this is always true since oEnd == oTest && oStartPt == oTest->fPt -- find proper condition 1254 if (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) { 1255 TrackOutside(oOutsidePts, startPt); 1256 } 1257 #endif 1258 while (oStartPt == oEnd->fPt || precisely_equal(oStartT, oEnd->fT)) { 1259 zeroSpan(oEnd); 1260 oEnd = &fTs[++oIndex]; 1261 } 1262 *oIndexPtr = oIndex; 1263 } 1264 1265 // FIXME: need to test this case: 1266 // contourA has two segments that are coincident 1267 // contourB has two segments that are coincident in the same place 1268 // each ends up with +2/0 pairs for winding count 1269 // since logic below doesn't transfer count (only increments/decrements) can this be 1270 // resolved to +4/0 ? 1271 1272 // set spans from start to end to increment the greater by one and decrement 1273 // the lesser 1274 bool SkOpSegment::addTCoincident(const SkPoint& startPt, const SkPoint& endPt, double endT, 1275 SkOpSegment* other) { 1276 bool binary = fOperand != other->fOperand; 1277 int index = 0; 1278 while (startPt != fTs[index].fPt) { 1279 SkASSERT(index < fTs.count()); 1280 ++index; 1281 } 1282 double startT = fTs[index].fT; 1283 while (index > 0 && precisely_equal(fTs[index - 1].fT, startT)) { 1284 --index; 1285 } 1286 int oIndex = 0; 1287 while (startPt != other->fTs[oIndex].fPt) { 1288 SkASSERT(oIndex < other->fTs.count()); 1289 ++oIndex; 1290 } 1291 double oStartT = other->fTs[oIndex].fT; 1292 while (oIndex > 0 && precisely_equal(other->fTs[oIndex - 1].fT, oStartT)) { 1293 --oIndex; 1294 } 1295 SkSTArray<kOutsideTrackedTCount, SkPoint, true> outsidePts; 1296 SkSTArray<kOutsideTrackedTCount, SkPoint, true> oOutsidePts; 1297 SkOpSpan* test = &fTs[index]; 1298 const SkPoint* testPt = &test->fPt; 1299 double testT = test->fT; 1300 SkOpSpan* oTest = &other->fTs[oIndex]; 1301 const SkPoint* oTestPt = &oTest->fPt; 1302 // paths with extreme data will fail this test and eject out of pathops altogether later on 1303 // SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); 1304 do { 1305 SkASSERT(test->fT < 1); 1306 if (oTest->fT == 1) { 1307 // paths with extreme data may be so mismatched that we fail here 1308 return false; 1309 } 1310 1311 // consolidate the winding count even if done 1312 if ((test->fWindValue == 0 && test->fOppValue == 0) 1313 || (oTest->fWindValue == 0 && oTest->fOppValue == 0)) { 1314 SkDEBUGCODE(int firstWind = test->fWindValue); 1315 SkDEBUGCODE(int firstOpp = test->fOppValue); 1316 do { 1317 SkASSERT(firstWind == fTs[index].fWindValue); 1318 SkASSERT(firstOpp == fTs[index].fOppValue); 1319 ++index; 1320 SkASSERT(index < fTs.count()); 1321 } while (*testPt == fTs[index].fPt); 1322 SkDEBUGCODE(firstWind = oTest->fWindValue); 1323 SkDEBUGCODE(firstOpp = oTest->fOppValue); 1324 do { 1325 SkASSERT(firstWind == other->fTs[oIndex].fWindValue); 1326 SkASSERT(firstOpp == other->fTs[oIndex].fOppValue); 1327 ++oIndex; 1328 SkASSERT(oIndex < other->fTs.count()); 1329 } while (*oTestPt == other->fTs[oIndex].fPt); 1330 } else { 1331 if (!binary || test->fWindValue + oTest->fOppValue >= 0) { 1332 bumpCoincidentThis(*oTest, binary, &index, &outsidePts); 1333 other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts); 1334 } else { 1335 other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts); 1336 bumpCoincidentOther(*oTest, &index, &outsidePts); 1337 } 1338 } 1339 test = &fTs[index]; 1340 testPt = &test->fPt; 1341 testT = test->fT; 1342 oTest = &other->fTs[oIndex]; 1343 oTestPt = &oTest->fPt; 1344 if (endPt == *testPt || precisely_equal(endT, testT)) { 1345 break; 1346 } 1347 // SkASSERT(AlmostEqualUlps(*testPt, *oTestPt)); 1348 } while (endPt != *oTestPt); 1349 // in rare cases, one may have ended before the other 1350 if (endPt != *testPt && !precisely_equal(endT, testT)) { 1351 int lastWind = test[-1].fWindValue; 1352 int lastOpp = test[-1].fOppValue; 1353 bool zero = lastWind == 0 && lastOpp == 0; 1354 do { 1355 if (test->fWindValue || test->fOppValue) { 1356 test->fWindValue = lastWind; 1357 test->fOppValue = lastOpp; 1358 if (zero) { 1359 test->fDone = true; 1360 ++fDoneSpans; 1361 } 1362 } 1363 test = &fTs[++index]; 1364 testPt = &test->fPt; 1365 } while (endPt != *testPt); 1366 } 1367 if (endPt != *oTestPt) { 1368 // look ahead to see if zeroing more spans will allows us to catch up 1369 int oPeekIndex = oIndex; 1370 bool success = true; 1371 SkOpSpan* oPeek; 1372 int oCount = other->count(); 1373 do { 1374 oPeek = &other->fTs[oPeekIndex]; 1375 if (++oPeekIndex == oCount) { 1376 success = false; 1377 break; 1378 } 1379 } while (endPt != oPeek->fPt); 1380 if (success) { 1381 // make sure the matching point completes the coincidence span 1382 success = false; 1383 do { 1384 if (oPeek->fOther == this) { 1385 success = true; 1386 break; 1387 } 1388 if (++oPeekIndex == oCount) { 1389 break; 1390 } 1391 oPeek = &other->fTs[oPeekIndex]; 1392 } while (endPt == oPeek->fPt); 1393 } 1394 if (success) { 1395 do { 1396 if (!binary || test->fWindValue + oTest->fOppValue >= 0) { 1397 other->bumpCoincidentOther(*test, &oIndex, &oOutsidePts); 1398 } else { 1399 other->bumpCoincidentThis(*test, binary, &oIndex, &oOutsidePts); 1400 } 1401 oTest = &other->fTs[oIndex]; 1402 oTestPt = &oTest->fPt; 1403 } while (endPt != *oTestPt); 1404 } 1405 } 1406 int outCount = outsidePts.count(); 1407 if (!done() && outCount) { 1408 addCoinOutsides(outsidePts[0], endPt, other); 1409 } 1410 if (!other->done() && oOutsidePts.count()) { 1411 other->addCoinOutsides(oOutsidePts[0], endPt, this); 1412 } 1413 setCoincidentRange(startPt, endPt, other); 1414 other->setCoincidentRange(startPt, endPt, this); 1415 return true; 1416 } 1417 1418 // FIXME: this doesn't prevent the same span from being added twice 1419 // fix in caller, SkASSERT here? 1420 // FIXME: this may erroneously reject adds for cubic loops 1421 const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind, 1422 const SkPoint& pt, const SkPoint& pt2) { 1423 int tCount = fTs.count(); 1424 for (int tIndex = 0; tIndex < tCount; ++tIndex) { 1425 const SkOpSpan& span = fTs[tIndex]; 1426 if (!approximately_negative(span.fT - t)) { 1427 break; 1428 } 1429 if (span.fOther == other) { 1430 bool tsMatch = approximately_equal(span.fT, t); 1431 bool otherTsMatch = approximately_equal(span.fOtherT, otherT); 1432 // FIXME: add cubic loop detecting logic here 1433 // if fLoop bit is set on span, that could be enough if addOtherT copies the bit 1434 // or if a new bit is added ala fOtherLoop 1435 if (tsMatch || otherTsMatch) { 1436 #if DEBUG_ADD_T_PAIR 1437 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n", 1438 __FUNCTION__, fID, t, other->fID, otherT); 1439 #endif 1440 return NULL; 1441 } 1442 } 1443 } 1444 int oCount = other->count(); 1445 for (int oIndex = 0; oIndex < oCount; ++oIndex) { 1446 const SkOpSpan& oSpan = other->span(oIndex); 1447 if (!approximately_negative(oSpan.fT - otherT)) { 1448 break; 1449 } 1450 if (oSpan.fOther == this) { 1451 bool otherTsMatch = approximately_equal(oSpan.fT, otherT); 1452 bool tsMatch = approximately_equal(oSpan.fOtherT, t); 1453 if (otherTsMatch || tsMatch) { 1454 #if DEBUG_ADD_T_PAIR 1455 SkDebugf("%s addTPair other duplicate this=%d %1.9g other=%d %1.9g\n", 1456 __FUNCTION__, fID, t, other->fID, otherT); 1457 #endif 1458 return NULL; 1459 } 1460 } 1461 } 1462 #if DEBUG_ADD_T_PAIR 1463 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n", 1464 __FUNCTION__, fID, t, other->fID, otherT); 1465 #endif 1466 SkASSERT(other != this); 1467 int insertedAt = addT(other, pt, t); 1468 int otherInsertedAt = other->addT(this, pt2, otherT); 1469 addOtherT(insertedAt, otherT, otherInsertedAt); 1470 other->addOtherT(otherInsertedAt, t, insertedAt); 1471 matchWindingValue(insertedAt, t, borrowWind); 1472 other->matchWindingValue(otherInsertedAt, otherT, borrowWind); 1473 SkOpSpan& span = this->fTs[insertedAt]; 1474 if (pt != pt2) { 1475 span.fNear = true; 1476 SkOpSpan& oSpan = other->fTs[otherInsertedAt]; 1477 oSpan.fNear = true; 1478 } 1479 return &span; 1480 } 1481 1482 const SkOpSpan* SkOpSegment::addTPair(double t, SkOpSegment* other, double otherT, bool borrowWind, 1483 const SkPoint& pt) { 1484 return addTPair(t, other, otherT, borrowWind, pt, pt); 1485 } 1486 1487 bool SkOpSegment::betweenPoints(double midT, const SkPoint& pt1, const SkPoint& pt2) const { 1488 const SkPoint midPt = ptAtT(midT); 1489 SkPathOpsBounds bounds; 1490 bounds.set(pt1.fX, pt1.fY, pt2.fX, pt2.fY); 1491 bounds.sort(); 1492 return bounds.almostContains(midPt); 1493 } 1494 1495 bool SkOpSegment::betweenTs(int lesser, double testT, int greater) const { 1496 if (lesser > greater) { 1497 SkTSwap<int>(lesser, greater); 1498 } 1499 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT); 1500 } 1501 1502 // in extreme cases (like the buffer overflow test) return false to abort 1503 // for now, if one t value represents two different points, then the values are too extreme 1504 // to generate meaningful results 1505 bool SkOpSegment::calcAngles() { 1506 int spanCount = fTs.count(); 1507 if (spanCount <= 2) { 1508 return spanCount == 2; 1509 } 1510 int index = 1; 1511 const SkOpSpan* firstSpan = &fTs[index]; 1512 int activePrior = checkSetAngle(0); 1513 const SkOpSpan* span = &fTs[0]; 1514 if (firstSpan->fT == 0 || span->fTiny || span->fOtherT != 1 || span->fOther->multipleEnds()) { 1515 index = findStartSpan(0); // curve start intersects 1516 if (fTs[index].fT == 0) { 1517 return false; 1518 } 1519 SkASSERT(index > 0); 1520 if (activePrior >= 0) { 1521 addStartSpan(index); 1522 } 1523 } 1524 bool addEnd; 1525 int endIndex = spanCount - 1; 1526 span = &fTs[endIndex - 1]; 1527 if ((addEnd = span->fT == 1 || span->fTiny)) { // if curve end intersects 1528 endIndex = findEndSpan(endIndex); 1529 SkASSERT(endIndex > 0); 1530 } else { 1531 addEnd = fTs[endIndex].fOtherT != 0 || fTs[endIndex].fOther->multipleStarts(); 1532 } 1533 SkASSERT(endIndex >= index); 1534 int prior = 0; 1535 while (index < endIndex) { 1536 const SkOpSpan& fromSpan = fTs[index]; // for each intermediate intersection 1537 const SkOpSpan* lastSpan; 1538 span = &fromSpan; 1539 int start = index; 1540 do { 1541 lastSpan = span; 1542 span = &fTs[++index]; 1543 SkASSERT(index < spanCount); 1544 if (!precisely_negative(span->fT - lastSpan->fT) && !lastSpan->fTiny) { 1545 break; 1546 } 1547 if (!SkDPoint::ApproximatelyEqual(lastSpan->fPt, span->fPt)) { 1548 return false; 1549 } 1550 } while (true); 1551 SkOpAngle* angle = NULL; 1552 SkOpAngle* priorAngle; 1553 if (activePrior >= 0) { 1554 int pActive = firstActive(prior); 1555 SkASSERT(pActive < start); 1556 priorAngle = &fAngles.push_back(); 1557 priorAngle->set(this, start, pActive); 1558 } 1559 int active = checkSetAngle(start); 1560 if (active >= 0) { 1561 SkASSERT(active < index); 1562 angle = &fAngles.push_back(); 1563 angle->set(this, active, index); 1564 } 1565 #if DEBUG_ANGLE 1566 debugCheckPointsEqualish(start, index); 1567 #endif 1568 prior = start; 1569 do { 1570 const SkOpSpan* startSpan = &fTs[start - 1]; 1571 if (!startSpan->fSmall || isCanceled(start - 1) || startSpan->fFromAngle 1572 || startSpan->fToAngle) { 1573 break; 1574 } 1575 --start; 1576 } while (start > 0); 1577 do { 1578 if (activePrior >= 0) { 1579 SkASSERT(fTs[start].fFromAngle == NULL); 1580 fTs[start].fFromAngle = priorAngle; 1581 } 1582 if (active >= 0) { 1583 SkASSERT(fTs[start].fToAngle == NULL); 1584 fTs[start].fToAngle = angle; 1585 } 1586 } while (++start < index); 1587 activePrior = active; 1588 } 1589 if (addEnd && activePrior >= 0) { 1590 addEndSpan(endIndex); 1591 } 1592 return true; 1593 } 1594 1595 int SkOpSegment::checkSetAngle(int tIndex) const { 1596 const SkOpSpan* span = &fTs[tIndex]; 1597 while (span->fTiny /* || span->fSmall */) { 1598 span = &fTs[++tIndex]; 1599 } 1600 return isCanceled(tIndex) ? -1 : tIndex; 1601 } 1602 1603 // at this point, the span is already ordered, or unorderable 1604 int SkOpSegment::computeSum(int startIndex, int endIndex, SkOpAngle::IncludeType includeType) { 1605 SkASSERT(includeType != SkOpAngle::kUnaryXor); 1606 SkOpAngle* firstAngle = spanToAngle(endIndex, startIndex); 1607 if (NULL == firstAngle || NULL == firstAngle->next()) { 1608 return SK_NaN32; 1609 } 1610 // if all angles have a computed winding, 1611 // or if no adjacent angles are orderable, 1612 // or if adjacent orderable angles have no computed winding, 1613 // there's nothing to do 1614 // if two orderable angles are adjacent, and both are next to orderable angles, 1615 // and one has winding computed, transfer to the other 1616 SkOpAngle* baseAngle = NULL; 1617 bool tryReverse = false; 1618 // look for counterclockwise transfers 1619 SkOpAngle* angle = firstAngle->previous(); 1620 SkOpAngle* next = angle->next(); 1621 firstAngle = next; 1622 do { 1623 SkOpAngle* prior = angle; 1624 angle = next; 1625 next = angle->next(); 1626 SkASSERT(prior->next() == angle); 1627 SkASSERT(angle->next() == next); 1628 if (prior->unorderable() || angle->unorderable() || next->unorderable()) { 1629 baseAngle = NULL; 1630 continue; 1631 } 1632 int testWinding = angle->segment()->windSum(angle); 1633 if (SK_MinS32 != testWinding) { 1634 baseAngle = angle; 1635 tryReverse = true; 1636 continue; 1637 } 1638 if (baseAngle) { 1639 ComputeOneSum(baseAngle, angle, includeType); 1640 baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angle : NULL; 1641 } 1642 } while (next != firstAngle); 1643 if (baseAngle && SK_MinS32 == firstAngle->segment()->windSum(firstAngle)) { 1644 firstAngle = baseAngle; 1645 tryReverse = true; 1646 } 1647 if (tryReverse) { 1648 baseAngle = NULL; 1649 SkOpAngle* prior = firstAngle; 1650 do { 1651 angle = prior; 1652 prior = angle->previous(); 1653 SkASSERT(prior->next() == angle); 1654 next = angle->next(); 1655 if (prior->unorderable() || angle->unorderable() || next->unorderable()) { 1656 baseAngle = NULL; 1657 continue; 1658 } 1659 int testWinding = angle->segment()->windSum(angle); 1660 if (SK_MinS32 != testWinding) { 1661 baseAngle = angle; 1662 continue; 1663 } 1664 if (baseAngle) { 1665 ComputeOneSumReverse(baseAngle, angle, includeType); 1666 baseAngle = SK_MinS32 != angle->segment()->windSum(angle) ? angle : NULL; 1667 } 1668 } while (prior != firstAngle); 1669 } 1670 int minIndex = SkMin32(startIndex, endIndex); 1671 return windSum(minIndex); 1672 } 1673 1674 void SkOpSegment::ComputeOneSum(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, 1675 SkOpAngle::IncludeType includeType) { 1676 const SkOpSegment* baseSegment = baseAngle->segment(); 1677 int sumMiWinding = baseSegment->updateWindingReverse(baseAngle); 1678 int sumSuWinding; 1679 bool binary = includeType >= SkOpAngle::kBinarySingle; 1680 if (binary) { 1681 sumSuWinding = baseSegment->updateOppWindingReverse(baseAngle); 1682 if (baseSegment->operand()) { 1683 SkTSwap<int>(sumMiWinding, sumSuWinding); 1684 } 1685 } 1686 SkOpSegment* nextSegment = nextAngle->segment(); 1687 int maxWinding, sumWinding; 1688 SkOpSpan* last; 1689 if (binary) { 1690 int oppMaxWinding, oppSumWinding; 1691 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding, 1692 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); 1693 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding, 1694 nextAngle); 1695 } else { 1696 nextSegment->setUpWindings(nextAngle->start(), nextAngle->end(), &sumMiWinding, 1697 &maxWinding, &sumWinding); 1698 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle); 1699 } 1700 nextAngle->setLastMarked(last); 1701 } 1702 1703 void SkOpSegment::ComputeOneSumReverse(const SkOpAngle* baseAngle, SkOpAngle* nextAngle, 1704 SkOpAngle::IncludeType includeType) { 1705 const SkOpSegment* baseSegment = baseAngle->segment(); 1706 int sumMiWinding = baseSegment->updateWinding(baseAngle); 1707 int sumSuWinding; 1708 bool binary = includeType >= SkOpAngle::kBinarySingle; 1709 if (binary) { 1710 sumSuWinding = baseSegment->updateOppWinding(baseAngle); 1711 if (baseSegment->operand()) { 1712 SkTSwap<int>(sumMiWinding, sumSuWinding); 1713 } 1714 } 1715 SkOpSegment* nextSegment = nextAngle->segment(); 1716 int maxWinding, sumWinding; 1717 SkOpSpan* last; 1718 if (binary) { 1719 int oppMaxWinding, oppSumWinding; 1720 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding, 1721 &sumSuWinding, &maxWinding, &sumWinding, &oppMaxWinding, &oppSumWinding); 1722 last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, oppSumWinding, 1723 nextAngle); 1724 } else { 1725 nextSegment->setUpWindings(nextAngle->end(), nextAngle->start(), &sumMiWinding, 1726 &maxWinding, &sumWinding); 1727 last = nextSegment->markAngle(maxWinding, sumWinding, nextAngle); 1728 } 1729 nextAngle->setLastMarked(last); 1730 } 1731 1732 bool SkOpSegment::containsPt(const SkPoint& pt, int index, int endIndex) const { 1733 int step = index < endIndex ? 1 : -1; 1734 do { 1735 const SkOpSpan& span = this->span(index); 1736 if (span.fPt == pt) { 1737 const SkOpSpan& endSpan = this->span(endIndex); 1738 return span.fT == endSpan.fT && pt != endSpan.fPt; 1739 } 1740 index += step; 1741 } while (index != endIndex); 1742 return false; 1743 } 1744 1745 bool SkOpSegment::containsT(double t, const SkOpSegment* other, double otherT) const { 1746 int count = this->count(); 1747 for (int index = 0; index < count; ++index) { 1748 const SkOpSpan& span = fTs[index]; 1749 if (t < span.fT) { 1750 return false; 1751 } 1752 if (t == span.fT) { 1753 if (other != span.fOther) { 1754 continue; 1755 } 1756 if (other->fVerb != SkPath::kCubic_Verb) { 1757 return true; 1758 } 1759 if (!other->fLoop) { 1760 return true; 1761 } 1762 double otherMidT = (otherT + span.fOtherT) / 2; 1763 SkPoint otherPt = other->ptAtT(otherMidT); 1764 return SkDPoint::ApproximatelyEqual(span.fPt, otherPt); 1765 } 1766 } 1767 return false; 1768 } 1769 1770 int SkOpSegment::crossedSpanY(const SkPoint& basePt, SkScalar* bestY, double* hitT, 1771 bool* hitSomething, double mid, bool opp, bool current) const { 1772 SkScalar bottom = fBounds.fBottom; 1773 int bestTIndex = -1; 1774 if (bottom <= *bestY) { 1775 return bestTIndex; 1776 } 1777 SkScalar top = fBounds.fTop; 1778 if (top >= basePt.fY) { 1779 return bestTIndex; 1780 } 1781 if (fBounds.fLeft > basePt.fX) { 1782 return bestTIndex; 1783 } 1784 if (fBounds.fRight < basePt.fX) { 1785 return bestTIndex; 1786 } 1787 if (fBounds.fLeft == fBounds.fRight) { 1788 // if vertical, and directly above test point, wait for another one 1789 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex; 1790 } 1791 // intersect ray starting at basePt with edge 1792 SkIntersections intersections; 1793 // OPTIMIZE: use specialty function that intersects ray with curve, 1794 // returning t values only for curve (we don't care about t on ray) 1795 intersections.allowNear(false); 1796 int pts = (intersections.*CurveVertical[SkPathOpsVerbToPoints(fVerb)]) 1797 (fPts, top, bottom, basePt.fX, false); 1798 if (pts == 0 || (current && pts == 1)) { 1799 return bestTIndex; 1800 } 1801 if (current) { 1802 SkASSERT(pts > 1); 1803 int closestIdx = 0; 1804 double closest = fabs(intersections[0][0] - mid); 1805 for (int idx = 1; idx < pts; ++idx) { 1806 double test = fabs(intersections[0][idx] - mid); 1807 if (closest > test) { 1808 closestIdx = idx; 1809 closest = test; 1810 } 1811 } 1812 intersections.quickRemoveOne(closestIdx, --pts); 1813 } 1814 double bestT = -1; 1815 for (int index = 0; index < pts; ++index) { 1816 double foundT = intersections[0][index]; 1817 if (approximately_less_than_zero(foundT) 1818 || approximately_greater_than_one(foundT)) { 1819 continue; 1820 } 1821 SkScalar testY = (*CurvePointAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fY; 1822 if (approximately_negative(testY - *bestY) 1823 || approximately_negative(basePt.fY - testY)) { 1824 continue; 1825 } 1826 if (pts > 1 && fVerb == SkPath::kLine_Verb) { 1827 return SK_MinS32; // if the intersection is edge on, wait for another one 1828 } 1829 if (fVerb > SkPath::kLine_Verb) { 1830 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, foundT).fX; 1831 if (approximately_zero(dx)) { 1832 return SK_MinS32; // hit vertical, wait for another one 1833 } 1834 } 1835 *bestY = testY; 1836 bestT = foundT; 1837 } 1838 if (bestT < 0) { 1839 return bestTIndex; 1840 } 1841 SkASSERT(bestT >= 0); 1842 SkASSERT(bestT <= 1); 1843 int start; 1844 int end = 0; 1845 do { 1846 start = end; 1847 end = nextSpan(start, 1); 1848 } while (fTs[end].fT < bestT); 1849 // FIXME: see next candidate for a better pattern to find the next start/end pair 1850 while (start + 1 < end && fTs[start].fDone) { 1851 ++start; 1852 } 1853 if (!isCanceled(start)) { 1854 *hitT = bestT; 1855 bestTIndex = start; 1856 *hitSomething = true; 1857 } 1858 return bestTIndex; 1859 } 1860 1861 bool SkOpSegment::decrementSpan(SkOpSpan* span) { 1862 SkASSERT(span->fWindValue > 0); 1863 if (--(span->fWindValue) == 0) { 1864 if (!span->fOppValue && !span->fDone) { 1865 span->fDone = true; 1866 ++fDoneSpans; 1867 return true; 1868 } 1869 } 1870 return false; 1871 } 1872 1873 bool SkOpSegment::bumpSpan(SkOpSpan* span, int windDelta, int oppDelta) { 1874 SkASSERT(!span->fDone || span->fTiny || span->fSmall); 1875 span->fWindValue += windDelta; 1876 SkASSERT(span->fWindValue >= 0); 1877 span->fOppValue += oppDelta; 1878 SkASSERT(span->fOppValue >= 0); 1879 if (fXor) { 1880 span->fWindValue &= 1; 1881 } 1882 if (fOppXor) { 1883 span->fOppValue &= 1; 1884 } 1885 if (!span->fWindValue && !span->fOppValue) { 1886 span->fDone = true; 1887 ++fDoneSpans; 1888 return true; 1889 } 1890 return false; 1891 } 1892 1893 const SkOpSpan& SkOpSegment::firstSpan(const SkOpSpan& thisSpan) const { 1894 const SkOpSpan* firstSpan = &thisSpan; // rewind to the start 1895 const SkOpSpan* beginSpan = fTs.begin(); 1896 const SkPoint& testPt = thisSpan.fPt; 1897 while (firstSpan > beginSpan && firstSpan[-1].fPt == testPt) { 1898 --firstSpan; 1899 } 1900 return *firstSpan; 1901 } 1902 1903 const SkOpSpan& SkOpSegment::lastSpan(const SkOpSpan& thisSpan) const { 1904 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be small 1905 const SkOpSpan* lastSpan = &thisSpan; // find the end 1906 const SkPoint& testPt = thisSpan.fPt; 1907 while (lastSpan < endSpan && lastSpan[1].fPt == testPt) { 1908 ++lastSpan; 1909 } 1910 return *lastSpan; 1911 } 1912 1913 // with a loop, the comparison is move involved 1914 // scan backwards and forwards to count all matching points 1915 // (verify that there are twp scans marked as loops) 1916 // compare that against 2 matching scans for loop plus other results 1917 bool SkOpSegment::calcLoopSpanCount(const SkOpSpan& thisSpan, int* smallCounts) { 1918 const SkOpSpan& firstSpan = this->firstSpan(thisSpan); // rewind to the start 1919 const SkOpSpan& lastSpan = this->lastSpan(thisSpan); // find the end 1920 double firstLoopT = -1, lastLoopT = -1; 1921 const SkOpSpan* testSpan = &firstSpan - 1; 1922 while (++testSpan <= &lastSpan) { 1923 if (testSpan->fLoop) { 1924 firstLoopT = testSpan->fT; 1925 break; 1926 } 1927 } 1928 testSpan = &lastSpan + 1; 1929 while (--testSpan >= &firstSpan) { 1930 if (testSpan->fLoop) { 1931 lastLoopT = testSpan->fT; 1932 break; 1933 } 1934 } 1935 SkASSERT((firstLoopT == -1) == (lastLoopT == -1)); 1936 if (firstLoopT == -1) { 1937 return false; 1938 } 1939 SkASSERT(firstLoopT < lastLoopT); 1940 testSpan = &firstSpan - 1; 1941 smallCounts[0] = smallCounts[1] = 0; 1942 while (++testSpan <= &lastSpan) { 1943 SkASSERT(approximately_equal(testSpan->fT, firstLoopT) + 1944 approximately_equal(testSpan->fT, lastLoopT) == 1); 1945 smallCounts[approximately_equal(testSpan->fT, lastLoopT)]++; 1946 } 1947 return true; 1948 } 1949 1950 double SkOpSegment::calcMissingTEnd(const SkOpSegment* ref, double loEnd, double min, double max, 1951 double hiEnd, const SkOpSegment* other, int thisStart) { 1952 if (max >= hiEnd) { 1953 return -1; 1954 } 1955 int end = findOtherT(hiEnd, ref); 1956 if (end < 0) { 1957 return -1; 1958 } 1959 double tHi = span(end).fT; 1960 double tLo, refLo; 1961 if (thisStart >= 0) { 1962 tLo = span(thisStart).fT; 1963 refLo = min; 1964 } else { 1965 int start1 = findOtherT(loEnd, ref); 1966 SkASSERT(start1 >= 0); 1967 tLo = span(start1).fT; 1968 refLo = loEnd; 1969 } 1970 double missingT = (max - refLo) / (hiEnd - refLo); 1971 missingT = tLo + missingT * (tHi - tLo); 1972 return missingT; 1973 } 1974 1975 double SkOpSegment::calcMissingTStart(const SkOpSegment* ref, double loEnd, double min, double max, 1976 double hiEnd, const SkOpSegment* other, int thisEnd) { 1977 if (min <= loEnd) { 1978 return -1; 1979 } 1980 int start = findOtherT(loEnd, ref); 1981 if (start < 0) { 1982 return -1; 1983 } 1984 double tLo = span(start).fT; 1985 double tHi, refHi; 1986 if (thisEnd >= 0) { 1987 tHi = span(thisEnd).fT; 1988 refHi = max; 1989 } else { 1990 int end1 = findOtherT(hiEnd, ref); 1991 if (end1 < 0) { 1992 return -1; 1993 } 1994 tHi = span(end1).fT; 1995 refHi = hiEnd; 1996 } 1997 double missingT = (min - loEnd) / (refHi - loEnd); 1998 missingT = tLo + missingT * (tHi - tLo); 1999 return missingT; 2000 } 2001 2002 // see if spans with two or more intersections have the same number on the other end 2003 void SkOpSegment::checkDuplicates() { 2004 debugValidate(); 2005 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; 2006 int index; 2007 int endIndex = 0; 2008 bool endFound; 2009 do { 2010 index = endIndex; 2011 endIndex = nextExactSpan(index, 1); 2012 if ((endFound = endIndex < 0)) { 2013 endIndex = count(); 2014 } 2015 int dupCount = endIndex - index; 2016 if (dupCount < 2) { 2017 continue; 2018 } 2019 do { 2020 const SkOpSpan* thisSpan = &fTs[index]; 2021 if (thisSpan->fNear) { 2022 continue; 2023 } 2024 SkOpSegment* other = thisSpan->fOther; 2025 int oIndex = thisSpan->fOtherIndex; 2026 int oStart = other->nextExactSpan(oIndex, -1) + 1; 2027 int oEnd = other->nextExactSpan(oIndex, 1); 2028 if (oEnd < 0) { 2029 oEnd = other->count(); 2030 } 2031 int oCount = oEnd - oStart; 2032 // force the other to match its t and this pt if not on an end point 2033 if (oCount != dupCount) { 2034 MissingSpan& missing = missingSpans.push_back(); 2035 missing.fOther = NULL; 2036 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing))); 2037 missing.fPt = thisSpan->fPt; 2038 const SkOpSpan& oSpan = other->span(oIndex); 2039 if (oCount > dupCount) { 2040 missing.fSegment = this; 2041 missing.fT = thisSpan->fT; 2042 other->checkLinks(&oSpan, &missingSpans); 2043 } else { 2044 missing.fSegment = other; 2045 missing.fT = oSpan.fT; 2046 checkLinks(thisSpan, &missingSpans); 2047 } 2048 if (!missingSpans.back().fOther) { 2049 missingSpans.pop_back(); 2050 } 2051 } 2052 } while (++index < endIndex); 2053 } while (!endFound); 2054 int missingCount = missingSpans.count(); 2055 if (missingCount == 0) { 2056 return; 2057 } 2058 SkSTArray<kMissingSpanCount, MissingSpan, true> missingCoincidence; 2059 for (index = 0; index < missingCount; ++index) { 2060 MissingSpan& missing = missingSpans[index]; 2061 SkOpSegment* missingOther = missing.fOther; 2062 if (missing.fSegment == missing.fOther) { 2063 continue; 2064 } 2065 #if 0 // FIXME: this eliminates spurious data from skpwww_argus_presse_fr_41 but breaks 2066 // skpwww_fashionscandal_com_94 -- calcAngles complains, but I don't understand why 2067 if (missing.fSegment->containsT(missing.fT, missing.fOther, missing.fOtherT)) { 2068 #if DEBUG_DUPLICATES 2069 SkDebugf("skip 1 id=%d t=%1.9g other=%d otherT=%1.9g\n", missing.fSegment->fID, 2070 missing.fT, missing.fOther->fID, missing.fOtherT); 2071 #endif 2072 continue; 2073 } 2074 if (missing.fOther->containsT(missing.fOtherT, missing.fSegment, missing.fT)) { 2075 #if DEBUG_DUPLICATES 2076 SkDebugf("skip 2 id=%d t=%1.9g other=%d otherT=%1.9g\n", missing.fOther->fID, 2077 missing.fOtherT, missing.fSegment->fID, missing.fT); 2078 #endif 2079 continue; 2080 } 2081 #endif 2082 // skip if adding would insert point into an existing coincindent span 2083 if (missing.fSegment->inCoincidentSpan(missing.fT, missingOther) 2084 && missingOther->inCoincidentSpan(missing.fOtherT, this)) { 2085 continue; 2086 } 2087 // skip if the created coincident spans are small 2088 if (missing.fSegment->coincidentSmall(missing.fPt, missing.fT, missingOther) 2089 && missingOther->coincidentSmall(missing.fPt, missing.fOtherT, missing.fSegment)) { 2090 continue; 2091 } 2092 const SkOpSpan* added = missing.fSegment->addTPair(missing.fT, missingOther, 2093 missing.fOtherT, false, missing.fPt); 2094 if (added && added->fSmall) { 2095 missing.fSegment->checkSmallCoincidence(*added, &missingCoincidence); 2096 } 2097 } 2098 for (index = 0; index < missingCount; ++index) { 2099 MissingSpan& missing = missingSpans[index]; 2100 missing.fSegment->fixOtherTIndex(); 2101 missing.fOther->fixOtherTIndex(); 2102 } 2103 for (index = 0; index < missingCoincidence.count(); ++index) { 2104 MissingSpan& missing = missingCoincidence[index]; 2105 missing.fSegment->fixOtherTIndex(); 2106 } 2107 debugValidate(); 2108 } 2109 2110 // look to see if the curve end intersects an intermediary that intersects the other 2111 void SkOpSegment::checkEnds() { 2112 debugValidate(); 2113 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; 2114 int count = fTs.count(); 2115 for (int index = 0; index < count; ++index) { 2116 const SkOpSpan& span = fTs[index]; 2117 double otherT = span.fOtherT; 2118 if (otherT != 0 && otherT != 1) { // only check ends 2119 continue; 2120 } 2121 const SkOpSegment* other = span.fOther; 2122 // peek start/last describe the range of spans that match the other t of this span 2123 int peekStart = span.fOtherIndex; 2124 while (--peekStart >= 0 && other->fTs[peekStart].fT == otherT) 2125 ; 2126 int otherCount = other->fTs.count(); 2127 int peekLast = span.fOtherIndex; 2128 while (++peekLast < otherCount && other->fTs[peekLast].fT == otherT) 2129 ; 2130 if (++peekStart == --peekLast) { // if there isn't a range, there's nothing to do 2131 continue; 2132 } 2133 // t start/last describe the range of spans that match the t of this span 2134 double t = span.fT; 2135 double tBottom = -1; 2136 int tStart = -1; 2137 int tLast = count; 2138 bool lastSmall = false; 2139 double afterT = t; 2140 for (int inner = 0; inner < count; ++inner) { 2141 double innerT = fTs[inner].fT; 2142 if (innerT <= t && innerT > tBottom) { 2143 if (innerT < t || !lastSmall) { 2144 tStart = inner - 1; 2145 } 2146 tBottom = innerT; 2147 } 2148 if (innerT > afterT) { 2149 if (t == afterT && lastSmall) { 2150 afterT = innerT; 2151 } else { 2152 tLast = inner; 2153 break; 2154 } 2155 } 2156 lastSmall = innerT <= t ? fTs[inner].fSmall : false; 2157 } 2158 for (int peekIndex = peekStart; peekIndex <= peekLast; ++peekIndex) { 2159 if (peekIndex == span.fOtherIndex) { // skip the other span pointed to by this span 2160 continue; 2161 } 2162 const SkOpSpan& peekSpan = other->fTs[peekIndex]; 2163 SkOpSegment* match = peekSpan.fOther; 2164 if (match->done()) { 2165 continue; // if the edge has already been eaten (likely coincidence), ignore it 2166 } 2167 const double matchT = peekSpan.fOtherT; 2168 // see if any of the spans match the other spans 2169 for (int tIndex = tStart + 1; tIndex < tLast; ++tIndex) { 2170 const SkOpSpan& tSpan = fTs[tIndex]; 2171 if (tSpan.fOther == match) { 2172 if (tSpan.fOtherT == matchT) { 2173 goto nextPeekIndex; 2174 } 2175 double midT = (tSpan.fOtherT + matchT) / 2; 2176 if (match->betweenPoints(midT, tSpan.fPt, peekSpan.fPt)) { 2177 goto nextPeekIndex; 2178 } 2179 } 2180 } 2181 if (missingSpans.count() > 0) { 2182 const MissingSpan& lastMissing = missingSpans.back(); 2183 if (lastMissing.fT == t 2184 && lastMissing.fOther == match 2185 && lastMissing.fOtherT == matchT) { 2186 SkASSERT(lastMissing.fPt == peekSpan.fPt); 2187 continue; 2188 } 2189 } 2190 #if DEBUG_CHECK_ENDS 2191 SkDebugf("%s id=%d missing t=%1.9g other=%d otherT=%1.9g pt=(%1.9g,%1.9g)\n", 2192 __FUNCTION__, fID, t, match->fID, matchT, peekSpan.fPt.fX, peekSpan.fPt.fY); 2193 #endif 2194 // this segment is missing a entry that the other contains 2195 // remember so we can add the missing one and recompute the indices 2196 { 2197 MissingSpan& missing = missingSpans.push_back(); 2198 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing))); 2199 missing.fT = t; 2200 SkASSERT(this != match); 2201 missing.fOther = match; 2202 missing.fOtherT = matchT; 2203 missing.fPt = peekSpan.fPt; 2204 } 2205 break; 2206 nextPeekIndex: 2207 ; 2208 } 2209 } 2210 if (missingSpans.count() == 0) { 2211 debugValidate(); 2212 return; 2213 } 2214 debugValidate(); 2215 int missingCount = missingSpans.count(); 2216 for (int index = 0; index < missingCount; ++index) { 2217 MissingSpan& missing = missingSpans[index]; 2218 if (this != missing.fOther) { 2219 addTPair(missing.fT, missing.fOther, missing.fOtherT, false, missing.fPt); 2220 } 2221 } 2222 fixOtherTIndex(); 2223 // OPTIMIZATION: this may fix indices more than once. Build an array of unique segments to 2224 // avoid this 2225 for (int index = 0; index < missingCount; ++index) { 2226 missingSpans[index].fOther->fixOtherTIndex(); 2227 } 2228 debugValidate(); 2229 } 2230 2231 void SkOpSegment::checkLinks(const SkOpSpan* base, 2232 SkTArray<MissingSpan, true>* missingSpans) const { 2233 const SkOpSpan* first = fTs.begin(); 2234 const SkOpSpan* last = fTs.end() - 1; 2235 SkASSERT(base >= first && last >= base); 2236 const SkOpSegment* other = base->fOther; 2237 const SkOpSpan* oFirst = other->fTs.begin(); 2238 const SkOpSpan* oLast = other->fTs.end() - 1; 2239 const SkOpSpan* oSpan = &other->fTs[base->fOtherIndex]; 2240 const SkOpSpan* test = base; 2241 const SkOpSpan* missing = NULL; 2242 while (test > first && (--test)->fPt == base->fPt) { 2243 if (this == test->fOther) { 2244 continue; 2245 } 2246 CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans); 2247 } 2248 test = base; 2249 while (test < last && (++test)->fPt == base->fPt) { 2250 SkASSERT(this != test->fOther); 2251 CheckOneLink(test, oSpan, oFirst, oLast, &missing, missingSpans); 2252 } 2253 } 2254 2255 // see if spans with two or more intersections all agree on common t and point values 2256 void SkOpSegment::checkMultiples() { 2257 debugValidate(); 2258 int index; 2259 int end = 0; 2260 while (fTs[++end].fT == 0) 2261 ; 2262 while (fTs[end].fT < 1) { 2263 int start = index = end; 2264 end = nextExactSpan(index, 1); 2265 if (end <= index) { 2266 return; // buffer overflow example triggers this 2267 } 2268 if (index + 1 == end) { 2269 continue; 2270 } 2271 // force the duplicates to agree on t and pt if not on the end 2272 SkOpSpan& span = fTs[index]; 2273 double thisT = span.fT; 2274 const SkPoint& thisPt = span.fPt; 2275 span.fMultiple = true; 2276 bool aligned = false; 2277 while (++index < end) { 2278 aligned |= alignSpan(index, thisT, thisPt); 2279 } 2280 if (aligned) { 2281 alignSpanState(start, end); 2282 } 2283 fMultiples = true; 2284 } 2285 debugValidate(); 2286 } 2287 2288 void SkOpSegment::CheckOneLink(const SkOpSpan* test, const SkOpSpan* oSpan, 2289 const SkOpSpan* oFirst, const SkOpSpan* oLast, const SkOpSpan** missingPtr, 2290 SkTArray<MissingSpan, true>* missingSpans) { 2291 SkASSERT(oSpan->fPt == test->fPt); 2292 const SkOpSpan* oTest = oSpan; 2293 while (oTest > oFirst && (--oTest)->fPt == test->fPt) { 2294 if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) { 2295 return; 2296 } 2297 } 2298 oTest = oSpan; 2299 while (oTest < oLast && (++oTest)->fPt == test->fPt) { 2300 if (oTest->fOther == test->fOther && oTest->fOtherT == test->fOtherT) { 2301 return; 2302 } 2303 } 2304 if (*missingPtr) { 2305 missingSpans->push_back(); 2306 } 2307 MissingSpan& lastMissing = missingSpans->back(); 2308 if (*missingPtr) { 2309 lastMissing = missingSpans->end()[-2]; 2310 } 2311 *missingPtr = test; 2312 lastMissing.fOther = test->fOther; 2313 lastMissing.fOtherT = test->fOtherT; 2314 } 2315 2316 bool SkOpSegment::checkSmall(int index) const { 2317 if (fTs[index].fSmall) { 2318 return true; 2319 } 2320 double tBase = fTs[index].fT; 2321 while (index > 0 && precisely_negative(tBase - fTs[--index].fT)) 2322 ; 2323 return fTs[index].fSmall; 2324 } 2325 2326 // a pair of curves may turn into coincident lines -- small may be a hint that that happened 2327 // if a cubic contains a loop, the counts must be adjusted 2328 void SkOpSegment::checkSmall() { 2329 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; 2330 const SkOpSpan* beginSpan = fTs.begin(); 2331 const SkOpSpan* thisSpan = beginSpan - 1; 2332 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be small 2333 while (++thisSpan < endSpan) { 2334 if (!thisSpan->fSmall) { 2335 continue; 2336 } 2337 if (!thisSpan->fWindValue) { 2338 continue; 2339 } 2340 const SkOpSpan& firstSpan = this->firstSpan(*thisSpan); 2341 const SkOpSpan& lastSpan = this->lastSpan(*thisSpan); 2342 const SkOpSpan* nextSpan = &firstSpan + 1; 2343 ptrdiff_t smallCount = &lastSpan - &firstSpan + 1; 2344 SkASSERT(1 <= smallCount && smallCount < count()); 2345 if (smallCount <= 1 && !nextSpan->fSmall) { 2346 SkASSERT(1 == smallCount); 2347 checkSmallCoincidence(firstSpan, NULL); 2348 continue; 2349 } 2350 // at this point, check for missing computed intersections 2351 const SkPoint& testPt = firstSpan.fPt; 2352 thisSpan = &firstSpan - 1; 2353 SkOpSegment* other = NULL; 2354 while (++thisSpan <= &lastSpan) { 2355 other = thisSpan->fOther; 2356 if (other != this) { 2357 break; 2358 } 2359 } 2360 SkASSERT(other != this); 2361 int oIndex = thisSpan->fOtherIndex; 2362 const SkOpSpan& oSpan = other->span(oIndex); 2363 const SkOpSpan& oFirstSpan = other->firstSpan(oSpan); 2364 const SkOpSpan& oLastSpan = other->lastSpan(oSpan); 2365 ptrdiff_t oCount = &oLastSpan - &oFirstSpan + 1; 2366 if (fLoop) { 2367 int smallCounts[2]; 2368 SkASSERT(!other->fLoop); // FIXME: we need more complicated logic for pair of loops 2369 if (calcLoopSpanCount(*thisSpan, smallCounts)) { 2370 if (smallCounts[0] && oCount != smallCounts[0]) { 2371 SkASSERT(0); // FIXME: need a working test case to properly code & debug 2372 } 2373 if (smallCounts[1] && oCount != smallCounts[1]) { 2374 SkASSERT(0); // FIXME: need a working test case to properly code & debug 2375 } 2376 goto nextSmallCheck; 2377 } 2378 } 2379 if (other->fLoop) { 2380 int otherCounts[2]; 2381 if (other->calcLoopSpanCount(other->span(oIndex), otherCounts)) { 2382 if (otherCounts[0] && otherCounts[0] != smallCount) { 2383 SkASSERT(0); // FIXME: need a working test case to properly code & debug 2384 } 2385 if (otherCounts[1] && otherCounts[1] != smallCount) { 2386 SkASSERT(0); // FIXME: need a working test case to properly code & debug 2387 } 2388 goto nextSmallCheck; 2389 } 2390 } 2391 if (oCount != smallCount) { // check if number of pts in this match other 2392 MissingSpan& missing = missingSpans.push_back(); 2393 missing.fOther = NULL; 2394 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing))); 2395 missing.fPt = testPt; 2396 const SkOpSpan& oSpan = other->span(oIndex); 2397 if (oCount > smallCount) { 2398 missing.fSegment = this; 2399 missing.fT = thisSpan->fT; 2400 other->checkLinks(&oSpan, &missingSpans); 2401 } else { 2402 missing.fSegment = other; 2403 missing.fT = oSpan.fT; 2404 checkLinks(thisSpan, &missingSpans); 2405 } 2406 if (!missingSpans.back().fOther || missing.fSegment->done()) { 2407 missingSpans.pop_back(); 2408 } 2409 } 2410 nextSmallCheck: 2411 thisSpan = &lastSpan; 2412 } 2413 int missingCount = missingSpans.count(); 2414 for (int index = 0; index < missingCount; ++index) { 2415 MissingSpan& missing = missingSpans[index]; 2416 SkOpSegment* missingOther = missing.fOther; 2417 // note that add t pair may edit span arrays, so prior pointers to spans are no longer valid 2418 if (!missing.fSegment->addTPair(missing.fT, missingOther, missing.fOtherT, false, 2419 missing.fPt)) { 2420 continue; 2421 } 2422 int otherTIndex = missingOther->findT(missing.fOtherT, missing.fPt, missing.fSegment); 2423 const SkOpSpan& otherSpan = missingOther->span(otherTIndex); 2424 if (otherSpan.fSmall) { 2425 const SkOpSpan* nextSpan = &otherSpan; 2426 do { 2427 ++nextSpan; 2428 } while (nextSpan->fSmall); 2429 SkAssertResult(missing.fSegment->addTCoincident(missing.fPt, nextSpan->fPt, 2430 nextSpan->fT, missingOther)); 2431 } else if (otherSpan.fT > 0) { 2432 const SkOpSpan* priorSpan = &otherSpan; 2433 do { 2434 --priorSpan; 2435 } while (priorSpan->fT == otherSpan.fT); 2436 if (priorSpan->fSmall) { 2437 missing.fSegment->addTCancel(missing.fPt, priorSpan->fPt, missingOther); 2438 } 2439 } 2440 } 2441 // OPTIMIZATION: this may fix indices more than once. Build an array of unique segments to 2442 // avoid this 2443 for (int index = 0; index < missingCount; ++index) { 2444 MissingSpan& missing = missingSpans[index]; 2445 missing.fSegment->fixOtherTIndex(); 2446 missing.fOther->fixOtherTIndex(); 2447 } 2448 debugValidate(); 2449 } 2450 2451 void SkOpSegment::checkSmallCoincidence(const SkOpSpan& span, 2452 SkTArray<MissingSpan, true>* checkMultiple) { 2453 SkASSERT(span.fSmall); 2454 if (0 && !span.fWindValue) { 2455 return; 2456 } 2457 SkASSERT(&span < fTs.end() - 1); 2458 const SkOpSpan* next = &span + 1; 2459 SkASSERT(!next->fSmall || checkMultiple); 2460 if (checkMultiple) { 2461 while (next->fSmall) { 2462 ++next; 2463 SkASSERT(next < fTs.end()); 2464 } 2465 } 2466 SkOpSegment* other = span.fOther; 2467 while (other != next->fOther) { 2468 if (!checkMultiple) { 2469 return; 2470 } 2471 const SkOpSpan* test = next + 1; 2472 if (test == fTs.end()) { 2473 return; 2474 } 2475 if (test->fPt != next->fPt || !precisely_equal(test->fT, next->fT)) { 2476 return; 2477 } 2478 next = test; 2479 } 2480 SkASSERT(span.fT < next->fT); 2481 int oStartIndex = other->findExactT(span.fOtherT, this); 2482 int oEndIndex = other->findExactT(next->fOtherT, this); 2483 // FIXME: be overly conservative by limiting this to the caller that allows multiple smalls 2484 if (!checkMultiple || fVerb != SkPath::kLine_Verb || other->fVerb != SkPath::kLine_Verb) { 2485 SkPoint mid = ptAtT((span.fT + next->fT) / 2); 2486 const SkOpSpan& oSpanStart = other->fTs[oStartIndex]; 2487 const SkOpSpan& oSpanEnd = other->fTs[oEndIndex]; 2488 SkPoint oMid = other->ptAtT((oSpanStart.fT + oSpanEnd.fT) / 2); 2489 if (!SkDPoint::ApproximatelyEqual(mid, oMid)) { 2490 return; 2491 } 2492 } 2493 // FIXME: again, be overly conservative to avoid breaking existing tests 2494 const SkOpSpan& oSpan = oStartIndex < oEndIndex ? other->fTs[oStartIndex] 2495 : other->fTs[oEndIndex]; 2496 if (checkMultiple && !oSpan.fSmall) { 2497 return; 2498 } 2499 // SkASSERT(oSpan.fSmall); 2500 if (oStartIndex < oEndIndex) { 2501 SkAssertResult(addTCoincident(span.fPt, next->fPt, next->fT, other)); 2502 } else { 2503 addTCancel(span.fPt, next->fPt, other); 2504 } 2505 if (!checkMultiple) { 2506 return; 2507 } 2508 // check to see if either segment is coincident with a third segment -- if it is, and if 2509 // the opposite segment is not already coincident with the third, make it so 2510 // OPTIMIZE: to make this check easier, add coincident and cancel could set a coincident bit 2511 if (span.fWindValue != 1 || span.fOppValue != 0) { 2512 // start here; 2513 // iterate through the spans, looking for the third coincident case 2514 // if we find one, we need to return state to the caller so that the indices can be fixed 2515 // this also suggests that all of this function is fragile since it relies on a valid index 2516 } 2517 // probably should make this a common function rather than copy/paste code 2518 if (oSpan.fWindValue != 1 || oSpan.fOppValue != 0) { 2519 const SkOpSpan* oTest = &oSpan; 2520 while (--oTest >= other->fTs.begin()) { 2521 if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT)) { 2522 break; 2523 } 2524 SkOpSegment* testOther = oTest->fOther; 2525 SkASSERT(testOther != this); 2526 // look in both directions to see if there is a coincident span 2527 const SkOpSpan* tTest = testOther->fTs.begin(); 2528 for (int testIndex = 0; testIndex < testOther->count(); ++testIndex) { 2529 if (tTest->fPt != span.fPt) { 2530 ++tTest; 2531 continue; 2532 } 2533 if (testOther->verb() != SkPath::kLine_Verb 2534 || other->verb() != SkPath::kLine_Verb) { 2535 SkPoint mid = ptAtT((span.fT + next->fT) / 2); 2536 SkPoint oMid = other->ptAtT((oTest->fOtherT + tTest->fT) / 2); 2537 if (!SkDPoint::ApproximatelyEqual(mid, oMid)) { 2538 continue; 2539 } 2540 } 2541 #if DEBUG_CONCIDENT 2542 SkDebugf("%s coincident found=%d %1.9g %1.9g\n", __FUNCTION__, testOther->fID, 2543 oTest->fOtherT, tTest->fT); 2544 #endif 2545 if (tTest->fT < oTest->fOtherT) { 2546 SkAssertResult(addTCoincident(span.fPt, next->fPt, next->fT, testOther)); 2547 } else { 2548 addTCancel(span.fPt, next->fPt, testOther); 2549 } 2550 MissingSpan missing; 2551 missing.fSegment = testOther; 2552 checkMultiple->push_back(missing); 2553 break; 2554 } 2555 } 2556 oTest = &oSpan; 2557 while (++oTest < other->fTs.end()) { 2558 if (oTest->fPt != oSpan.fPt || !precisely_equal(oTest->fT, oSpan.fT)) { 2559 break; 2560 } 2561 2562 } 2563 } 2564 } 2565 2566 // if pair of spans on either side of tiny have the same end point and mid point, mark 2567 // them as parallel 2568 void SkOpSegment::checkTiny() { 2569 SkSTArray<kMissingSpanCount, MissingSpan, true> missingSpans; 2570 SkOpSpan* thisSpan = fTs.begin() - 1; 2571 const SkOpSpan* endSpan = fTs.end() - 1; // last can't be tiny 2572 while (++thisSpan < endSpan) { 2573 if (!thisSpan->fTiny) { 2574 continue; 2575 } 2576 SkOpSpan* nextSpan = thisSpan + 1; 2577 double thisT = thisSpan->fT; 2578 double nextT = nextSpan->fT; 2579 if (thisT == nextT) { 2580 continue; 2581 } 2582 SkASSERT(thisT < nextT); 2583 SkASSERT(thisSpan->fPt == nextSpan->fPt); 2584 SkOpSegment* thisOther = thisSpan->fOther; 2585 SkOpSegment* nextOther = nextSpan->fOther; 2586 int oIndex = thisSpan->fOtherIndex; 2587 for (int oStep = -1; oStep <= 1; oStep += 2) { 2588 int oEnd = thisOther->nextExactSpan(oIndex, oStep); 2589 if (oEnd < 0) { 2590 continue; 2591 } 2592 const SkOpSpan& oSpan = thisOther->span(oEnd); 2593 int nIndex = nextSpan->fOtherIndex; 2594 for (int nStep = -1; nStep <= 1; nStep += 2) { 2595 int nEnd = nextOther->nextExactSpan(nIndex, nStep); 2596 if (nEnd < 0) { 2597 continue; 2598 } 2599 const SkOpSpan& nSpan = nextOther->span(nEnd); 2600 if (oSpan.fPt != nSpan.fPt) { 2601 continue; 2602 } 2603 double oMidT = (thisSpan->fOtherT + oSpan.fT) / 2; 2604 const SkPoint& oPt = thisOther->ptAtT(oMidT); 2605 double nMidT = (nextSpan->fOtherT + nSpan.fT) / 2; 2606 const SkPoint& nPt = nextOther->ptAtT(nMidT); 2607 if (!AlmostEqualUlps(oPt, nPt)) { 2608 continue; 2609 } 2610 #if DEBUG_CHECK_TINY 2611 SkDebugf("%s [%d] add coincidence [%d] [%d]\n", __FUNCTION__, fID, 2612 thisOther->fID, nextOther->fID); 2613 #endif 2614 // this segment is missing a entry that the other contains 2615 // remember so we can add the missing one and recompute the indices 2616 MissingSpan& missing = missingSpans.push_back(); 2617 SkDEBUGCODE(sk_bzero(&missing, sizeof(missing))); 2618 missing.fSegment = thisOther; 2619 missing.fT = thisSpan->fOtherT; 2620 SkASSERT(this != nextOther); 2621 missing.fOther = nextOther; 2622 missing.fOtherT = nextSpan->fOtherT; 2623 missing.fPt = thisSpan->fPt; 2624 } 2625 } 2626 } 2627 int missingCount = missingSpans.count(); 2628 if (!missingCount) { 2629 return; 2630 } 2631 for (int index = 0; index < missingCount; ++index) { 2632 MissingSpan& missing = missingSpans[index]; 2633 if (missing.fSegment != missing.fOther) { 2634 missing.fSegment->addTPair(missing.fT, missing.fOther, missing.fOtherT, false, 2635 missing.fPt); 2636 } 2637 } 2638 // OPTIMIZE: consolidate to avoid multiple calls to fix index 2639 for (int index = 0; index < missingCount; ++index) { 2640 MissingSpan& missing = missingSpans[index]; 2641 missing.fSegment->fixOtherTIndex(); 2642 missing.fOther->fixOtherTIndex(); 2643 } 2644 } 2645 2646 bool SkOpSegment::coincidentSmall(const SkPoint& pt, double t, const SkOpSegment* other) const { 2647 int count = this->count(); 2648 for (int index = 0; index < count; ++index) { 2649 const SkOpSpan& span = this->span(index); 2650 if (span.fOther != other) { 2651 continue; 2652 } 2653 if (span.fPt == pt) { 2654 continue; 2655 } 2656 if (!AlmostEqualUlps(span.fPt, pt)) { 2657 continue; 2658 } 2659 if (fVerb != SkPath::kCubic_Verb) { 2660 return true; 2661 } 2662 double tInterval = t - span.fT; 2663 double tMid = t - tInterval / 2; 2664 SkDPoint midPt = dcubic_xy_at_t(fPts, tMid); 2665 return midPt.approximatelyEqual(xyAtT(t)); 2666 } 2667 return false; 2668 } 2669 2670 bool SkOpSegment::findCoincidentMatch(const SkOpSpan* span, const SkOpSegment* other, int oStart, 2671 int oEnd, int step, SkPoint* startPt, SkPoint* endPt, double* endT) const { 2672 SkASSERT(span->fT == 0 || span->fT == 1); 2673 SkASSERT(span->fOtherT == 0 || span->fOtherT == 1); 2674 const SkOpSpan* otherSpan = &other->span(oEnd); 2675 double refT = otherSpan->fT; 2676 const SkPoint& refPt = otherSpan->fPt; 2677 const SkOpSpan* lastSpan = &other->span(step > 0 ? other->count() - 1 : 0); 2678 do { 2679 const SkOpSegment* match = span->fOther; 2680 if (match == otherSpan->fOther) { 2681 // find start of respective spans and see if both have winding 2682 int startIndex, endIndex; 2683 if (span->fOtherT == 1) { 2684 endIndex = span->fOtherIndex; 2685 startIndex = match->nextExactSpan(endIndex, -1); 2686 } else { 2687 startIndex = span->fOtherIndex; 2688 endIndex = match->nextExactSpan(startIndex, 1); 2689 } 2690 const SkOpSpan& startSpan = match->span(startIndex); 2691 if (startSpan.fWindValue != 0) { 2692 // draw ray from endSpan.fPt perpendicular to end tangent and measure distance 2693 // to other segment. 2694 const SkOpSpan& endSpan = match->span(endIndex); 2695 SkDLine ray; 2696 SkVector dxdy; 2697 if (span->fOtherT == 1) { 2698 ray.fPts[0].set(startSpan.fPt); 2699 dxdy = match->dxdy(startIndex); 2700 } else { 2701 ray.fPts[0].set(endSpan.fPt); 2702 dxdy = match->dxdy(endIndex); 2703 } 2704 ray.fPts[1].fX = ray.fPts[0].fX + dxdy.fY; 2705 ray.fPts[1].fY = ray.fPts[0].fY - dxdy.fX; 2706 SkIntersections i; 2707 int roots = (i.*CurveRay[SkPathOpsVerbToPoints(other->verb())])(other->pts(), ray); 2708 for (int index = 0; index < roots; ++index) { 2709 if (ray.fPts[0].approximatelyEqual(i.pt(index))) { 2710 double matchMidT = (match->span(startIndex).fT 2711 + match->span(endIndex).fT) / 2; 2712 SkPoint matchMidPt = match->ptAtT(matchMidT); 2713 double otherMidT = (i[0][index] + other->span(oStart).fT) / 2; 2714 SkPoint otherMidPt = other->ptAtT(otherMidT); 2715 if (SkDPoint::ApproximatelyEqual(matchMidPt, otherMidPt)) { 2716 *startPt = startSpan.fPt; 2717 *endPt = endSpan.fPt; 2718 *endT = endSpan.fT; 2719 return true; 2720 } 2721 } 2722 } 2723 } 2724 return false; 2725 } 2726 if (otherSpan == lastSpan) { 2727 break; 2728 } 2729 otherSpan += step; 2730 } while (otherSpan->fT == refT || otherSpan->fPt == refPt); 2731 return false; 2732 } 2733 2734 int SkOpSegment::findEndSpan(int endIndex) const { 2735 const SkOpSpan* span = &fTs[--endIndex]; 2736 const SkPoint& lastPt = span->fPt; 2737 double endT = span->fT; 2738 do { 2739 span = &fTs[--endIndex]; 2740 } while (SkDPoint::ApproximatelyEqual(span->fPt, lastPt) && (span->fT == endT || span->fTiny)); 2741 return endIndex + 1; 2742 } 2743 2744 /* 2745 The M and S variable name parts stand for the operators. 2746 Mi stands for Minuend (see wiki subtraction, analogous to difference) 2747 Su stands for Subtrahend 2748 The Opp variable name part designates that the value is for the Opposite operator. 2749 Opposite values result from combining coincident spans. 2750 */ 2751 SkOpSegment* SkOpSegment::findNextOp(SkTDArray<SkOpSpan*>* chase, int* nextStart, int* nextEnd, 2752 bool* unsortable, SkPathOp op, const int xorMiMask, 2753 const int xorSuMask) { 2754 const int startIndex = *nextStart; 2755 const int endIndex = *nextEnd; 2756 SkASSERT(startIndex != endIndex); 2757 SkDEBUGCODE(const int count = fTs.count()); 2758 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0); 2759 int step = SkSign32(endIndex - startIndex); 2760 *nextStart = startIndex; 2761 SkOpSegment* other = isSimple(nextStart, &step); 2762 if (other) 2763 { 2764 // mark the smaller of startIndex, endIndex done, and all adjacent 2765 // spans with the same T value (but not 'other' spans) 2766 #if DEBUG_WINDING 2767 SkDebugf("%s simple\n", __FUNCTION__); 2768 #endif 2769 int min = SkMin32(startIndex, endIndex); 2770 if (fTs[min].fDone) { 2771 return NULL; 2772 } 2773 markDoneBinary(min); 2774 double startT = other->fTs[*nextStart].fT; 2775 *nextEnd = *nextStart; 2776 do { 2777 *nextEnd += step; 2778 } while (precisely_zero(startT - other->fTs[*nextEnd].fT)); 2779 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); 2780 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) { 2781 *unsortable = true; 2782 return NULL; 2783 } 2784 return other; 2785 } 2786 const int end = nextExactSpan(startIndex, step); 2787 SkASSERT(end >= 0); 2788 SkASSERT(startIndex - endIndex != 0); 2789 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); 2790 // more than one viable candidate -- measure angles to find best 2791 2792 int calcWinding = computeSum(startIndex, end, SkOpAngle::kBinaryOpp); 2793 bool sortable = calcWinding != SK_NaN32; 2794 if (!sortable) { 2795 *unsortable = true; 2796 markDoneBinary(SkMin32(startIndex, endIndex)); 2797 return NULL; 2798 } 2799 SkOpAngle* angle = spanToAngle(end, startIndex); 2800 if (angle->unorderable()) { 2801 *unsortable = true; 2802 markDoneBinary(SkMin32(startIndex, endIndex)); 2803 return NULL; 2804 } 2805 #if DEBUG_SORT 2806 SkDebugf("%s\n", __FUNCTION__); 2807 angle->debugLoop(); 2808 #endif 2809 int sumMiWinding = updateWinding(endIndex, startIndex); 2810 if (sumMiWinding == SK_MinS32) { 2811 *unsortable = true; 2812 markDoneBinary(SkMin32(startIndex, endIndex)); 2813 return NULL; 2814 } 2815 int sumSuWinding = updateOppWinding(endIndex, startIndex); 2816 if (operand()) { 2817 SkTSwap<int>(sumMiWinding, sumSuWinding); 2818 } 2819 SkOpAngle* nextAngle = angle->next(); 2820 const SkOpAngle* foundAngle = NULL; 2821 bool foundDone = false; 2822 // iterate through the angle, and compute everyone's winding 2823 SkOpSegment* nextSegment; 2824 int activeCount = 0; 2825 do { 2826 nextSegment = nextAngle->segment(); 2827 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(), 2828 nextAngle->end(), op, &sumMiWinding, &sumSuWinding); 2829 if (activeAngle) { 2830 ++activeCount; 2831 if (!foundAngle || (foundDone && activeCount & 1)) { 2832 if (nextSegment->isTiny(nextAngle)) { 2833 *unsortable = true; 2834 markDoneBinary(SkMin32(startIndex, endIndex)); 2835 return NULL; 2836 } 2837 foundAngle = nextAngle; 2838 foundDone = nextSegment->done(nextAngle); 2839 } 2840 } 2841 if (nextSegment->done()) { 2842 continue; 2843 } 2844 if (nextSegment->isTiny(nextAngle)) { 2845 continue; 2846 } 2847 if (!activeAngle) { 2848 (void) nextSegment->markAndChaseDoneBinary(nextAngle->start(), nextAngle->end()); 2849 } 2850 SkOpSpan* last = nextAngle->lastMarked(); 2851 if (last) { 2852 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last)); 2853 *chase->append() = last; 2854 #if DEBUG_WINDING 2855 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__, 2856 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum, 2857 last->fSmall); 2858 #endif 2859 } 2860 } while ((nextAngle = nextAngle->next()) != angle); 2861 #if DEBUG_ANGLE 2862 if (foundAngle) { 2863 foundAngle->debugSameAs(foundAngle); 2864 } 2865 #endif 2866 2867 markDoneBinary(SkMin32(startIndex, endIndex)); 2868 if (!foundAngle) { 2869 return NULL; 2870 } 2871 *nextStart = foundAngle->start(); 2872 *nextEnd = foundAngle->end(); 2873 nextSegment = foundAngle->segment(); 2874 #if DEBUG_WINDING 2875 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 2876 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd); 2877 #endif 2878 return nextSegment; 2879 } 2880 2881 SkOpSegment* SkOpSegment::findNextWinding(SkTDArray<SkOpSpan*>* chase, int* nextStart, 2882 int* nextEnd, bool* unsortable) { 2883 const int startIndex = *nextStart; 2884 const int endIndex = *nextEnd; 2885 SkASSERT(startIndex != endIndex); 2886 SkDEBUGCODE(const int count = fTs.count()); 2887 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0); 2888 int step = SkSign32(endIndex - startIndex); 2889 *nextStart = startIndex; 2890 SkOpSegment* other = isSimple(nextStart, &step); 2891 if (other) 2892 { 2893 // mark the smaller of startIndex, endIndex done, and all adjacent 2894 // spans with the same T value (but not 'other' spans) 2895 #if DEBUG_WINDING 2896 SkDebugf("%s simple\n", __FUNCTION__); 2897 #endif 2898 int min = SkMin32(startIndex, endIndex); 2899 if (fTs[min].fDone) { 2900 return NULL; 2901 } 2902 markDoneUnary(min); 2903 double startT = other->fTs[*nextStart].fT; 2904 *nextEnd = *nextStart; 2905 do { 2906 *nextEnd += step; 2907 } while (precisely_zero(startT - other->fTs[*nextEnd].fT)); 2908 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); 2909 if (other->isTiny(SkMin32(*nextStart, *nextEnd))) { 2910 *unsortable = true; 2911 return NULL; 2912 } 2913 return other; 2914 } 2915 const int end = nextExactSpan(startIndex, step); 2916 SkASSERT(end >= 0); 2917 SkASSERT(startIndex - endIndex != 0); 2918 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); 2919 // more than one viable candidate -- measure angles to find best 2920 2921 int calcWinding = computeSum(startIndex, end, SkOpAngle::kUnaryWinding); 2922 bool sortable = calcWinding != SK_NaN32; 2923 if (!sortable) { 2924 *unsortable = true; 2925 markDoneUnary(SkMin32(startIndex, endIndex)); 2926 return NULL; 2927 } 2928 SkOpAngle* angle = spanToAngle(end, startIndex); 2929 #if DEBUG_SORT 2930 SkDebugf("%s\n", __FUNCTION__); 2931 angle->debugLoop(); 2932 #endif 2933 int sumWinding = updateWinding(endIndex, startIndex); 2934 SkOpAngle* nextAngle = angle->next(); 2935 const SkOpAngle* foundAngle = NULL; 2936 bool foundDone = false; 2937 SkOpSegment* nextSegment; 2938 int activeCount = 0; 2939 do { 2940 nextSegment = nextAngle->segment(); 2941 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(), 2942 &sumWinding); 2943 if (activeAngle) { 2944 ++activeCount; 2945 if (!foundAngle || (foundDone && activeCount & 1)) { 2946 if (nextSegment->isTiny(nextAngle)) { 2947 *unsortable = true; 2948 markDoneUnary(SkMin32(startIndex, endIndex)); 2949 return NULL; 2950 } 2951 foundAngle = nextAngle; 2952 foundDone = nextSegment->done(nextAngle); 2953 } 2954 } 2955 if (nextSegment->done()) { 2956 continue; 2957 } 2958 if (nextSegment->isTiny(nextAngle)) { 2959 continue; 2960 } 2961 if (!activeAngle) { 2962 nextSegment->markAndChaseDoneUnary(nextAngle->start(), nextAngle->end()); 2963 } 2964 SkOpSpan* last = nextAngle->lastMarked(); 2965 if (last) { 2966 SkASSERT(!SkPathOpsDebug::ChaseContains(*chase, last)); 2967 *chase->append() = last; 2968 #if DEBUG_WINDING 2969 SkDebugf("%s chase.append id=%d windSum=%d small=%d\n", __FUNCTION__, 2970 last->fOther->fTs[last->fOtherIndex].fOther->debugID(), last->fWindSum, 2971 last->fSmall); 2972 #endif 2973 } 2974 } while ((nextAngle = nextAngle->next()) != angle); 2975 markDoneUnary(SkMin32(startIndex, endIndex)); 2976 if (!foundAngle) { 2977 return NULL; 2978 } 2979 *nextStart = foundAngle->start(); 2980 *nextEnd = foundAngle->end(); 2981 nextSegment = foundAngle->segment(); 2982 #if DEBUG_WINDING 2983 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 2984 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd); 2985 #endif 2986 return nextSegment; 2987 } 2988 2989 SkOpSegment* SkOpSegment::findNextXor(int* nextStart, int* nextEnd, bool* unsortable) { 2990 const int startIndex = *nextStart; 2991 const int endIndex = *nextEnd; 2992 SkASSERT(startIndex != endIndex); 2993 SkDEBUGCODE(int count = fTs.count()); 2994 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0); 2995 int step = SkSign32(endIndex - startIndex); 2996 // Detect cases where all the ends canceled out (e.g., 2997 // there is no angle) and therefore there's only one valid connection 2998 *nextStart = startIndex; 2999 SkOpSegment* other = isSimple(nextStart, &step); 3000 if (other) 3001 { 3002 #if DEBUG_WINDING 3003 SkDebugf("%s simple\n", __FUNCTION__); 3004 #endif 3005 int min = SkMin32(startIndex, endIndex); 3006 if (fTs[min].fDone) { 3007 return NULL; 3008 } 3009 markDone(min, 1); 3010 double startT = other->fTs[*nextStart].fT; 3011 // FIXME: I don't know why the logic here is difference from the winding case 3012 SkDEBUGCODE(bool firstLoop = true;) 3013 if ((approximately_less_than_zero(startT) && step < 0) 3014 || (approximately_greater_than_one(startT) && step > 0)) { 3015 step = -step; 3016 SkDEBUGCODE(firstLoop = false;) 3017 } 3018 do { 3019 *nextEnd = *nextStart; 3020 do { 3021 *nextEnd += step; 3022 } while (precisely_zero(startT - other->fTs[*nextEnd].fT)); 3023 if (other->fTs[SkMin32(*nextStart, *nextEnd)].fWindValue) { 3024 break; 3025 } 3026 SkASSERT(firstLoop); 3027 SkDEBUGCODE(firstLoop = false;) 3028 step = -step; 3029 } while (true); 3030 SkASSERT(step < 0 ? *nextEnd >= 0 : *nextEnd < other->fTs.count()); 3031 return other; 3032 } 3033 SkASSERT(startIndex - endIndex != 0); 3034 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); 3035 // parallel block above with presorted version 3036 int end = nextExactSpan(startIndex, step); 3037 SkASSERT(end >= 0); 3038 SkOpAngle* angle = spanToAngle(end, startIndex); 3039 SkASSERT(angle); 3040 #if DEBUG_SORT 3041 SkDebugf("%s\n", __FUNCTION__); 3042 angle->debugLoop(); 3043 #endif 3044 SkOpAngle* nextAngle = angle->next(); 3045 const SkOpAngle* foundAngle = NULL; 3046 bool foundDone = false; 3047 SkOpSegment* nextSegment; 3048 int activeCount = 0; 3049 do { 3050 nextSegment = nextAngle->segment(); 3051 ++activeCount; 3052 if (!foundAngle || (foundDone && activeCount & 1)) { 3053 if (nextSegment->isTiny(nextAngle)) { 3054 *unsortable = true; 3055 return NULL; 3056 } 3057 foundAngle = nextAngle; 3058 if (!(foundDone = nextSegment->done(nextAngle))) { 3059 break; 3060 } 3061 } 3062 nextAngle = nextAngle->next(); 3063 } while (nextAngle != angle); 3064 markDone(SkMin32(startIndex, endIndex), 1); 3065 if (!foundAngle) { 3066 return NULL; 3067 } 3068 *nextStart = foundAngle->start(); 3069 *nextEnd = foundAngle->end(); 3070 nextSegment = foundAngle->segment(); 3071 #if DEBUG_WINDING 3072 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 3073 __FUNCTION__, debugID(), nextSegment->debugID(), *nextStart, *nextEnd); 3074 #endif 3075 return nextSegment; 3076 } 3077 3078 int SkOpSegment::findStartSpan(int startIndex) const { 3079 int index = startIndex; 3080 const SkOpSpan* span = &fTs[index]; 3081 const SkPoint& firstPt = span->fPt; 3082 double firstT = span->fT; 3083 const SkOpSpan* prior; 3084 do { 3085 prior = span; 3086 span = &fTs[++index]; 3087 } while (SkDPoint::ApproximatelyEqual(span->fPt, firstPt) 3088 && (span->fT == firstT || prior->fTiny)); 3089 return index; 3090 } 3091 3092 int SkOpSegment::findExactT(double t, const SkOpSegment* match) const { 3093 int count = this->count(); 3094 for (int index = 0; index < count; ++index) { 3095 const SkOpSpan& span = fTs[index]; 3096 if (span.fT == t && span.fOther == match) { 3097 return index; 3098 } 3099 } 3100 SkASSERT(0); 3101 return -1; 3102 } 3103 3104 int SkOpSegment::findOtherT(double t, const SkOpSegment* match) const { 3105 int count = this->count(); 3106 for (int index = 0; index < count; ++index) { 3107 const SkOpSpan& span = fTs[index]; 3108 if (span.fOtherT == t && span.fOther == match) { 3109 return index; 3110 } 3111 } 3112 return -1; 3113 } 3114 3115 int SkOpSegment::findT(double t, const SkPoint& pt, const SkOpSegment* match) const { 3116 int count = this->count(); 3117 // prefer exact matches over approximate matches 3118 for (int index = 0; index < count; ++index) { 3119 const SkOpSpan& span = fTs[index]; 3120 if (span.fT == t && span.fOther == match) { 3121 return index; 3122 } 3123 } 3124 for (int index = 0; index < count; ++index) { 3125 const SkOpSpan& span = fTs[index]; 3126 if (approximately_equal_orderable(span.fT, t) && span.fOther == match) { 3127 return index; 3128 } 3129 } 3130 // Usually, the pair of ts are an exact match. It's possible that the t values have 3131 // been adjusted to make multiple intersections align. In this rare case, look for a 3132 // matching point / match pair instead. 3133 for (int index = 0; index < count; ++index) { 3134 const SkOpSpan& span = fTs[index]; 3135 if (span.fPt == pt && span.fOther == match) { 3136 return index; 3137 } 3138 } 3139 SkASSERT(0); 3140 return -1; 3141 } 3142 3143 SkOpSegment* SkOpSegment::findTop(int* tIndexPtr, int* endIndexPtr, bool* unsortable, 3144 bool firstPass) { 3145 // iterate through T intersections and return topmost 3146 // topmost tangent from y-min to first pt is closer to horizontal 3147 SkASSERT(!done()); 3148 int firstT = -1; 3149 /* SkPoint topPt = */ activeLeftTop(&firstT); 3150 if (firstT < 0) { 3151 *unsortable = !firstPass; 3152 firstT = 0; 3153 while (fTs[firstT].fDone) { 3154 SkASSERT(firstT < fTs.count()); 3155 ++firstT; 3156 } 3157 *tIndexPtr = firstT; 3158 *endIndexPtr = nextExactSpan(firstT, 1); 3159 return this; 3160 } 3161 // sort the edges to find the leftmost 3162 int step = 1; 3163 int end; 3164 if (span(firstT).fDone || (end = nextSpan(firstT, step)) == -1) { 3165 step = -1; 3166 end = nextSpan(firstT, step); 3167 SkASSERT(end != -1); 3168 } 3169 // if the topmost T is not on end, or is three-way or more, find left 3170 // look for left-ness from tLeft to firstT (matching y of other) 3171 SkASSERT(firstT - end != 0); 3172 SkOpAngle* markAngle = spanToAngle(firstT, end); 3173 if (!markAngle) { 3174 markAngle = addSingletonAngles(step); 3175 } 3176 markAngle->markStops(); 3177 const SkOpAngle* baseAngle = markAngle->next() == markAngle && !isVertical() ? markAngle 3178 : markAngle->findFirst(); 3179 if (!baseAngle) { 3180 return NULL; // nothing to do 3181 } 3182 SkScalar top = SK_ScalarMax; 3183 const SkOpAngle* firstAngle = NULL; 3184 const SkOpAngle* angle = baseAngle; 3185 do { 3186 if (!angle->unorderable()) { 3187 SkOpSegment* next = angle->segment(); 3188 SkPathOpsBounds bounds; 3189 next->subDivideBounds(angle->end(), angle->start(), &bounds); 3190 if (approximately_greater(top, bounds.fTop)) { 3191 top = bounds.fTop; 3192 firstAngle = angle; 3193 } 3194 } 3195 angle = angle->next(); 3196 } while (angle != baseAngle); 3197 SkASSERT(firstAngle); 3198 #if DEBUG_SORT 3199 SkDebugf("%s\n", __FUNCTION__); 3200 firstAngle->debugLoop(); 3201 #endif 3202 // skip edges that have already been processed 3203 angle = firstAngle; 3204 SkOpSegment* leftSegment = NULL; 3205 bool looped = false; 3206 do { 3207 *unsortable = angle->unorderable(); 3208 if (firstPass || !*unsortable) { 3209 leftSegment = angle->segment(); 3210 *tIndexPtr = angle->end(); 3211 *endIndexPtr = angle->start(); 3212 if (!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fDone) { 3213 break; 3214 } 3215 } 3216 angle = angle->next(); 3217 looped = true; 3218 } while (angle != firstAngle); 3219 if (angle == firstAngle && looped) { 3220 return NULL; 3221 } 3222 if (leftSegment->verb() >= SkPath::kQuad_Verb) { 3223 const int tIndex = *tIndexPtr; 3224 const int endIndex = *endIndexPtr; 3225 bool swap; 3226 if (!leftSegment->clockwise(tIndex, endIndex, &swap)) { 3227 #if DEBUG_SWAP_TOP 3228 SkDebugf("%s swap=%d inflections=%d serpentine=%d controlledbyends=%d monotonic=%d\n", 3229 __FUNCTION__, 3230 swap, leftSegment->debugInflections(tIndex, endIndex), 3231 leftSegment->serpentine(tIndex, endIndex), 3232 leftSegment->controlsContainedByEnds(tIndex, endIndex), 3233 leftSegment->monotonicInY(tIndex, endIndex)); 3234 #endif 3235 if (swap) { 3236 // FIXME: I doubt it makes sense to (necessarily) swap if the edge was not the first 3237 // sorted but merely the first not already processed (i.e., not done) 3238 SkTSwap(*tIndexPtr, *endIndexPtr); 3239 } 3240 } 3241 } 3242 SkASSERT(!leftSegment->fTs[SkMin32(*tIndexPtr, *endIndexPtr)].fTiny); 3243 return leftSegment; 3244 } 3245 3246 int SkOpSegment::firstActive(int tIndex) const { 3247 while (fTs[tIndex].fTiny) { 3248 SkASSERT(!isCanceled(tIndex)); 3249 ++tIndex; 3250 } 3251 return tIndex; 3252 } 3253 3254 // FIXME: not crazy about this 3255 // when the intersections are performed, the other index is into an 3256 // incomplete array. As the array grows, the indices become incorrect 3257 // while the following fixes the indices up again, it isn't smart about 3258 // skipping segments whose indices are already correct 3259 // assuming we leave the code that wrote the index in the first place 3260 // FIXME: if called after remove, this needs to correct tiny 3261 void SkOpSegment::fixOtherTIndex() { 3262 int iCount = fTs.count(); 3263 for (int i = 0; i < iCount; ++i) { 3264 SkOpSpan& iSpan = fTs[i]; 3265 double oT = iSpan.fOtherT; 3266 SkOpSegment* other = iSpan.fOther; 3267 int oCount = other->fTs.count(); 3268 SkDEBUGCODE(iSpan.fOtherIndex = -1); 3269 for (int o = 0; o < oCount; ++o) { 3270 SkOpSpan& oSpan = other->fTs[o]; 3271 if (oT == oSpan.fT && this == oSpan.fOther && oSpan.fOtherT == iSpan.fT) { 3272 iSpan.fOtherIndex = o; 3273 oSpan.fOtherIndex = i; 3274 break; 3275 } 3276 } 3277 SkASSERT(iSpan.fOtherIndex >= 0); 3278 } 3279 } 3280 3281 bool SkOpSegment::inCoincidentSpan(double t, const SkOpSegment* other) const { 3282 int foundEnds = 0; 3283 int count = this->count(); 3284 for (int index = 0; index < count; ++index) { 3285 const SkOpSpan& span = this->span(index); 3286 if (span.fCoincident) { 3287 foundEnds |= (span.fOther == other) << ((t > span.fT) + (t >= span.fT)); 3288 } 3289 } 3290 SkASSERT(foundEnds != 7); 3291 return foundEnds == 0x3 || foundEnds == 0x5 || foundEnds == 0x6; // two bits set 3292 } 3293 3294 void SkOpSegment::init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) { 3295 fDoneSpans = 0; 3296 fOperand = operand; 3297 fXor = evenOdd; 3298 fPts = pts; 3299 fVerb = verb; 3300 fLoop = fMultiples = fSmall = fTiny = false; 3301 } 3302 3303 void SkOpSegment::initWinding(int start, int end, SkOpAngle::IncludeType angleIncludeType) { 3304 int local = spanSign(start, end); 3305 if (angleIncludeType == SkOpAngle::kBinarySingle) { 3306 int oppLocal = oppSign(start, end); 3307 (void) markAndChaseWinding(start, end, local, oppLocal); 3308 // OPTIMIZATION: the reverse mark and chase could skip the first marking 3309 (void) markAndChaseWinding(end, start, local, oppLocal); 3310 } else { 3311 (void) markAndChaseWinding(start, end, local); 3312 // OPTIMIZATION: the reverse mark and chase could skip the first marking 3313 (void) markAndChaseWinding(end, start, local); 3314 } 3315 } 3316 3317 /* 3318 when we start with a vertical intersect, we try to use the dx to determine if the edge is to 3319 the left or the right of vertical. This determines if we need to add the span's 3320 sign or not. However, this isn't enough. 3321 If the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed. 3322 If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed 3323 from has the same x direction as this span, the winding should change. If the dx is opposite, then 3324 the same winding is shared by both. 3325 */ 3326 void SkOpSegment::initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, 3327 int oppWind, SkScalar hitOppDx) { 3328 SkASSERT(hitDx || !winding); 3329 SkScalar dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX; 3330 SkASSERT(dx); 3331 int windVal = windValue(SkMin32(start, end)); 3332 #if DEBUG_WINDING_AT_T 3333 SkDebugf("%s id=%d oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, debugID(), winding, 3334 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal); 3335 #endif 3336 int sideWind = winding + (dx < 0 ? windVal : -windVal); 3337 if (abs(winding) < abs(sideWind)) { 3338 winding = sideWind; 3339 } 3340 SkDEBUGCODE(int oppLocal = oppSign(start, end)); 3341 SkASSERT(hitOppDx || !oppWind || !oppLocal); 3342 int oppWindVal = oppValue(SkMin32(start, end)); 3343 if (!oppWind) { 3344 oppWind = dx < 0 ? oppWindVal : -oppWindVal; 3345 } else if (hitOppDx * dx >= 0) { 3346 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal); 3347 if (abs(oppWind) < abs(oppSideWind)) { 3348 oppWind = oppSideWind; 3349 } 3350 } 3351 #if DEBUG_WINDING_AT_T 3352 SkDebugf(" winding=%d oppWind=%d\n", winding, oppWind); 3353 #endif 3354 (void) markAndChaseWinding(start, end, winding, oppWind); 3355 // OPTIMIZATION: the reverse mark and chase could skip the first marking 3356 (void) markAndChaseWinding(end, start, winding, oppWind); 3357 } 3358 3359 bool SkOpSegment::inLoop(const SkOpAngle* baseAngle, int spanCount, int* indexPtr) const { 3360 if (!baseAngle->inLoop()) { 3361 return false; 3362 } 3363 int index = *indexPtr; 3364 SkOpAngle* from = fTs[index].fFromAngle; 3365 SkOpAngle* to = fTs[index].fToAngle; 3366 while (++index < spanCount) { 3367 SkOpAngle* nextFrom = fTs[index].fFromAngle; 3368 SkOpAngle* nextTo = fTs[index].fToAngle; 3369 if (from != nextFrom || to != nextTo) { 3370 break; 3371 } 3372 } 3373 *indexPtr = index; 3374 return true; 3375 } 3376 3377 // OPTIMIZE: successive calls could start were the last leaves off 3378 // or calls could specialize to walk forwards or backwards 3379 bool SkOpSegment::isMissing(double startT, const SkPoint& pt) const { 3380 int tCount = fTs.count(); 3381 for (int index = 0; index < tCount; ++index) { 3382 const SkOpSpan& span = fTs[index]; 3383 if (approximately_zero(startT - span.fT) && pt == span.fPt) { 3384 return false; 3385 } 3386 } 3387 return true; 3388 } 3389 3390 3391 SkOpSegment* SkOpSegment::isSimple(int* end, int* step) { 3392 return nextChase(end, step, NULL, NULL); 3393 } 3394 3395 bool SkOpSegment::isTiny(const SkOpAngle* angle) const { 3396 int start = angle->start(); 3397 int end = angle->end(); 3398 const SkOpSpan& mSpan = fTs[SkMin32(start, end)]; 3399 return mSpan.fTiny; 3400 } 3401 3402 bool SkOpSegment::isTiny(int index) const { 3403 return fTs[index].fTiny; 3404 } 3405 3406 // look pair of active edges going away from coincident edge 3407 // one of them should be the continuation of other 3408 // if both are active, look to see if they both the connect to another coincident pair 3409 // if at least one is a line, then make the pair coincident 3410 // if neither is a line, test for coincidence 3411 bool SkOpSegment::joinCoincidence(SkOpSegment* other, double otherT, const SkPoint& otherPt, 3412 int step, bool cancel) { 3413 int otherTIndex = other->findT(otherT, otherPt, this); 3414 int next = other->nextExactSpan(otherTIndex, step); 3415 int otherMin = SkMin32(otherTIndex, next); 3416 int otherWind = other->span(otherMin).fWindValue; 3417 if (otherWind == 0) { 3418 return false; 3419 } 3420 SkASSERT(next >= 0); 3421 int tIndex = 0; 3422 do { 3423 SkOpSpan* test = &fTs[tIndex]; 3424 SkASSERT(test->fT == 0); 3425 if (test->fOther == other || test->fOtherT != 1) { 3426 continue; 3427 } 3428 SkPoint startPt, endPt; 3429 double endT; 3430 if (findCoincidentMatch(test, other, otherTIndex, next, step, &startPt, &endPt, &endT)) { 3431 SkOpSegment* match = test->fOther; 3432 if (cancel) { 3433 match->addTCancel(startPt, endPt, other); 3434 } else { 3435 SkAssertResult(match->addTCoincident(startPt, endPt, endT, other)); 3436 } 3437 return true; 3438 } 3439 } while (fTs[++tIndex].fT == 0); 3440 return false; 3441 } 3442 3443 // this span is excluded by the winding rule -- chase the ends 3444 // as long as they are unambiguous to mark connections as done 3445 // and give them the same winding value 3446 3447 SkOpSpan* SkOpSegment::markAndChaseDoneBinary(int index, int endIndex) { 3448 int step = SkSign32(endIndex - index); 3449 int min = SkMin32(index, endIndex); 3450 markDoneBinary(min); 3451 SkOpSpan* last = NULL; 3452 SkOpSegment* other = this; 3453 while ((other = other->nextChase(&index, &step, &min, &last))) { 3454 if (other->done()) { 3455 SkASSERT(!last); 3456 break; 3457 } 3458 other->markDoneBinary(min); 3459 } 3460 return last; 3461 } 3462 3463 SkOpSpan* SkOpSegment::markAndChaseDoneUnary(int index, int endIndex) { 3464 int step = SkSign32(endIndex - index); 3465 int min = SkMin32(index, endIndex); 3466 markDoneUnary(min); 3467 SkOpSpan* last = NULL; 3468 SkOpSegment* other = this; 3469 while ((other = other->nextChase(&index, &step, &min, &last))) { 3470 if (other->done()) { 3471 SkASSERT(!last); 3472 break; 3473 } 3474 other->markDoneUnary(min); 3475 } 3476 return last; 3477 } 3478 3479 SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding) { 3480 int index = angle->start(); 3481 int endIndex = angle->end(); 3482 int step = SkSign32(endIndex - index); 3483 int min = SkMin32(index, endIndex); 3484 markWinding(min, winding); 3485 SkOpSpan* last = NULL; 3486 SkOpSegment* other = this; 3487 while ((other = other->nextChase(&index, &step, &min, &last))) { 3488 if (other->fTs[min].fWindSum != SK_MinS32) { 3489 // SkASSERT(other->fTs[min].fWindSum == winding); 3490 SkASSERT(!last); 3491 break; 3492 } 3493 other->markWinding(min, winding); 3494 } 3495 return last; 3496 } 3497 3498 SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding) { 3499 int min = SkMin32(index, endIndex); 3500 int step = SkSign32(endIndex - index); 3501 markWinding(min, winding); 3502 SkOpSpan* last = NULL; 3503 SkOpSegment* other = this; 3504 while ((other = other->nextChase(&index, &step, &min, &last))) { 3505 if (other->fTs[min].fWindSum != SK_MinS32) { 3506 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop); 3507 SkASSERT(!last); 3508 break; 3509 } 3510 other->markWinding(min, winding); 3511 } 3512 return last; 3513 } 3514 3515 SkOpSpan* SkOpSegment::markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) { 3516 int min = SkMin32(index, endIndex); 3517 int step = SkSign32(endIndex - index); 3518 markWinding(min, winding, oppWinding); 3519 SkOpSpan* last = NULL; 3520 SkOpSegment* other = this; 3521 while ((other = other->nextChase(&index, &step, &min, &last))) { 3522 if (other->fTs[min].fWindSum != SK_MinS32) { 3523 #ifdef SK_DEBUG 3524 if (!other->fTs[min].fLoop) { 3525 if (fOperand == other->fOperand) { 3526 // FIXME: this is probably a bug -- rects4 asserts here 3527 // SkASSERT(other->fTs[min].fWindSum == winding); 3528 // FIXME: this is probably a bug -- rects3 asserts here 3529 // SkASSERT(other->fTs[min].fOppSum == oppWinding); 3530 } else { 3531 // FIXME: this is probably a bug -- issue414409b asserts here 3532 // SkASSERT(other->fTs[min].fWindSum == oppWinding); 3533 // FIXME: this is probably a bug -- skpwww_joomla_org_23 asserts here 3534 // SkASSERT(other->fTs[min].fOppSum == winding); 3535 } 3536 } 3537 SkASSERT(!last); 3538 #endif 3539 break; 3540 } 3541 if (fOperand == other->fOperand) { 3542 other->markWinding(min, winding, oppWinding); 3543 } else { 3544 other->markWinding(min, oppWinding, winding); 3545 } 3546 } 3547 return last; 3548 } 3549 3550 SkOpSpan* SkOpSegment::markAndChaseWinding(const SkOpAngle* angle, int winding, int oppWinding) { 3551 int start = angle->start(); 3552 int end = angle->end(); 3553 return markAndChaseWinding(start, end, winding, oppWinding); 3554 } 3555 3556 SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, const SkOpAngle* angle) { 3557 SkASSERT(angle->segment() == this); 3558 if (UseInnerWinding(maxWinding, sumWinding)) { 3559 maxWinding = sumWinding; 3560 } 3561 SkOpSpan* last = markAndChaseWinding(angle, maxWinding); 3562 #if DEBUG_WINDING 3563 if (last) { 3564 SkDebugf("%s last id=%d windSum=", __FUNCTION__, 3565 last->fOther->fTs[last->fOtherIndex].fOther->debugID()); 3566 SkPathOpsDebug::WindingPrintf(last->fWindSum); 3567 SkDebugf(" small=%d\n", last->fSmall); 3568 } 3569 #endif 3570 return last; 3571 } 3572 3573 SkOpSpan* SkOpSegment::markAngle(int maxWinding, int sumWinding, int oppMaxWinding, 3574 int oppSumWinding, const SkOpAngle* angle) { 3575 SkASSERT(angle->segment() == this); 3576 if (UseInnerWinding(maxWinding, sumWinding)) { 3577 maxWinding = sumWinding; 3578 } 3579 if (oppMaxWinding != oppSumWinding && UseInnerWinding(oppMaxWinding, oppSumWinding)) { 3580 oppMaxWinding = oppSumWinding; 3581 } 3582 SkOpSpan* last = markAndChaseWinding(angle, maxWinding, oppMaxWinding); 3583 #if DEBUG_WINDING 3584 if (last) { 3585 SkDebugf("%s last id=%d windSum=", __FUNCTION__, 3586 last->fOther->fTs[last->fOtherIndex].fOther->debugID()); 3587 SkPathOpsDebug::WindingPrintf(last->fWindSum); 3588 SkDebugf(" small=%d\n", last->fSmall); 3589 } 3590 #endif 3591 return last; 3592 } 3593 3594 // FIXME: this should also mark spans with equal (x,y) 3595 // This may be called when the segment is already marked done. While this 3596 // wastes time, it shouldn't do any more than spin through the T spans. 3597 // OPTIMIZATION: abort on first done found (assuming that this code is 3598 // always called to mark segments done). 3599 void SkOpSegment::markDone(int index, int winding) { 3600 // SkASSERT(!done()); 3601 SkASSERT(winding); 3602 double referenceT = fTs[index].fT; 3603 int lesser = index; 3604 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 3605 markOneDone(__FUNCTION__, lesser, winding); 3606 } 3607 do { 3608 markOneDone(__FUNCTION__, index, winding); 3609 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT)); 3610 debugValidate(); 3611 } 3612 3613 void SkOpSegment::markDoneBinary(int index) { 3614 double referenceT = fTs[index].fT; 3615 int lesser = index; 3616 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 3617 markOneDoneBinary(__FUNCTION__, lesser); 3618 } 3619 do { 3620 markOneDoneBinary(__FUNCTION__, index); 3621 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT)); 3622 debugValidate(); 3623 } 3624 3625 void SkOpSegment::markDoneUnary(int index) { 3626 double referenceT = fTs[index].fT; 3627 int lesser = index; 3628 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 3629 markOneDoneUnary(__FUNCTION__, lesser); 3630 } 3631 do { 3632 markOneDoneUnary(__FUNCTION__, index); 3633 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT)); 3634 debugValidate(); 3635 } 3636 3637 void SkOpSegment::markOneDone(const char* funName, int tIndex, int winding) { 3638 SkOpSpan* span = markOneWinding(funName, tIndex, winding); 3639 if (!span || span->fDone) { 3640 return; 3641 } 3642 span->fDone = true; 3643 fDoneSpans++; 3644 } 3645 3646 void SkOpSegment::markOneDoneBinary(const char* funName, int tIndex) { 3647 SkOpSpan* span = verifyOneWinding(funName, tIndex); 3648 if (!span) { 3649 return; 3650 } 3651 SkASSERT(!span->fDone); 3652 span->fDone = true; 3653 fDoneSpans++; 3654 } 3655 3656 void SkOpSegment::markOneDoneUnary(const char* funName, int tIndex) { 3657 SkOpSpan* span = verifyOneWindingU(funName, tIndex); 3658 if (!span) { 3659 return; 3660 } 3661 if (span->fWindSum == SK_MinS32) { 3662 SkDebugf("%s uncomputed\n", __FUNCTION__); 3663 } 3664 SkASSERT(!span->fDone); 3665 span->fDone = true; 3666 fDoneSpans++; 3667 } 3668 3669 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding) { 3670 SkOpSpan& span = fTs[tIndex]; 3671 if (span.fDone && !span.fSmall) { 3672 return NULL; 3673 } 3674 #if DEBUG_MARK_DONE 3675 debugShowNewWinding(funName, span, winding); 3676 #endif 3677 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); 3678 #if DEBUG_LIMIT_WIND_SUM 3679 SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM); 3680 #endif 3681 span.fWindSum = winding; 3682 return &span; 3683 } 3684 3685 SkOpSpan* SkOpSegment::markOneWinding(const char* funName, int tIndex, int winding, 3686 int oppWinding) { 3687 SkOpSpan& span = fTs[tIndex]; 3688 if (span.fDone && !span.fSmall) { 3689 return NULL; 3690 } 3691 #if DEBUG_MARK_DONE 3692 debugShowNewWinding(funName, span, winding, oppWinding); 3693 #endif 3694 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); 3695 #if DEBUG_LIMIT_WIND_SUM 3696 SkASSERT(abs(winding) <= DEBUG_LIMIT_WIND_SUM); 3697 #endif 3698 span.fWindSum = winding; 3699 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding); 3700 #if DEBUG_LIMIT_WIND_SUM 3701 SkASSERT(abs(oppWinding) <= DEBUG_LIMIT_WIND_SUM); 3702 #endif 3703 span.fOppSum = oppWinding; 3704 debugValidate(); 3705 return &span; 3706 } 3707 3708 // from http://stackoverflow.com/questions/1165647/how-to-determine-if-a-list-of-polygon-points-are-in-clockwise-order 3709 bool SkOpSegment::clockwise(int tStart, int tEnd, bool* swap) const { 3710 SkASSERT(fVerb != SkPath::kLine_Verb); 3711 SkPoint edge[4]; 3712 subDivide(tStart, tEnd, edge); 3713 int points = SkPathOpsVerbToPoints(fVerb); 3714 double sum = (edge[0].fX - edge[points].fX) * (edge[0].fY + edge[points].fY); 3715 bool sumSet = false; 3716 if (fVerb == SkPath::kCubic_Verb) { 3717 SkDCubic cubic; 3718 cubic.set(edge); 3719 double inflectionTs[2]; 3720 int inflections = cubic.findInflections(inflectionTs); 3721 // FIXME: this fixes cubicOp114 and breaks cubicOp58d 3722 // the trouble is that cubics with inflections confuse whether the curve breaks towards 3723 // or away, which in turn is used to determine if it is on the far right or left. 3724 // Probably a totally different approach is in order. At one time I tried to project a 3725 // horizontal ray to determine winding, but was confused by how to map the vertically 3726 // oriented winding computation over. 3727 if (0 && inflections) { 3728 double tLo = this->span(tStart).fT; 3729 double tHi = this->span(tEnd).fT; 3730 double tLoStart = tLo; 3731 for (int index = 0; index < inflections; ++index) { 3732 if (between(tLo, inflectionTs[index], tHi)) { 3733 tLo = inflectionTs[index]; 3734 } 3735 } 3736 if (tLo != tLoStart && tLo != tHi) { 3737 SkDPoint sub[2]; 3738 sub[0] = cubic.ptAtT(tLo); 3739 sub[1].set(edge[3]); 3740 SkDPoint ctrl[2]; 3741 SkDCubic::SubDivide(fPts, sub[0], sub[1], tLo, tHi, ctrl); 3742 edge[0] = sub[0].asSkPoint(); 3743 edge[1] = ctrl[0].asSkPoint(); 3744 edge[2] = ctrl[1].asSkPoint(); 3745 sum = (edge[0].fX - edge[3].fX) * (edge[0].fY + edge[3].fY); 3746 } 3747 } 3748 SkScalar lesser = SkTMin<SkScalar>(edge[0].fY, edge[3].fY); 3749 if (edge[1].fY < lesser && edge[2].fY < lesser) { 3750 SkDLine tangent1 = {{ {edge[0].fX, edge[0].fY}, {edge[1].fX, edge[1].fY} }}; 3751 SkDLine tangent2 = {{ {edge[2].fX, edge[2].fY}, {edge[3].fX, edge[3].fY} }}; 3752 if (SkIntersections::Test(tangent1, tangent2)) { 3753 SkPoint topPt = cubic_top(fPts, fTs[tStart].fT, fTs[tEnd].fT); 3754 sum += (topPt.fX - edge[0].fX) * (topPt.fY + edge[0].fY); 3755 sum += (edge[3].fX - topPt.fX) * (edge[3].fY + topPt.fY); 3756 sumSet = true; 3757 } 3758 } 3759 } 3760 if (!sumSet) { 3761 for (int idx = 0; idx < points; ++idx){ 3762 sum += (edge[idx + 1].fX - edge[idx].fX) * (edge[idx + 1].fY + edge[idx].fY); 3763 } 3764 } 3765 if (fVerb == SkPath::kCubic_Verb) { 3766 SkDCubic cubic; 3767 cubic.set(edge); 3768 *swap = sum > 0 && !cubic.monotonicInY() && !cubic.serpentine(); 3769 } else { 3770 SkDQuad quad; 3771 quad.set(edge); 3772 *swap = sum > 0 && !quad.monotonicInY(); 3773 } 3774 return sum <= 0; 3775 } 3776 3777 bool SkOpSegment::monotonicInY(int tStart, int tEnd) const { 3778 SkASSERT(fVerb != SkPath::kLine_Verb); 3779 if (fVerb == SkPath::kQuad_Verb) { 3780 SkDQuad dst = SkDQuad::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); 3781 return dst.monotonicInY(); 3782 } 3783 SkASSERT(fVerb == SkPath::kCubic_Verb); 3784 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); 3785 return dst.monotonicInY(); 3786 } 3787 3788 bool SkOpSegment::serpentine(int tStart, int tEnd) const { 3789 if (fVerb != SkPath::kCubic_Verb) { 3790 return false; 3791 } 3792 SkDCubic dst = SkDCubic::SubDivide(fPts, fTs[tStart].fT, fTs[tEnd].fT); 3793 return dst.serpentine(); 3794 } 3795 3796 SkOpSpan* SkOpSegment::verifyOneWinding(const char* funName, int tIndex) { 3797 SkOpSpan& span = fTs[tIndex]; 3798 if (span.fDone) { 3799 return NULL; 3800 } 3801 #if DEBUG_MARK_DONE 3802 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum); 3803 #endif 3804 // If the prior angle in the sort is unorderable, the winding sum may not be computable. 3805 // To enable the assert, the 'prior is unorderable' state could be 3806 // piped down to this test, but not sure it's worth it. 3807 // (Once the sort order is stored in the span, this test may be feasible.) 3808 // SkASSERT(span.fWindSum != SK_MinS32); 3809 // SkASSERT(span.fOppSum != SK_MinS32); 3810 return &span; 3811 } 3812 3813 SkOpSpan* SkOpSegment::verifyOneWindingU(const char* funName, int tIndex) { 3814 SkOpSpan& span = fTs[tIndex]; 3815 if (span.fDone) { 3816 return NULL; 3817 } 3818 #if DEBUG_MARK_DONE 3819 debugShowNewWinding(funName, span, span.fWindSum); 3820 #endif 3821 // If the prior angle in the sort is unorderable, the winding sum may not be computable. 3822 // To enable the assert, the 'prior is unorderable' state could be 3823 // piped down to this test, but not sure it's worth it. 3824 // (Once the sort order is stored in the span, this test may be feasible.) 3825 // SkASSERT(span.fWindSum != SK_MinS32); 3826 return &span; 3827 } 3828 3829 void SkOpSegment::markWinding(int index, int winding) { 3830 // SkASSERT(!done()); 3831 SkASSERT(winding); 3832 double referenceT = fTs[index].fT; 3833 int lesser = index; 3834 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 3835 markOneWinding(__FUNCTION__, lesser, winding); 3836 } 3837 do { 3838 markOneWinding(__FUNCTION__, index, winding); 3839 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT)); 3840 debugValidate(); 3841 } 3842 3843 void SkOpSegment::markWinding(int index, int winding, int oppWinding) { 3844 // SkASSERT(!done()); 3845 SkASSERT(winding || oppWinding); 3846 double referenceT = fTs[index].fT; 3847 int lesser = index; 3848 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 3849 markOneWinding(__FUNCTION__, lesser, winding, oppWinding); 3850 } 3851 do { 3852 markOneWinding(__FUNCTION__, index, winding, oppWinding); 3853 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT)); 3854 debugValidate(); 3855 } 3856 3857 void SkOpSegment::matchWindingValue(int tIndex, double t, bool borrowWind) { 3858 int nextDoorWind = SK_MaxS32; 3859 int nextOppWind = SK_MaxS32; 3860 // prefer exact matches 3861 if (tIndex > 0) { 3862 const SkOpSpan& below = fTs[tIndex - 1]; 3863 if (below.fT == t) { 3864 nextDoorWind = below.fWindValue; 3865 nextOppWind = below.fOppValue; 3866 } 3867 } 3868 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) { 3869 const SkOpSpan& above = fTs[tIndex + 1]; 3870 if (above.fT == t) { 3871 nextDoorWind = above.fWindValue; 3872 nextOppWind = above.fOppValue; 3873 } 3874 } 3875 if (nextDoorWind == SK_MaxS32 && tIndex > 0) { 3876 const SkOpSpan& below = fTs[tIndex - 1]; 3877 if (approximately_negative(t - below.fT)) { 3878 nextDoorWind = below.fWindValue; 3879 nextOppWind = below.fOppValue; 3880 } 3881 } 3882 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) { 3883 const SkOpSpan& above = fTs[tIndex + 1]; 3884 if (approximately_negative(above.fT - t)) { 3885 nextDoorWind = above.fWindValue; 3886 nextOppWind = above.fOppValue; 3887 } 3888 } 3889 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) { 3890 const SkOpSpan& below = fTs[tIndex - 1]; 3891 nextDoorWind = below.fWindValue; 3892 nextOppWind = below.fOppValue; 3893 } 3894 if (nextDoorWind != SK_MaxS32) { 3895 SkOpSpan& newSpan = fTs[tIndex]; 3896 newSpan.fWindValue = nextDoorWind; 3897 newSpan.fOppValue = nextOppWind; 3898 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) { 3899 newSpan.fDone = true; 3900 ++fDoneSpans; 3901 } 3902 } 3903 } 3904 3905 bool SkOpSegment::nextCandidate(int* start, int* end) const { 3906 while (fTs[*end].fDone) { 3907 if (fTs[*end].fT == 1) { 3908 return false; 3909 } 3910 ++(*end); 3911 } 3912 *start = *end; 3913 *end = nextExactSpan(*start, 1); 3914 return true; 3915 } 3916 3917 static SkOpSegment* set_last(SkOpSpan** last, SkOpSpan* endSpan) { 3918 if (last && !endSpan->fSmall) { 3919 *last = endSpan; 3920 } 3921 return NULL; 3922 } 3923 3924 SkOpSegment* SkOpSegment::nextChase(int* indexPtr, int* stepPtr, int* minPtr, SkOpSpan** last) { 3925 int origIndex = *indexPtr; 3926 int step = *stepPtr; 3927 int end = nextExactSpan(origIndex, step); 3928 SkASSERT(end >= 0); 3929 SkOpSpan& endSpan = fTs[end]; 3930 SkOpAngle* angle = step > 0 ? endSpan.fFromAngle : endSpan.fToAngle; 3931 int foundIndex; 3932 int otherEnd; 3933 SkOpSegment* other; 3934 if (angle == NULL) { 3935 if (endSpan.fT != 0 && endSpan.fT != 1) { 3936 return NULL; 3937 } 3938 other = endSpan.fOther; 3939 foundIndex = endSpan.fOtherIndex; 3940 otherEnd = other->nextExactSpan(foundIndex, step); 3941 } else { 3942 int loopCount = angle->loopCount(); 3943 if (loopCount > 2) { 3944 return set_last(last, &endSpan); 3945 } 3946 const SkOpAngle* next = angle->next(); 3947 if (NULL == next) { 3948 return NULL; 3949 } 3950 if (angle->sign() != next->sign()) { 3951 #if DEBUG_WINDING 3952 SkDebugf("%s mismatched signs\n", __FUNCTION__); 3953 #endif 3954 // return set_last(last, &endSpan); 3955 } 3956 other = next->segment(); 3957 foundIndex = end = next->start(); 3958 otherEnd = next->end(); 3959 } 3960 int foundStep = foundIndex < otherEnd ? 1 : -1; 3961 if (*stepPtr != foundStep) { 3962 return set_last(last, &endSpan); 3963 } 3964 SkASSERT(*indexPtr >= 0); 3965 if (otherEnd < 0) { 3966 return NULL; 3967 } 3968 // SkASSERT(otherEnd >= 0); 3969 #if 1 3970 int origMin = origIndex + (step < 0 ? step : 0); 3971 const SkOpSpan& orig = this->span(origMin); 3972 #endif 3973 int foundMin = SkMin32(foundIndex, otherEnd); 3974 #if 1 3975 const SkOpSpan& found = other->span(foundMin); 3976 if (found.fWindValue != orig.fWindValue || found.fOppValue != orig.fOppValue) { 3977 return set_last(last, &endSpan); 3978 } 3979 #endif 3980 *indexPtr = foundIndex; 3981 *stepPtr = foundStep; 3982 if (minPtr) { 3983 *minPtr = foundMin; 3984 } 3985 return other; 3986 } 3987 3988 // This has callers for two different situations: one establishes the end 3989 // of the current span, and one establishes the beginning of the next span 3990 // (thus the name). When this is looking for the end of the current span, 3991 // coincidence is found when the beginning Ts contain -step and the end 3992 // contains step. When it is looking for the beginning of the next, the 3993 // first Ts found can be ignored and the last Ts should contain -step. 3994 // OPTIMIZATION: probably should split into two functions 3995 int SkOpSegment::nextSpan(int from, int step) const { 3996 const SkOpSpan& fromSpan = fTs[from]; 3997 int count = fTs.count(); 3998 int to = from; 3999 while (step > 0 ? ++to < count : --to >= 0) { 4000 const SkOpSpan& span = fTs[to]; 4001 if (approximately_zero(span.fT - fromSpan.fT)) { 4002 continue; 4003 } 4004 return to; 4005 } 4006 return -1; 4007 } 4008 4009 // FIXME 4010 // this returns at any difference in T, vs. a preset minimum. It may be 4011 // that all callers to nextSpan should use this instead. 4012 int SkOpSegment::nextExactSpan(int from, int step) const { 4013 int to = from; 4014 if (step < 0) { 4015 const SkOpSpan& fromSpan = fTs[from]; 4016 while (--to >= 0) { 4017 const SkOpSpan& span = fTs[to]; 4018 if (precisely_negative(fromSpan.fT - span.fT) || span.fTiny) { 4019 continue; 4020 } 4021 return to; 4022 } 4023 } else { 4024 while (fTs[from].fTiny) { 4025 from++; 4026 } 4027 const SkOpSpan& fromSpan = fTs[from]; 4028 int count = fTs.count(); 4029 while (++to < count) { 4030 const SkOpSpan& span = fTs[to]; 4031 if (precisely_negative(span.fT - fromSpan.fT)) { 4032 continue; 4033 } 4034 return to; 4035 } 4036 } 4037 return -1; 4038 } 4039 4040 void SkOpSegment::pinT(const SkPoint& pt, double* t) { 4041 if (pt == fPts[0]) { 4042 *t = 0; 4043 } 4044 int count = SkPathOpsVerbToPoints(fVerb); 4045 if (pt == fPts[count]) { 4046 *t = 1; 4047 } 4048 } 4049 4050 bool SkOpSegment::reversePoints(const SkPoint& p1, const SkPoint& p2) const { 4051 SkASSERT(p1 != p2); 4052 int spanCount = count(); 4053 int p1IndexMin = -1; 4054 int p2IndexMax = spanCount; 4055 for (int index = 0; index < spanCount; ++index) { 4056 const SkOpSpan& span = fTs[index]; 4057 if (span.fPt == p1) { 4058 if (p1IndexMin < 0) { 4059 p1IndexMin = index; 4060 } 4061 } else if (span.fPt == p2) { 4062 p2IndexMax = index; 4063 } 4064 } 4065 return p1IndexMin > p2IndexMax; 4066 } 4067 4068 void SkOpSegment::setCoincidentRange(const SkPoint& startPt, const SkPoint& endPt, 4069 SkOpSegment* other) { 4070 int count = this->count(); 4071 for (int index = 0; index < count; ++index) { 4072 SkOpSpan &span = fTs[index]; 4073 if ((startPt == span.fPt || endPt == span.fPt) && other == span.fOther) { 4074 span.fCoincident = true; 4075 } 4076 } 4077 } 4078 4079 void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, int* sumSuWinding, 4080 int* maxWinding, int* sumWinding, int* oppMaxWinding, int* oppSumWinding) { 4081 int deltaSum = spanSign(index, endIndex); 4082 int oppDeltaSum = oppSign(index, endIndex); 4083 if (operand()) { 4084 *maxWinding = *sumSuWinding; 4085 *sumWinding = *sumSuWinding -= deltaSum; 4086 *oppMaxWinding = *sumMiWinding; 4087 *oppSumWinding = *sumMiWinding -= oppDeltaSum; 4088 } else { 4089 *maxWinding = *sumMiWinding; 4090 *sumWinding = *sumMiWinding -= deltaSum; 4091 *oppMaxWinding = *sumSuWinding; 4092 *oppSumWinding = *sumSuWinding -= oppDeltaSum; 4093 } 4094 #if DEBUG_LIMIT_WIND_SUM 4095 SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM); 4096 SkASSERT(abs(*oppSumWinding) <= DEBUG_LIMIT_WIND_SUM); 4097 #endif 4098 } 4099 4100 void SkOpSegment::setUpWindings(int index, int endIndex, int* sumMiWinding, 4101 int* maxWinding, int* sumWinding) { 4102 int deltaSum = spanSign(index, endIndex); 4103 *maxWinding = *sumMiWinding; 4104 *sumWinding = *sumMiWinding -= deltaSum; 4105 #if DEBUG_LIMIT_WIND_SUM 4106 SkASSERT(abs(*sumWinding) <= DEBUG_LIMIT_WIND_SUM); 4107 #endif 4108 } 4109 4110 void SkOpSegment::sortAngles() { 4111 int spanCount = fTs.count(); 4112 if (spanCount <= 2) { 4113 return; 4114 } 4115 int index = 0; 4116 do { 4117 SkOpAngle* fromAngle = fTs[index].fFromAngle; 4118 SkOpAngle* toAngle = fTs[index].fToAngle; 4119 if (!fromAngle && !toAngle) { 4120 index += 1; 4121 continue; 4122 } 4123 SkOpAngle* baseAngle = NULL; 4124 if (fromAngle) { 4125 baseAngle = fromAngle; 4126 if (inLoop(baseAngle, spanCount, &index)) { 4127 continue; 4128 } 4129 } 4130 #if DEBUG_ANGLE 4131 bool wroteAfterHeader = false; 4132 #endif 4133 if (toAngle) { 4134 if (!baseAngle) { 4135 baseAngle = toAngle; 4136 if (inLoop(baseAngle, spanCount, &index)) { 4137 continue; 4138 } 4139 } else { 4140 SkDEBUGCODE(int newIndex = index); 4141 SkASSERT(!inLoop(baseAngle, spanCount, &newIndex) && newIndex == index); 4142 #if DEBUG_ANGLE 4143 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT, 4144 index); 4145 wroteAfterHeader = true; 4146 #endif 4147 baseAngle->insert(toAngle); 4148 } 4149 } 4150 SkOpAngle* nextFrom, * nextTo; 4151 int firstIndex = index; 4152 do { 4153 SkOpSpan& span = fTs[index]; 4154 SkOpSegment* other = span.fOther; 4155 SkOpSpan& oSpan = other->fTs[span.fOtherIndex]; 4156 SkOpAngle* oAngle = oSpan.fFromAngle; 4157 if (oAngle) { 4158 #if DEBUG_ANGLE 4159 if (!wroteAfterHeader) { 4160 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT, 4161 index); 4162 wroteAfterHeader = true; 4163 } 4164 #endif 4165 if (!oAngle->loopContains(*baseAngle)) { 4166 baseAngle->insert(oAngle); 4167 } 4168 } 4169 oAngle = oSpan.fToAngle; 4170 if (oAngle) { 4171 #if DEBUG_ANGLE 4172 if (!wroteAfterHeader) { 4173 SkDebugf("%s [%d] tStart=%1.9g [%d]\n", __FUNCTION__, debugID(), fTs[index].fT, 4174 index); 4175 wroteAfterHeader = true; 4176 } 4177 #endif 4178 if (!oAngle->loopContains(*baseAngle)) { 4179 baseAngle->insert(oAngle); 4180 } 4181 } 4182 if (++index == spanCount) { 4183 break; 4184 } 4185 nextFrom = fTs[index].fFromAngle; 4186 nextTo = fTs[index].fToAngle; 4187 } while (fromAngle == nextFrom && toAngle == nextTo); 4188 if (baseAngle && baseAngle->loopCount() == 1) { 4189 index = firstIndex; 4190 do { 4191 SkOpSpan& span = fTs[index]; 4192 span.fFromAngle = span.fToAngle = NULL; 4193 if (++index == spanCount) { 4194 break; 4195 } 4196 nextFrom = fTs[index].fFromAngle; 4197 nextTo = fTs[index].fToAngle; 4198 } while (fromAngle == nextFrom && toAngle == nextTo); 4199 baseAngle = NULL; 4200 } 4201 #if DEBUG_SORT 4202 SkASSERT(!baseAngle || baseAngle->loopCount() > 1); 4203 #endif 4204 } while (index < spanCount); 4205 } 4206 4207 // return true if midpoints were computed 4208 bool SkOpSegment::subDivide(int start, int end, SkPoint edge[4]) const { 4209 SkASSERT(start != end); 4210 edge[0] = fTs[start].fPt; 4211 int points = SkPathOpsVerbToPoints(fVerb); 4212 edge[points] = fTs[end].fPt; 4213 if (fVerb == SkPath::kLine_Verb) { 4214 return false; 4215 } 4216 double startT = fTs[start].fT; 4217 double endT = fTs[end].fT; 4218 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { 4219 // don't compute midpoints if we already have them 4220 if (fVerb == SkPath::kQuad_Verb) { 4221 edge[1] = fPts[1]; 4222 return false; 4223 } 4224 SkASSERT(fVerb == SkPath::kCubic_Verb); 4225 if (start < end) { 4226 edge[1] = fPts[1]; 4227 edge[2] = fPts[2]; 4228 return false; 4229 } 4230 edge[1] = fPts[2]; 4231 edge[2] = fPts[1]; 4232 return false; 4233 } 4234 const SkDPoint sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[points].fX, edge[points].fY }}; 4235 if (fVerb == SkPath::kQuad_Verb) { 4236 edge[1] = SkDQuad::SubDivide(fPts, sub[0], sub[1], startT, endT).asSkPoint(); 4237 } else { 4238 SkASSERT(fVerb == SkPath::kCubic_Verb); 4239 SkDPoint ctrl[2]; 4240 SkDCubic::SubDivide(fPts, sub[0], sub[1], startT, endT, ctrl); 4241 edge[1] = ctrl[0].asSkPoint(); 4242 edge[2] = ctrl[1].asSkPoint(); 4243 } 4244 return true; 4245 } 4246 4247 // return true if midpoints were computed 4248 bool SkOpSegment::subDivide(int start, int end, SkDCubic* result) const { 4249 SkASSERT(start != end); 4250 (*result)[0].set(fTs[start].fPt); 4251 int points = SkPathOpsVerbToPoints(fVerb); 4252 (*result)[points].set(fTs[end].fPt); 4253 if (fVerb == SkPath::kLine_Verb) { 4254 return false; 4255 } 4256 double startT = fTs[start].fT; 4257 double endT = fTs[end].fT; 4258 if ((startT == 0 || endT == 0) && (startT == 1 || endT == 1)) { 4259 // don't compute midpoints if we already have them 4260 if (fVerb == SkPath::kQuad_Verb) { 4261 (*result)[1].set(fPts[1]); 4262 return false; 4263 } 4264 SkASSERT(fVerb == SkPath::kCubic_Verb); 4265 if (start < end) { 4266 (*result)[1].set(fPts[1]); 4267 (*result)[2].set(fPts[2]); 4268 return false; 4269 } 4270 (*result)[1].set(fPts[2]); 4271 (*result)[2].set(fPts[1]); 4272 return false; 4273 } 4274 if (fVerb == SkPath::kQuad_Verb) { 4275 (*result)[1] = SkDQuad::SubDivide(fPts, (*result)[0], (*result)[2], startT, endT); 4276 } else { 4277 SkASSERT(fVerb == SkPath::kCubic_Verb); 4278 SkDCubic::SubDivide(fPts, (*result)[0], (*result)[3], startT, endT, &(*result)[1]); 4279 } 4280 return true; 4281 } 4282 4283 void SkOpSegment::subDivideBounds(int start, int end, SkPathOpsBounds* bounds) const { 4284 SkPoint edge[4]; 4285 subDivide(start, end, edge); 4286 (bounds->*SetCurveBounds[SkPathOpsVerbToPoints(fVerb)])(edge); 4287 } 4288 4289 void SkOpSegment::TrackOutsidePair(SkTArray<SkPoint, true>* outsidePts, const SkPoint& endPt, 4290 const SkPoint& startPt) { 4291 int outCount = outsidePts->count(); 4292 if (outCount == 0 || endPt != (*outsidePts)[outCount - 2]) { 4293 outsidePts->push_back(endPt); 4294 outsidePts->push_back(startPt); 4295 } 4296 } 4297 4298 void SkOpSegment::TrackOutside(SkTArray<SkPoint, true>* outsidePts, const SkPoint& startPt) { 4299 int outCount = outsidePts->count(); 4300 if (outCount == 0 || startPt != (*outsidePts)[outCount - 1]) { 4301 outsidePts->push_back(startPt); 4302 } 4303 } 4304 4305 void SkOpSegment::undoneSpan(int* start, int* end) { 4306 int tCount = fTs.count(); 4307 int index; 4308 for (index = 0; index < tCount; ++index) { 4309 if (!fTs[index].fDone) { 4310 break; 4311 } 4312 } 4313 SkASSERT(index < tCount - 1); 4314 *start = index; 4315 double startT = fTs[index].fT; 4316 while (approximately_negative(fTs[++index].fT - startT)) 4317 SkASSERT(index < tCount); 4318 SkASSERT(index < tCount); 4319 *end = index; 4320 } 4321 4322 int SkOpSegment::updateOppWinding(int index, int endIndex) const { 4323 int lesser = SkMin32(index, endIndex); 4324 int oppWinding = oppSum(lesser); 4325 int oppSpanWinding = oppSign(index, endIndex); 4326 if (oppSpanWinding && UseInnerWinding(oppWinding - oppSpanWinding, oppWinding) 4327 && oppWinding != SK_MaxS32) { 4328 oppWinding -= oppSpanWinding; 4329 } 4330 return oppWinding; 4331 } 4332 4333 int SkOpSegment::updateOppWinding(const SkOpAngle* angle) const { 4334 int startIndex = angle->start(); 4335 int endIndex = angle->end(); 4336 return updateOppWinding(endIndex, startIndex); 4337 } 4338 4339 int SkOpSegment::updateOppWindingReverse(const SkOpAngle* angle) const { 4340 int startIndex = angle->start(); 4341 int endIndex = angle->end(); 4342 return updateOppWinding(startIndex, endIndex); 4343 } 4344 4345 int SkOpSegment::updateWinding(int index, int endIndex) const { 4346 int lesser = SkMin32(index, endIndex); 4347 int winding = windSum(lesser); 4348 if (winding == SK_MinS32) { 4349 return winding; 4350 } 4351 int spanWinding = spanSign(index, endIndex); 4352 if (winding && UseInnerWinding(winding - spanWinding, winding) 4353 && winding != SK_MaxS32) { 4354 winding -= spanWinding; 4355 } 4356 return winding; 4357 } 4358 4359 int SkOpSegment::updateWinding(const SkOpAngle* angle) const { 4360 int startIndex = angle->start(); 4361 int endIndex = angle->end(); 4362 return updateWinding(endIndex, startIndex); 4363 } 4364 4365 int SkOpSegment::updateWindingReverse(int index, int endIndex) const { 4366 int lesser = SkMin32(index, endIndex); 4367 int winding = windSum(lesser); 4368 int spanWinding = spanSign(endIndex, index); 4369 if (winding && UseInnerWindingReverse(winding - spanWinding, winding) 4370 && winding != SK_MaxS32) { 4371 winding -= spanWinding; 4372 } 4373 return winding; 4374 } 4375 4376 int SkOpSegment::updateWindingReverse(const SkOpAngle* angle) const { 4377 int startIndex = angle->start(); 4378 int endIndex = angle->end(); 4379 return updateWindingReverse(endIndex, startIndex); 4380 } 4381 4382 // OPTIMIZATION: does the following also work, and is it any faster? 4383 // return outerWinding * innerWinding > 0 4384 // || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0))) 4385 bool SkOpSegment::UseInnerWinding(int outerWinding, int innerWinding) { 4386 SkASSERT(outerWinding != SK_MaxS32); 4387 SkASSERT(innerWinding != SK_MaxS32); 4388 int absOut = abs(outerWinding); 4389 int absIn = abs(innerWinding); 4390 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; 4391 return result; 4392 } 4393 4394 bool SkOpSegment::UseInnerWindingReverse(int outerWinding, int innerWinding) { 4395 SkASSERT(outerWinding != SK_MaxS32); 4396 SkASSERT(innerWinding != SK_MaxS32); 4397 int absOut = abs(outerWinding); 4398 int absIn = abs(innerWinding); 4399 bool result = absOut == absIn ? true : absOut < absIn; 4400 return result; 4401 } 4402 4403 int SkOpSegment::windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar* dx) const { 4404 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard 4405 return SK_MinS32; 4406 } 4407 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex); 4408 SkASSERT(winding != SK_MinS32); 4409 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex); 4410 #if DEBUG_WINDING_AT_T 4411 SkDebugf("%s id=%d opp=%d tHit=%1.9g t=%1.9g oldWinding=%d windValue=%d", __FUNCTION__, 4412 debugID(), crossOpp, tHit, t(tIndex), winding, windVal); 4413 #endif 4414 // see if a + change in T results in a +/- change in X (compute x'(T)) 4415 *dx = (*CurveSlopeAtT[SkPathOpsVerbToPoints(fVerb)])(fPts, tHit).fX; 4416 if (fVerb > SkPath::kLine_Verb && approximately_zero(*dx)) { 4417 *dx = fPts[2].fX - fPts[1].fX - *dx; 4418 } 4419 if (*dx == 0) { 4420 #if DEBUG_WINDING_AT_T 4421 SkDebugf(" dx=0 winding=SK_MinS32\n"); 4422 #endif 4423 return SK_MinS32; 4424 } 4425 if (windVal < 0) { // reverse sign if opp contour traveled in reverse 4426 *dx = -*dx; 4427 } 4428 if (winding * *dx > 0) { // if same signs, result is negative 4429 winding += *dx > 0 ? -windVal : windVal; 4430 } 4431 #if DEBUG_WINDING_AT_T 4432 SkDebugf(" dx=%c winding=%d\n", *dx > 0 ? '+' : '-', winding); 4433 #endif 4434 return winding; 4435 } 4436 4437 int SkOpSegment::windSum(const SkOpAngle* angle) const { 4438 int start = angle->start(); 4439 int end = angle->end(); 4440 int index = SkMin32(start, end); 4441 return windSum(index); 4442 } 4443 4444 void SkOpSegment::zeroSpan(SkOpSpan* span) { 4445 SkASSERT(span->fWindValue > 0 || span->fOppValue != 0); 4446 span->fWindValue = 0; 4447 span->fOppValue = 0; 4448 if (span->fTiny || span->fSmall) { 4449 return; 4450 } 4451 SkASSERT(!span->fDone); 4452 span->fDone = true; 4453 ++fDoneSpans; 4454 } 4455