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