Simplify.cpp revision 5b6f91643d3ad1bdcdd65329d656f0fc43174be3
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 "Simplify.h" 8 9#undef SkASSERT 10#define SkASSERT(cond) while (!(cond)) { sk_throw(); } 11 12// Terminology: 13// A Path contains one of more Contours 14// A Contour is made up of Segment array 15// A Segment is described by a Verb and a Point array with 2, 3, or 4 points 16// A Verb is one of Line, Quad(ratic), or Cubic 17// A Segment contains a Span array 18// A Span is describes a portion of a Segment using starting and ending T 19// T values range from 0 to 1, where 0 is the first Point in the Segment 20// An Edge is a Segment generated from a Span 21 22// FIXME: remove once debugging is complete 23#ifdef SK_DEBUG 24int gDebugMaxWindSum = SK_MaxS32; 25int gDebugMaxWindValue = SK_MaxS32; 26#endif 27 28#define PRECISE_T_SORT 1 29 30#define DEBUG_UNUSED 0 // set to expose unused functions 31 32#if 1 // set to 1 for multiple thread -- no debugging 33 34const bool gRunTestsInOneThread = false; 35 36#define DEBUG_ACTIVE_SPANS 0 37#define DEBUG_ADD_INTERSECTING_TS 0 38#define DEBUG_ADD_T_PAIR 0 39#define DEBUG_ANGLE 0 40#define DEBUG_CONCIDENT 0 41#define DEBUG_CROSS 0 42#define DEBUG_MARK_DONE 0 43#define DEBUG_PATH_CONSTRUCTION 0 44#define DEBUG_SORT 0 45#define DEBUG_WIND_BUMP 0 46#define DEBUG_WINDING 0 47 48#else 49 50const bool gRunTestsInOneThread = true; 51 52#define DEBUG_ACTIVE_SPANS 0 53#define DEBUG_ADD_INTERSECTING_TS 1 54#define DEBUG_ADD_T_PAIR 1 55#define DEBUG_ANGLE 1 56#define DEBUG_CONCIDENT 1 57#define DEBUG_CROSS 0 58#define DEBUG_MARK_DONE 1 59#define DEBUG_PATH_CONSTRUCTION 1 60#define DEBUG_SORT 1 61#define DEBUG_WIND_BUMP 0 62#define DEBUG_WINDING 1 63 64#endif 65 66#define DEBUG_DUMP (DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | DEBUG_PATH_CONSTRUCTION) 67 68#if DEBUG_DUMP 69static const char* kLVerbStr[] = {"", "line", "quad", "cubic"}; 70// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"}; 71static int gContourID; 72static int gSegmentID; 73#endif 74 75#ifndef DEBUG_TEST 76#define DEBUG_TEST 0 77#endif 78 79#define MAKE_CONST_LINE(line, pts) \ 80 const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}} 81#define MAKE_CONST_QUAD(quad, pts) \ 82 const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \ 83 {pts[2].fX, pts[2].fY}} 84#define MAKE_CONST_CUBIC(cubic, pts) \ 85 const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \ 86 {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}} 87 88static int LineIntersect(const SkPoint a[2], const SkPoint b[2], 89 Intersections& intersections) { 90 MAKE_CONST_LINE(aLine, a); 91 MAKE_CONST_LINE(bLine, b); 92 return intersect(aLine, bLine, intersections.fT[0], intersections.fT[1]); 93} 94 95static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2], 96 Intersections& intersections) { 97 MAKE_CONST_QUAD(aQuad, a); 98 MAKE_CONST_LINE(bLine, b); 99 return intersect(aQuad, bLine, intersections); 100} 101 102static int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2], 103 Intersections& intersections) { 104 MAKE_CONST_CUBIC(aCubic, a); 105 MAKE_CONST_LINE(bLine, b); 106 return intersect(aCubic, bLine, intersections.fT[0], intersections.fT[1]); 107} 108 109static int QuadIntersect(const SkPoint a[3], const SkPoint b[3], 110 Intersections& intersections) { 111 MAKE_CONST_QUAD(aQuad, a); 112 MAKE_CONST_QUAD(bQuad, b); 113#define TRY_QUARTIC_SOLUTION 1 114#if TRY_QUARTIC_SOLUTION 115 intersect2(aQuad, bQuad, intersections); 116#else 117 intersect(aQuad, bQuad, intersections); 118#endif 119 return intersections.fUsed ? intersections.fUsed : intersections.fCoincidentUsed; 120} 121 122static int CubicIntersect(const SkPoint a[4], const SkPoint b[4], 123 Intersections& intersections) { 124 MAKE_CONST_CUBIC(aCubic, a); 125 MAKE_CONST_CUBIC(bCubic, b); 126 intersect(aCubic, bCubic, intersections); 127 return intersections.fUsed; 128} 129 130static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right, 131 SkScalar y, bool flipped, Intersections& intersections) { 132 MAKE_CONST_LINE(aLine, a); 133 return horizontalIntersect(aLine, left, right, y, flipped, intersections); 134} 135 136static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right, 137 SkScalar y, bool flipped, Intersections& intersections) { 138 MAKE_CONST_QUAD(aQuad, a); 139 return horizontalIntersect(aQuad, left, right, y, flipped, intersections); 140} 141 142static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right, 143 SkScalar y, bool flipped, Intersections& intersections) { 144 MAKE_CONST_CUBIC(aCubic, a); 145 return horizontalIntersect(aCubic, left, right, y, flipped, intersections); 146} 147 148static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom, 149 SkScalar x, bool flipped, Intersections& intersections) { 150 MAKE_CONST_LINE(aLine, a); 151 return verticalIntersect(aLine, top, bottom, x, flipped, intersections); 152} 153 154static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom, 155 SkScalar x, bool flipped, Intersections& intersections) { 156 MAKE_CONST_QUAD(aQuad, a); 157 return verticalIntersect(aQuad, top, bottom, x, flipped, intersections); 158} 159 160static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom, 161 SkScalar x, bool flipped, Intersections& intersections) { 162 MAKE_CONST_CUBIC(aCubic, a); 163 return verticalIntersect(aCubic, top, bottom, x, flipped, intersections); 164} 165 166static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar , 167 SkScalar , SkScalar , bool , Intersections& ) = { 168 NULL, 169 VLineIntersect, 170 VQuadIntersect, 171 VCubicIntersect 172}; 173 174static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) { 175 MAKE_CONST_LINE(line, a); 176 double x, y; 177 xy_at_t(line, t, x, y); 178 out->fX = SkDoubleToScalar(x); 179 out->fY = SkDoubleToScalar(y); 180} 181 182static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) { 183 MAKE_CONST_QUAD(quad, a); 184 double x, y; 185 xy_at_t(quad, t, x, y); 186 out->fX = SkDoubleToScalar(x); 187 out->fY = SkDoubleToScalar(y); 188} 189 190static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) { 191 MAKE_CONST_QUAD(quad, a); 192 xy_at_t(quad, t, out->x, out->y); 193} 194 195static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) { 196 MAKE_CONST_CUBIC(cubic, a); 197 double x, y; 198 xy_at_t(cubic, t, x, y); 199 out->fX = SkDoubleToScalar(x); 200 out->fY = SkDoubleToScalar(y); 201} 202 203static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = { 204 NULL, 205 LineXYAtT, 206 QuadXYAtT, 207 CubicXYAtT 208}; 209 210static SkScalar LineXAtT(const SkPoint a[2], double t) { 211 MAKE_CONST_LINE(aLine, a); 212 double x; 213 xy_at_t(aLine, t, x, *(double*) 0); 214 return SkDoubleToScalar(x); 215} 216 217static SkScalar QuadXAtT(const SkPoint a[3], double t) { 218 MAKE_CONST_QUAD(quad, a); 219 double x; 220 xy_at_t(quad, t, x, *(double*) 0); 221 return SkDoubleToScalar(x); 222} 223 224static SkScalar CubicXAtT(const SkPoint a[4], double t) { 225 MAKE_CONST_CUBIC(cubic, a); 226 double x; 227 xy_at_t(cubic, t, x, *(double*) 0); 228 return SkDoubleToScalar(x); 229} 230 231static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = { 232 NULL, 233 LineXAtT, 234 QuadXAtT, 235 CubicXAtT 236}; 237 238static SkScalar LineYAtT(const SkPoint a[2], double t) { 239 MAKE_CONST_LINE(aLine, a); 240 double y; 241 xy_at_t(aLine, t, *(double*) 0, y); 242 return SkDoubleToScalar(y); 243} 244 245static SkScalar QuadYAtT(const SkPoint a[3], double t) { 246 MAKE_CONST_QUAD(quad, a); 247 double y; 248 xy_at_t(quad, t, *(double*) 0, y); 249 return SkDoubleToScalar(y); 250} 251 252static SkScalar CubicYAtT(const SkPoint a[4], double t) { 253 MAKE_CONST_CUBIC(cubic, a); 254 double y; 255 xy_at_t(cubic, t, *(double*) 0, y); 256 return SkDoubleToScalar(y); 257} 258 259static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = { 260 NULL, 261 LineYAtT, 262 QuadYAtT, 263 CubicYAtT 264}; 265 266static SkScalar LineDXAtT(const SkPoint a[2], double ) { 267 return a[1].fX - a[0].fX; 268} 269 270static SkScalar QuadDXAtT(const SkPoint a[3], double t) { 271 MAKE_CONST_QUAD(quad, a); 272 double x; 273 dxdy_at_t(quad, t, x, *(double*) 0); 274 return SkDoubleToScalar(x); 275} 276 277static SkScalar CubicDXAtT(const SkPoint a[4], double t) { 278 MAKE_CONST_CUBIC(cubic, a); 279 double x; 280 dxdy_at_t(cubic, t, x, *(double*) 0); 281 return SkDoubleToScalar(x); 282} 283 284static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = { 285 NULL, 286 LineDXAtT, 287 QuadDXAtT, 288 CubicDXAtT 289}; 290 291static void LineSubDivide(const SkPoint a[2], double startT, double endT, 292 SkPoint sub[2]) { 293 MAKE_CONST_LINE(aLine, a); 294 _Line dst; 295 sub_divide(aLine, startT, endT, dst); 296 sub[0].fX = SkDoubleToScalar(dst[0].x); 297 sub[0].fY = SkDoubleToScalar(dst[0].y); 298 sub[1].fX = SkDoubleToScalar(dst[1].x); 299 sub[1].fY = SkDoubleToScalar(dst[1].y); 300} 301 302static void QuadSubDivide(const SkPoint a[3], double startT, double endT, 303 SkPoint sub[3]) { 304 MAKE_CONST_QUAD(aQuad, a); 305 Quadratic dst; 306 sub_divide(aQuad, startT, endT, dst); 307 sub[0].fX = SkDoubleToScalar(dst[0].x); 308 sub[0].fY = SkDoubleToScalar(dst[0].y); 309 sub[1].fX = SkDoubleToScalar(dst[1].x); 310 sub[1].fY = SkDoubleToScalar(dst[1].y); 311 sub[2].fX = SkDoubleToScalar(dst[2].x); 312 sub[2].fY = SkDoubleToScalar(dst[2].y); 313} 314 315static void CubicSubDivide(const SkPoint a[4], double startT, double endT, 316 SkPoint sub[4]) { 317 MAKE_CONST_CUBIC(aCubic, a); 318 Cubic dst; 319 sub_divide(aCubic, startT, endT, dst); 320 sub[0].fX = SkDoubleToScalar(dst[0].x); 321 sub[0].fY = SkDoubleToScalar(dst[0].y); 322 sub[1].fX = SkDoubleToScalar(dst[1].x); 323 sub[1].fY = SkDoubleToScalar(dst[1].y); 324 sub[2].fX = SkDoubleToScalar(dst[2].x); 325 sub[2].fY = SkDoubleToScalar(dst[2].y); 326 sub[3].fX = SkDoubleToScalar(dst[3].x); 327 sub[3].fY = SkDoubleToScalar(dst[3].y); 328} 329 330static void (* const SegmentSubDivide[])(const SkPoint [], double , double , 331 SkPoint []) = { 332 NULL, 333 LineSubDivide, 334 QuadSubDivide, 335 CubicSubDivide 336}; 337 338static void LineSubDivideHD(const SkPoint a[2], double startT, double endT, 339 _Line sub) { 340 MAKE_CONST_LINE(aLine, a); 341 _Line dst; 342 sub_divide(aLine, startT, endT, dst); 343 sub[0] = dst[0]; 344 sub[1] = dst[1]; 345} 346 347static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT, 348 Quadratic sub) { 349 MAKE_CONST_QUAD(aQuad, a); 350 Quadratic dst; 351 sub_divide(aQuad, startT, endT, dst); 352 sub[0] = dst[0]; 353 sub[1] = dst[1]; 354 sub[2] = dst[2]; 355} 356 357static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT, 358 Cubic sub) { 359 MAKE_CONST_CUBIC(aCubic, a); 360 Cubic dst; 361 sub_divide(aCubic, startT, endT, dst); 362 sub[0] = dst[0]; 363 sub[1] = dst[1]; 364 sub[2] = dst[2]; 365 sub[3] = dst[3]; 366} 367 368#if DEBUG_UNUSED 369static void QuadSubBounds(const SkPoint a[3], double startT, double endT, 370 SkRect& bounds) { 371 SkPoint dst[3]; 372 QuadSubDivide(a, startT, endT, dst); 373 bounds.fLeft = bounds.fRight = dst[0].fX; 374 bounds.fTop = bounds.fBottom = dst[0].fY; 375 for (int index = 1; index < 3; ++index) { 376 bounds.growToInclude(dst[index].fX, dst[index].fY); 377 } 378} 379 380static void CubicSubBounds(const SkPoint a[4], double startT, double endT, 381 SkRect& bounds) { 382 SkPoint dst[4]; 383 CubicSubDivide(a, startT, endT, dst); 384 bounds.fLeft = bounds.fRight = dst[0].fX; 385 bounds.fTop = bounds.fBottom = dst[0].fY; 386 for (int index = 1; index < 4; ++index) { 387 bounds.growToInclude(dst[index].fX, dst[index].fY); 388 } 389} 390#endif 391 392static SkPath::Verb QuadReduceOrder(const SkPoint a[3], 393 SkTDArray<SkPoint>& reducePts) { 394 MAKE_CONST_QUAD(aQuad, a); 395 Quadratic dst; 396 int order = reduceOrder(aQuad, dst); 397 if (order == 2) { // quad became line 398 for (int index = 0; index < order; ++index) { 399 SkPoint* pt = reducePts.append(); 400 pt->fX = SkDoubleToScalar(dst[index].x); 401 pt->fY = SkDoubleToScalar(dst[index].y); 402 } 403 } 404 return (SkPath::Verb) (order - 1); 405} 406 407static SkPath::Verb CubicReduceOrder(const SkPoint a[4], 408 SkTDArray<SkPoint>& reducePts) { 409 MAKE_CONST_CUBIC(aCubic, a); 410 Cubic dst; 411 int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed); 412 if (order == 2 || order == 3) { // cubic became line or quad 413 for (int index = 0; index < order; ++index) { 414 SkPoint* pt = reducePts.append(); 415 pt->fX = SkDoubleToScalar(dst[index].x); 416 pt->fY = SkDoubleToScalar(dst[index].y); 417 } 418 } 419 return (SkPath::Verb) (order - 1); 420} 421 422static bool QuadIsLinear(const SkPoint a[3]) { 423 MAKE_CONST_QUAD(aQuad, a); 424 return isLinear(aQuad, 0, 2); 425} 426 427static bool CubicIsLinear(const SkPoint a[4]) { 428 MAKE_CONST_CUBIC(aCubic, a); 429 return isLinear(aCubic, 0, 3); 430} 431 432static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) { 433 MAKE_CONST_LINE(aLine, a); 434 double x[2]; 435 xy_at_t(aLine, startT, x[0], *(double*) 0); 436 xy_at_t(aLine, endT, x[1], *(double*) 0); 437 return SkMinScalar((float) x[0], (float) x[1]); 438} 439 440static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) { 441 MAKE_CONST_QUAD(aQuad, a); 442 return (float) leftMostT(aQuad, startT, endT); 443} 444 445static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) { 446 MAKE_CONST_CUBIC(aCubic, a); 447 return (float) leftMostT(aCubic, startT, endT); 448} 449 450static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = { 451 NULL, 452 LineLeftMost, 453 QuadLeftMost, 454 CubicLeftMost 455}; 456 457#if 0 // currently unused 458static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2], 459 Intersections& intersections) { 460 MAKE_CONST_QUAD(aQuad, a); 461 MAKE_CONST_LINE(bLine, b); 462 return intersectRay(aQuad, bLine, intersections); 463} 464#endif 465 466static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine, 467 Intersections& intersections) { 468 MAKE_CONST_QUAD(aQuad, a); 469 return intersectRay(aQuad, bLine, intersections); 470} 471 472class Segment; 473 474struct Span { 475 Segment* fOther; 476 mutable SkPoint fPt; // lazily computed as needed 477 double fT; 478 double fOtherT; // value at fOther[fOtherIndex].fT 479 int fOtherIndex; // can't be used during intersection 480 int fWindSum; // accumulated from contours surrounding this one 481 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident 482 int fWindValueOpp; // opposite value, if any (for binary ops with coincidence) 483 bool fDone; // if set, this span to next higher T has been processed 484}; 485 486// sorting angles 487// given angles of {dx dy ddx ddy dddx dddy} sort them 488class Angle { 489public: 490 // FIXME: this is bogus for quads and cubics 491 // if the quads and cubics' line from end pt to ctrl pt are coincident, 492 // there's no obvious way to determine the curve ordering from the 493 // derivatives alone. In particular, if one quadratic's coincident tangent 494 // is longer than the other curve, the final control point can place the 495 // longer curve on either side of the shorter one. 496 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf 497 // may provide some help, but nothing has been figured out yet. 498 499 // start here 500 /*( 501 for quads and cubics, set up a parameterized line (e.g. LineParameters ) 502 for points [0] to [1]. See if point [2] is on that line, or on one side 503 or the other. If it both quads' end points are on the same side, choose 504 the shorter tangent. If the tangents are equal, choose the better second 505 tangent angle 506 507 maybe I could set up LineParameters lazily 508 */ 509 bool operator<(const Angle& rh) const { 510 double y = dy(); 511 double ry = rh.dy(); 512 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ? 513 return y < 0; 514 } 515 double x = dx(); 516 double rx = rh.dx(); 517 if (y == 0 && ry == 0 && x * rx < 0) { 518 return x < rx; 519 } 520 double x_ry = x * ry; 521 double rx_y = rx * y; 522 double cmp = x_ry - rx_y; 523 if (!approximately_zero(cmp)) { 524 return cmp < 0; 525 } 526 if (approximately_zero(x_ry) && approximately_zero(rx_y) 527 && !approximately_zero_squared(cmp)) { 528 return cmp < 0; 529 } 530 // see if either curve can be lengthened and try the tangent compare again 531 if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical 532 && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting 533 Angle longer = *this; 534 Angle rhLonger = rh; 535 if (longer.lengthen() | rhLonger.lengthen()) { 536 return longer < rhLonger; 537 } 538 // what if we extend in the other direction? 539 longer = *this; 540 rhLonger = rh; 541 if (longer.reverseLengthen() | rhLonger.reverseLengthen()) { 542 return longer < rhLonger; 543 } 544 } 545 // at this point, the initial tangent line is coincident 546 if (fSide * rh.fSide <= 0) { 547 // FIXME: running demo will trigger this assertion 548 // (don't know if commenting out will trigger further assertion or not) 549 // commenting it out allows demo to run in release, though 550 // SkASSERT(fSide != rh.fSide); 551 return fSide < rh.fSide; 552 } 553 SkASSERT(fVerb == SkPath::kQuad_Verb); // worry about cubics later 554 SkASSERT(rh.fVerb == SkPath::kQuad_Verb); 555 // FIXME: until I can think of something better, project a ray from the 556 // end of the shorter tangent to midway between the end points 557 // through both curves and use the resulting angle to sort 558 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive 559 double len = fTangent1.normalSquared(); 560 double rlen = rh.fTangent1.normalSquared(); 561 _Line ray; 562 Intersections i, ri; 563 int roots, rroots; 564 bool flip = false; 565 do { 566 const Quadratic& q = (len < rlen) ^ flip ? fQ : rh.fQ; 567 double midX = (q[0].x + q[2].x) / 2; 568 double midY = (q[0].y + q[2].y) / 2; 569 ray[0] = q[1]; 570 ray[1].x = midX; 571 ray[1].y = midY; 572 SkASSERT(ray[0] != ray[1]); 573 roots = QuadRayIntersect(fPts, ray, i); 574 rroots = QuadRayIntersect(rh.fPts, ray, ri); 575 } while ((roots == 0 || rroots == 0) && (flip ^= true)); 576 SkASSERT(roots > 0); 577 SkASSERT(rroots > 0); 578 _Point loc; 579 double best = SK_ScalarInfinity; 580 double dx, dy, dist; 581 int index; 582 for (index = 0; index < roots; ++index) { 583 QuadXYAtT(fPts, i.fT[0][index], &loc); 584 dx = loc.x - ray[0].x; 585 dy = loc.y - ray[0].y; 586 dist = dx * dx + dy * dy; 587 if (best > dist) { 588 best = dist; 589 } 590 } 591 for (index = 0; index < rroots; ++index) { 592 QuadXYAtT(rh.fPts, ri.fT[0][index], &loc); 593 dx = loc.x - ray[0].x; 594 dy = loc.y - ray[0].y; 595 dist = dx * dx + dy * dy; 596 if (best > dist) { 597 return fSide < 0; 598 } 599 } 600 return fSide > 0; 601 } 602 603 double dx() const { 604 return fTangent1.dx(); 605 } 606 607 double dy() const { 608 return fTangent1.dy(); 609 } 610 611 int end() const { 612 return fEnd; 613 } 614 615 bool isHorizontal() const { 616 return dy() == 0 && fVerb == SkPath::kLine_Verb; 617 } 618 619 bool lengthen() { 620 int newEnd = fEnd; 621 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) { 622 fEnd = newEnd; 623 setSpans(); 624 return true; 625 } 626 return false; 627 } 628 629 bool reverseLengthen() { 630 if (fReversed) { 631 return false; 632 } 633 int newEnd = fStart; 634 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) { 635 fEnd = newEnd; 636 fReversed = true; 637 setSpans(); 638 return true; 639 } 640 return false; 641 } 642 643 void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment, 644 int start, int end, const SkTDArray<Span>& spans) { 645 fSegment = segment; 646 fStart = start; 647 fEnd = end; 648 fPts = orig; 649 fVerb = verb; 650 fSpans = &spans; 651 fReversed = false; 652 setSpans(); 653 } 654 655 void setSpans() { 656 double startT = (*fSpans)[fStart].fT; 657 double endT = (*fSpans)[fEnd].fT; 658 switch (fVerb) { 659 case SkPath::kLine_Verb: 660 _Line l; 661 LineSubDivideHD(fPts, startT, endT, l); 662 // OPTIMIZATION: for pure line compares, we never need fTangent1.c 663 fTangent1.lineEndPoints(l); 664 fSide = 0; 665 break; 666 case SkPath::kQuad_Verb: 667 QuadSubDivideHD(fPts, startT, endT, fQ); 668 fTangent1.quadEndPoints(fQ, 0, 1); 669 fSide = -fTangent1.pointDistance(fQ[2]); // not normalized -- compare sign only 670 break; 671 case SkPath::kCubic_Verb: 672 Cubic c; 673 CubicSubDivideHD(fPts, startT, endT, c); 674 fTangent1.cubicEndPoints(c, 0, 1); 675 fSide = -fTangent1.pointDistance(c[2]); // not normalized -- compare sign only 676 break; 677 default: 678 SkASSERT(0); 679 } 680 } 681 682 Segment* segment() const { 683 return const_cast<Segment*>(fSegment); 684 } 685 686 int sign() const { 687 return SkSign32(fStart - fEnd); 688 } 689 690 int start() const { 691 return fStart; 692 } 693 694#if DEBUG_ANGLE 695 const SkPoint* pts() const { 696 return fPts; 697 } 698 699 const SkTDArray<Span>* spans() const { 700 return fSpans; 701 } 702 703 SkPath::Verb verb() const { 704 return fVerb; 705 } 706 707 void debugShow(const SkPoint& a) const { 708 SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide); 709 } 710#endif 711 712private: 713 const SkPoint* fPts; 714 Quadratic fQ; 715 SkPath::Verb fVerb; 716 double fSide; 717 LineParameters fTangent1; 718 const SkTDArray<Span>* fSpans; 719 const Segment* fSegment; 720 int fStart; 721 int fEnd; 722 bool fReversed; 723}; 724 725static void sortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) { 726 int angleCount = angles.count(); 727 int angleIndex; 728 angleList.setReserve(angleCount); 729 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { 730 *angleList.append() = &angles[angleIndex]; 731 } 732 QSort<Angle>(angleList.begin(), angleList.end() - 1); 733} 734 735// Bounds, unlike Rect, does not consider a line to be empty. 736struct Bounds : public SkRect { 737 static bool Intersects(const Bounds& a, const Bounds& b) { 738 return a.fLeft <= b.fRight && b.fLeft <= a.fRight && 739 a.fTop <= b.fBottom && b.fTop <= a.fBottom; 740 } 741 742 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { 743 if (left < fLeft) { 744 fLeft = left; 745 } 746 if (top < fTop) { 747 fTop = top; 748 } 749 if (right > fRight) { 750 fRight = right; 751 } 752 if (bottom > fBottom) { 753 fBottom = bottom; 754 } 755 } 756 757 void add(const Bounds& toAdd) { 758 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom); 759 } 760 761 bool isEmpty() { 762 return fLeft > fRight || fTop > fBottom 763 || (fLeft == fRight && fTop == fBottom) 764 || isnan(fLeft) || isnan(fRight) 765 || isnan(fTop) || isnan(fBottom); 766 } 767 768 void setCubicBounds(const SkPoint a[4]) { 769 _Rect dRect; 770 MAKE_CONST_CUBIC(cubic, a); 771 dRect.setBounds(cubic); 772 set((float) dRect.left, (float) dRect.top, (float) dRect.right, 773 (float) dRect.bottom); 774 } 775 776 void setQuadBounds(const SkPoint a[3]) { 777 MAKE_CONST_QUAD(quad, a); 778 _Rect dRect; 779 dRect.setBounds(quad); 780 set((float) dRect.left, (float) dRect.top, (float) dRect.right, 781 (float) dRect.bottom); 782 } 783}; 784 785static bool useInnerWinding(int outerWinding, int innerWinding) { 786 SkASSERT(outerWinding != innerWinding); 787 int absOut = abs(outerWinding); 788 int absIn = abs(innerWinding); 789 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; 790 if (outerWinding * innerWinding < 0) { 791#if DEBUG_WINDING 792 SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__, 793 outerWinding, innerWinding, result ? "true" : "false"); 794#endif 795 } 796 return result; 797} 798 799static const bool opLookup[][2][2] = { 800 // ==0 !=0 801 // b a b a 802 {{true , false}, {false, true }}, // a - b 803 {{false, false}, {true , true }}, // a & b 804 {{true , true }, {false, false}}, // a | b 805 {{true , true }, {true , true }}, // a ^ b 806}; 807 808static bool activeOp(bool angleIsOp, int otherNonZero, ShapeOp op) { 809 return opLookup[op][otherNonZero][angleIsOp]; 810} 811 812class Segment { 813public: 814 Segment() { 815#if DEBUG_DUMP 816 fID = ++gSegmentID; 817#endif 818 } 819 820 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) const { 821 if (activeAngleInner(index, done, angles)) { 822 return true; 823 } 824 double referenceT = fTs[index].fT; 825 int lesser = index; 826 while (--lesser >= 0 && approximately_negative(referenceT - fTs[lesser].fT)) { 827 if (activeAngleOther(lesser, done, angles)) { 828 return true; 829 } 830 } 831 do { 832 if (activeAngleOther(index, done, angles)) { 833 return true; 834 } 835 } while (++index < fTs.count() && approximately_negative(fTs[index].fT - referenceT)); 836 return false; 837 } 838 839 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) const { 840 Span* span = &fTs[index]; 841 Segment* other = span->fOther; 842 int oIndex = span->fOtherIndex; 843 return other->activeAngleInner(oIndex, done, angles); 844 } 845 846 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) const { 847 int next = nextSpan(index, 1); 848 if (next > 0) { 849 const Span& upSpan = fTs[index]; 850 if (upSpan.fWindValue) { 851 addAngle(angles, index, next); 852 if (upSpan.fDone) { 853 done++; 854 } else if (upSpan.fWindSum != SK_MinS32) { 855 return true; 856 } 857 } 858 } 859 int prev = nextSpan(index, -1); 860 // edge leading into junction 861 if (prev >= 0) { 862 const Span& downSpan = fTs[prev]; 863 if (downSpan.fWindValue) { 864 addAngle(angles, index, prev); 865 if (downSpan.fDone) { 866 done++; 867 } else if (downSpan.fWindSum != SK_MinS32) { 868 return true; 869 } 870 } 871 } 872 return false; 873 } 874 875 SkScalar activeTop() const { 876 SkASSERT(!done()); 877 int count = fTs.count(); 878 SkScalar result = SK_ScalarMax; 879 bool lastDone = true; 880 for (int index = 0; index < count; ++index) { 881 bool done = fTs[index].fDone; 882 if (!done || !lastDone) { 883 SkScalar y = yAtT(index); 884 if (result > y) { 885 result = y; 886 } 887 } 888 lastDone = done; 889 } 890 SkASSERT(result < SK_ScalarMax); 891 return result; 892 } 893 894 void addAngle(SkTDArray<Angle>& angles, int start, int end) const { 895 SkASSERT(start != end); 896 Angle* angle = angles.append(); 897#if DEBUG_ANGLE 898 if (angles.count() > 1) { 899 SkPoint angle0Pt, newPt; 900 (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(), 901 (*angles[0].spans())[angles[0].start()].fT, &angle0Pt); 902 (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt); 903 SkASSERT(approximately_equal(angle0Pt.fX, newPt.fX)); 904 SkASSERT(approximately_equal(angle0Pt.fY, newPt.fY)); 905 } 906#endif 907 angle->set(fPts, fVerb, this, start, end, fTs); 908 } 909 910 void addCancelOutsides(double tStart, double oStart, Segment& other, 911 double oEnd) { 912 int tIndex = -1; 913 int tCount = fTs.count(); 914 int oIndex = -1; 915 int oCount = other.fTs.count(); 916 do { 917 ++tIndex; 918 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount); 919 int tIndexStart = tIndex; 920 do { 921 ++oIndex; 922 } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount); 923 int oIndexStart = oIndex; 924 double nextT; 925 do { 926 nextT = fTs[++tIndex].fT; 927 } while (nextT < 1 && approximately_negative(nextT - tStart)); 928 double oNextT; 929 do { 930 oNextT = other.fTs[++oIndex].fT; 931 } while (oNextT < 1 && approximately_negative(oNextT - oStart)); 932 // at this point, spans before and after are at: 933 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex] 934 // if tIndexStart == 0, no prior span 935 // if nextT == 1, no following span 936 937 // advance the span with zero winding 938 // if the following span exists (not past the end, non-zero winding) 939 // connect the two edges 940 if (!fTs[tIndexStart].fWindValue) { 941 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) { 942 #if DEBUG_CONCIDENT 943 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", 944 __FUNCTION__, fID, other.fID, tIndexStart - 1, 945 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX, 946 xyAtT(tIndexStart).fY); 947 #endif 948 addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false); 949 } 950 if (nextT < 1 && fTs[tIndex].fWindValue) { 951 #if DEBUG_CONCIDENT 952 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", 953 __FUNCTION__, fID, other.fID, tIndex, 954 fTs[tIndex].fT, xyAtT(tIndex).fX, 955 xyAtT(tIndex).fY); 956 #endif 957 addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false); 958 } 959 } else { 960 SkASSERT(!other.fTs[oIndexStart].fWindValue); 961 if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) { 962 #if DEBUG_CONCIDENT 963 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", 964 __FUNCTION__, fID, other.fID, oIndexStart - 1, 965 other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX, 966 other.xyAtT(oIndexStart).fY); 967 other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT); 968 #endif 969 } 970 if (oNextT < 1 && other.fTs[oIndex].fWindValue) { 971 #if DEBUG_CONCIDENT 972 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", 973 __FUNCTION__, fID, other.fID, oIndex, 974 other.fTs[oIndex].fT, other.xyAtT(oIndex).fX, 975 other.xyAtT(oIndex).fY); 976 other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT); 977 #endif 978 } 979 } 980 } 981 982 void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other, 983 double oEnd) { 984 // walk this to outsideTs[0] 985 // walk other to outsideTs[1] 986 // if either is > 0, add a pointer to the other, copying adjacent winding 987 int tIndex = -1; 988 int oIndex = -1; 989 double tStart = outsideTs[0]; 990 double oStart = outsideTs[1]; 991 do { 992 ++tIndex; 993 } while (!approximately_negative(tStart - fTs[tIndex].fT)); 994 do { 995 ++oIndex; 996 } while (!approximately_negative(oStart - other.fTs[oIndex].fT)); 997 if (tIndex > 0 || oIndex > 0) { 998 addTPair(tStart, other, oStart, false); 999 } 1000 tStart = fTs[tIndex].fT; 1001 oStart = other.fTs[oIndex].fT; 1002 do { 1003 double nextT; 1004 do { 1005 nextT = fTs[++tIndex].fT; 1006 } while (approximately_negative(nextT - tStart)); 1007 tStart = nextT; 1008 do { 1009 nextT = other.fTs[++oIndex].fT; 1010 } while (approximately_negative(nextT - oStart)); 1011 oStart = nextT; 1012 if (tStart == 1 && oStart == 1) { 1013 break; 1014 } 1015 addTPair(tStart, other, oStart, false); 1016 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart)); 1017 } 1018 1019 void addCubic(const SkPoint pts[4], bool operand) { 1020 init(pts, SkPath::kCubic_Verb, operand); 1021 fBounds.setCubicBounds(pts); 1022 } 1023 1024 // FIXME: this needs to defer add for aligned consecutive line segments 1025 SkPoint addCurveTo(int start, int end, SkPath& path, bool active) { 1026 SkPoint edge[4]; 1027 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end) 1028 (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge); 1029 if (active) { 1030 #if DEBUG_PATH_CONSTRUCTION 1031 SkDebugf("path.%sTo(%1.9g,%1.9g", 1032 kLVerbStr[fVerb], edge[1].fX, edge[1].fY); 1033 if (fVerb > 1) { 1034 SkDebugf(", %1.9g,%1.9g", edge[2].fX, edge[2].fY); 1035 } 1036 if (fVerb > 2) { 1037 SkDebugf(", %1.9g,%1.9g", edge[3].fX, edge[3].fY); 1038 } 1039 SkDebugf(");\n"); 1040 #endif 1041 switch (fVerb) { 1042 case SkPath::kLine_Verb: 1043 path.lineTo(edge[1].fX, edge[1].fY); 1044 break; 1045 case SkPath::kQuad_Verb: 1046 path.quadTo(edge[1].fX, edge[1].fY, edge[2].fX, edge[2].fY); 1047 break; 1048 case SkPath::kCubic_Verb: 1049 path.cubicTo(edge[1].fX, edge[1].fY, edge[2].fX, edge[2].fY, 1050 edge[3].fX, edge[3].fY); 1051 break; 1052 default: 1053 SkASSERT(0); 1054 } 1055 } 1056 return edge[fVerb]; 1057 } 1058 1059 void addLine(const SkPoint pts[2], bool operand) { 1060 init(pts, SkPath::kLine_Verb, operand); 1061 fBounds.set(pts, 2); 1062 } 1063 1064 const SkPoint& addMoveTo(int tIndex, SkPath& path, bool active) { 1065 const SkPoint& pt = xyAtT(tIndex); 1066 if (active) { 1067 #if DEBUG_PATH_CONSTRUCTION 1068 SkDebugf("path.moveTo(%1.9g, %1.9g);\n", pt.fX, pt.fY); 1069 #endif 1070 path.moveTo(pt.fX, pt.fY); 1071 } 1072 return pt; 1073 } 1074 1075 // add 2 to edge or out of range values to get T extremes 1076 void addOtherT(int index, double otherT, int otherIndex) { 1077 Span& span = fTs[index]; 1078 span.fOtherT = otherT; 1079 span.fOtherIndex = otherIndex; 1080 } 1081 1082 void addQuad(const SkPoint pts[3], bool operand) { 1083 init(pts, SkPath::kQuad_Verb, operand); 1084 fBounds.setQuadBounds(pts); 1085 } 1086 1087 // Defer all coincident edge processing until 1088 // after normal intersections have been computed 1089 1090// no need to be tricky; insert in normal T order 1091// resolve overlapping ts when considering coincidence later 1092 1093 // add non-coincident intersection. Resulting edges are sorted in T. 1094 int addT(double newT, Segment* other) { 1095 // FIXME: in the pathological case where there is a ton of intercepts, 1096 // binary search? 1097 int insertedAt = -1; 1098 size_t tCount = fTs.count(); 1099 // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect) 1100 if (approximately_less_than_zero(newT)) { 1101 newT = 0; 1102 } 1103 if (approximately_greater_than_one(newT)) { 1104 newT = 1; 1105 } 1106 for (size_t index = 0; index < tCount; ++index) { 1107 // OPTIMIZATION: if there are three or more identical Ts, then 1108 // the fourth and following could be further insertion-sorted so 1109 // that all the edges are clockwise or counterclockwise. 1110 // This could later limit segment tests to the two adjacent 1111 // neighbors, although it doesn't help with determining which 1112 // circular direction to go in. 1113 if (newT < fTs[index].fT) { 1114 insertedAt = index; 1115 break; 1116 } 1117 } 1118 Span* span; 1119 if (insertedAt >= 0) { 1120 span = fTs.insert(insertedAt); 1121 } else { 1122 insertedAt = tCount; 1123 span = fTs.append(); 1124 } 1125 span->fT = newT; 1126 span->fOther = other; 1127 span->fPt.fX = SK_ScalarNaN; 1128 span->fWindSum = SK_MinS32; 1129 span->fWindValue = 1; 1130 span->fWindValueOpp = 0; 1131 if ((span->fDone = newT == 1)) { 1132 ++fDoneSpans; 1133 } 1134 return insertedAt; 1135 } 1136 1137 // set spans from start to end to decrement by one 1138 // note this walks other backwards 1139 // FIMXE: there's probably an edge case that can be constructed where 1140 // two span in one segment are separated by float epsilon on one span but 1141 // not the other, if one segment is very small. For this 1142 // case the counts asserted below may or may not be enough to separate the 1143 // spans. Even if the counts work out, what if the spans aren't correctly 1144 // sorted? It feels better in such a case to match the span's other span 1145 // pointer since both coincident segments must contain the same spans. 1146 void addTCancel(double startT, double endT, Segment& other, 1147 double oStartT, double oEndT) { 1148 SkASSERT(!approximately_negative(endT - startT)); 1149 SkASSERT(!approximately_negative(oEndT - oStartT)); 1150 bool binary = fOperand != other.fOperand; 1151 int index = 0; 1152 while (!approximately_negative(startT - fTs[index].fT)) { 1153 ++index; 1154 } 1155 int oIndex = other.fTs.count(); 1156 while (approximately_positive(other.fTs[--oIndex].fT - oEndT)) 1157 ; 1158 double tRatio = (oEndT - oStartT) / (endT - startT); 1159 Span* test = &fTs[index]; 1160 Span* oTest = &other.fTs[oIndex]; 1161 SkTDArray<double> outsideTs; 1162 SkTDArray<double> oOutsideTs; 1163 do { 1164 bool decrement = test->fWindValue && oTest->fWindValue; 1165 bool track = test->fWindValue || oTest->fWindValue; 1166 double testT = test->fT; 1167 double oTestT = oTest->fT; 1168 Span* span = test; 1169 do { 1170 if (decrement) { 1171 if (binary) { 1172 --(span->fWindValueOpp); 1173 } else { 1174 decrementSpan(span); 1175 } 1176 } else if (track && span->fT < 1 && oTestT < 1) { 1177 TrackOutside(outsideTs, span->fT, oTestT); 1178 } 1179 span = &fTs[++index]; 1180 } while (approximately_negative(span->fT - testT)); 1181 Span* oSpan = oTest; 1182 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio; 1183 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio; 1184 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue); 1185 while (approximately_negative(otherTMatchStart - oSpan->fT) 1186 && !approximately_negative(otherTMatchEnd - oSpan->fT)) { 1187 #ifdef SK_DEBUG 1188 SkASSERT(originalWindValue == oSpan->fWindValue); 1189 #endif 1190 if (decrement) { 1191 other.decrementSpan(oSpan); 1192 } else if (track && oSpan->fT < 1 && testT < 1) { 1193 TrackOutside(oOutsideTs, oSpan->fT, testT); 1194 } 1195 if (!oIndex) { 1196 break; 1197 } 1198 oSpan = &other.fTs[--oIndex]; 1199 } 1200 test = span; 1201 oTest = oSpan; 1202 } while (!approximately_negative(endT - test->fT)); 1203 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT)); 1204 // FIXME: determine if canceled edges need outside ts added 1205 if (!done() && outsideTs.count()) { 1206 double tStart = outsideTs[0]; 1207 double oStart = outsideTs[1]; 1208 addCancelOutsides(tStart, oStart, other, oEndT); 1209 int count = outsideTs.count(); 1210 if (count > 2) { 1211 double tStart = outsideTs[count - 2]; 1212 double oStart = outsideTs[count - 1]; 1213 addCancelOutsides(tStart, oStart, other, oEndT); 1214 } 1215 } 1216 if (!other.done() && oOutsideTs.count()) { 1217 double tStart = oOutsideTs[0]; 1218 double oStart = oOutsideTs[1]; 1219 other.addCancelOutsides(tStart, oStart, *this, endT); 1220 } 1221 } 1222 1223 // set spans from start to end to increment the greater by one and decrement 1224 // the lesser 1225 void addTCoincident(const bool isXor, double startT, double endT, 1226 Segment& other, double oStartT, double oEndT) { 1227 SkASSERT(!approximately_negative(endT - startT)); 1228 SkASSERT(!approximately_negative(oEndT - oStartT)); 1229 bool binary = fOperand != other.fOperand; 1230 int index = 0; 1231 while (!approximately_negative(startT - fTs[index].fT)) { 1232 ++index; 1233 } 1234 int oIndex = 0; 1235 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) { 1236 ++oIndex; 1237 } 1238 double tRatio = (oEndT - oStartT) / (endT - startT); 1239 Span* test = &fTs[index]; 1240 Span* oTest = &other.fTs[oIndex]; 1241 SkTDArray<double> outsideTs; 1242 SkTDArray<double> xOutsideTs; 1243 SkTDArray<double> oOutsideTs; 1244 SkTDArray<double> oxOutsideTs; 1245 do { 1246 bool transfer = test->fWindValue && oTest->fWindValue; 1247 bool decrementThis = (test->fWindValue < oTest->fWindValue) & !isXor; 1248 bool decrementOther = (test->fWindValue >= oTest->fWindValue) & !isXor; 1249 Span* end = test; 1250 double startT = end->fT; 1251 int startIndex = index; 1252 double oStartT = oTest->fT; 1253 int oStartIndex = oIndex; 1254 do { 1255 if (transfer) { 1256 if (decrementOther) { 1257 #ifdef SK_DEBUG 1258 SkASSERT(abs(end->fWindValue) < gDebugMaxWindValue); 1259 #endif 1260 if (binary) { 1261 ++(end->fWindValueOpp); 1262 } else { 1263 ++(end->fWindValue); 1264 } 1265 } else if (decrementSpan(end)) { 1266 TrackOutside(outsideTs, end->fT, oStartT); 1267 } 1268 } else if (oTest->fWindValue) { 1269 SkASSERT(!decrementOther); 1270 if (startIndex > 0 && fTs[startIndex - 1].fWindValue) { 1271 TrackOutside(xOutsideTs, end->fT, oStartT); 1272 } 1273 } 1274 end = &fTs[++index]; 1275 } while (approximately_negative(end->fT - test->fT)); 1276 // because of the order in which coincidences are resolved, this and other 1277 // may not have the same intermediate points. Compute the corresponding 1278 // intermediate T values (using this as the master, other as the follower) 1279 // and walk other conditionally -- hoping that it catches up in the end 1280 double otherTMatch = (test->fT - startT) * tRatio + oStartT; 1281 Span* oEnd = oTest; 1282 while (!approximately_negative(oEndT - oEnd->fT) && approximately_negative(oEnd->fT - otherTMatch)) { 1283 if (transfer) { 1284 if (decrementThis) { 1285 #ifdef SK_DEBUG 1286 SkASSERT(abs(oEnd->fWindValue) < gDebugMaxWindValue); 1287 #endif 1288 if (binary) { 1289 ++(oEnd->fWindValueOpp); 1290 } else { 1291 ++(oEnd->fWindValue); 1292 } 1293 } else if (other.decrementSpan(oEnd)) { 1294 TrackOutside(oOutsideTs, oEnd->fT, startT); 1295 } 1296 } else if (test->fWindValue) { 1297 SkASSERT(!decrementOther); 1298 if (oStartIndex > 0 && other.fTs[oStartIndex - 1].fWindValue) { 1299 SkASSERT(0); // track for later? 1300 } 1301 } 1302 oEnd = &other.fTs[++oIndex]; 1303 } 1304 test = end; 1305 oTest = oEnd; 1306 } while (!approximately_negative(endT - test->fT)); 1307 SkASSERT(approximately_negative(oTest->fT - oEndT)); 1308 SkASSERT(approximately_negative(oEndT - oTest->fT)); 1309 if (!done()) { 1310 if (outsideTs.count()) { 1311 addCoinOutsides(outsideTs, other, oEndT); 1312 } 1313 if (xOutsideTs.count()) { 1314 addCoinOutsides(xOutsideTs, other, oEndT); 1315 } 1316 } 1317 if (!other.done() && oOutsideTs.count()) { 1318 other.addCoinOutsides(oOutsideTs, *this, endT); 1319 } 1320 } 1321 1322 // FIXME: this doesn't prevent the same span from being added twice 1323 // fix in caller, assert here? 1324 void addTPair(double t, Segment& other, double otherT, bool borrowWind) { 1325 int tCount = fTs.count(); 1326 for (int tIndex = 0; tIndex < tCount; ++tIndex) { 1327 const Span& span = fTs[tIndex]; 1328 if (!approximately_negative(span.fT - t)) { 1329 break; 1330 } 1331 if (approximately_negative(span.fT - t) && span.fOther == &other 1332 && approximately_equal(span.fOtherT, otherT)) { 1333#if DEBUG_ADD_T_PAIR 1334 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n", 1335 __FUNCTION__, fID, t, other.fID, otherT); 1336#endif 1337 return; 1338 } 1339 } 1340#if DEBUG_ADD_T_PAIR 1341 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n", 1342 __FUNCTION__, fID, t, other.fID, otherT); 1343#endif 1344 int insertedAt = addT(t, &other); 1345 int otherInsertedAt = other.addT(otherT, this); 1346 addOtherT(insertedAt, otherT, otherInsertedAt); 1347 other.addOtherT(otherInsertedAt, t, insertedAt); 1348 matchWindingValue(insertedAt, t, borrowWind); 1349 other.matchWindingValue(otherInsertedAt, otherT, borrowWind); 1350 } 1351 1352 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const { 1353 // add edge leading into junction 1354 if (fTs[SkMin32(end, start)].fWindValue > 0) { 1355 addAngle(angles, end, start); 1356 } 1357 // add edge leading away from junction 1358 int step = SkSign32(end - start); 1359 int tIndex = nextExactSpan(end, step); 1360 if (tIndex >= 0 && fTs[SkMin32(end, tIndex)].fWindValue > 0) { 1361 addAngle(angles, end, tIndex); 1362 } 1363 } 1364 1365 const Bounds& bounds() const { 1366 return fBounds; 1367 } 1368 1369 void buildAngles(int index, SkTDArray<Angle>& angles) const { 1370 double referenceT = fTs[index].fT; 1371 int lesser = index; 1372 #if PRECISE_T_SORT 1373 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 1374 buildAnglesInner(lesser, angles); 1375 } 1376 do { 1377 buildAnglesInner(index, angles); 1378 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT)); 1379 #else 1380 while (--lesser >= 0 && approximately_negative(referenceT - fTs[lesser].fT)) { 1381 buildAnglesInner(lesser, angles); 1382 } 1383 do { 1384 buildAnglesInner(index, angles); 1385 } while (++index < fTs.count() && approximately_negative(fTs[index].fT - referenceT)); 1386 #endif 1387 } 1388 1389 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const { 1390 Span* span = &fTs[index]; 1391 Segment* other = span->fOther; 1392 // if there is only one live crossing, and no coincidence, continue 1393 // in the same direction 1394 // if there is coincidence, the only choice may be to reverse direction 1395 // find edge on either side of intersection 1396 int oIndex = span->fOtherIndex; 1397 // if done == -1, prior span has already been processed 1398 int step = 1; 1399 #if PRECISE_T_SORT 1400 int next = other->nextExactSpan(oIndex, step); 1401 #else 1402 int next = other->nextSpan(oIndex, step); 1403 #endif 1404 if (next < 0) { 1405 step = -step; 1406 #if PRECISE_T_SORT 1407 next = other->nextExactSpan(oIndex, step); 1408 #else 1409 next = other->nextSpan(oIndex, step); 1410 #endif 1411 } 1412 // add candidate into and away from junction 1413 other->addTwoAngles(next, oIndex, angles); 1414 } 1415 1416 // figure out if the segment's ascending T goes clockwise or not 1417 // not enough context to write this as shown 1418 // instead, add all segments meeting at the top 1419 // sort them using buildAngleList 1420 // find the first in the sort 1421 // see if ascendingT goes to top 1422 bool clockwise(int /* tIndex */) const { 1423 SkASSERT(0); // incomplete 1424 return false; 1425 } 1426 1427 // FIXME may not need this at all 1428 // FIXME once I figure out the logic, merge this and too close to call 1429 // NOTE not sure if tiny triangles can ever form at the edge, so until we 1430 // see one, only worry about triangles that happen away from 0 and 1 1431 void collapseTriangles(bool isXor) { 1432 if (fTs.count() < 3) { // require t=0, x, 1 at minimum 1433 return; 1434 } 1435 int lastIndex = 1; 1436 double lastT; 1437 while (approximately_less_than_zero((lastT = fTs[lastIndex].fT))) { 1438 ++lastIndex; 1439 } 1440 if (approximately_greater_than_one(lastT)) { 1441 return; 1442 } 1443 int matchIndex = lastIndex; 1444 do { 1445 Span& match = fTs[++matchIndex]; 1446 double matchT = match.fT; 1447 if (approximately_greater_than_one(matchT)) { 1448 return; 1449 } 1450 if (matchT == lastT) { 1451 goto nextSpan; 1452 } 1453 if (approximately_negative(matchT - lastT)) { 1454 Span& last = fTs[lastIndex]; 1455 Segment* lOther = last.fOther; 1456 double lT = last.fOtherT; 1457 if (approximately_less_than_zero(lT) || approximately_greater_than_one(lT)) { 1458 goto nextSpan; 1459 } 1460 Segment* mOther = match.fOther; 1461 double mT = match.fOtherT; 1462 if (approximately_less_than_zero(mT) || approximately_greater_than_one(mT)) { 1463 goto nextSpan; 1464 } 1465 // add new point to connect adjacent spurs 1466 int count = lOther->fTs.count(); 1467 for (int index = 0; index < count; ++index) { 1468 Span& span = lOther->fTs[index]; 1469 if (span.fOther == mOther && approximately_zero(span.fOtherT - mT)) { 1470 goto nextSpan; 1471 } 1472 } 1473 mOther->addTPair(mT, *lOther, lT, false); 1474 // FIXME ? this could go on to detect that spans on mOther, lOther are now coincident 1475 } 1476 nextSpan: 1477 lastIndex = matchIndex; 1478 lastT = matchT; 1479 } while (true); 1480 } 1481 1482 int computeSum(int startIndex, int endIndex) { 1483 SkTDArray<Angle> angles; 1484 addTwoAngles(startIndex, endIndex, angles); 1485 buildAngles(endIndex, angles); 1486 // OPTIMIZATION: check all angles to see if any have computed wind sum 1487 // before sorting (early exit if none) 1488 SkTDArray<Angle*> sorted; 1489 sortAngles(angles, sorted); 1490#if DEBUG_SORT 1491 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0); 1492#endif 1493 int angleCount = angles.count(); 1494 const Angle* angle; 1495 const Segment* base; 1496 int winding; 1497 int firstIndex = 0; 1498 do { 1499 angle = sorted[firstIndex]; 1500 base = angle->segment(); 1501 winding = base->windSum(angle); 1502 if (winding != SK_MinS32) { 1503 break; 1504 } 1505 if (++firstIndex == angleCount) { 1506 return SK_MinS32; 1507 } 1508 } while (true); 1509 // turn winding into contourWinding 1510 int spanWinding = base->spanSign(angle); 1511 bool inner = useInnerWinding(winding + spanWinding, winding); 1512 #if DEBUG_WINDING 1513 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__, 1514 spanWinding, winding, angle->sign(), inner, 1515 inner ? winding + spanWinding : winding); 1516 #endif 1517 if (inner) { 1518 winding += spanWinding; 1519 } 1520 #if DEBUG_SORT 1521 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding); 1522 #endif 1523 int nextIndex = firstIndex + 1; 1524 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; 1525 winding -= base->spanSign(angle); 1526 do { 1527 if (nextIndex == angleCount) { 1528 nextIndex = 0; 1529 } 1530 angle = sorted[nextIndex]; 1531 Segment* segment = angle->segment(); 1532 int maxWinding = winding; 1533 winding -= segment->spanSign(angle); 1534 if (segment->windSum(angle) == SK_MinS32) { 1535 if (useInnerWinding(maxWinding, winding)) { 1536 maxWinding = winding; 1537 } 1538 segment->markAndChaseWinding(angle, maxWinding); 1539 } 1540 } while (++nextIndex != lastIndex); 1541 return windSum(SkMin32(startIndex, endIndex)); 1542 } 1543 1544 int crossedSpan(const SkPoint& basePt, SkScalar& bestY, double& hitT) const { 1545 int bestT = -1; 1546 SkScalar top = bounds().fTop; 1547 SkScalar bottom = bounds().fBottom; 1548 int end = 0; 1549 do { 1550 int start = end; 1551 end = nextSpan(start, 1); 1552 if (fTs[start].fWindValue == 0) { 1553 continue; 1554 } 1555 SkPoint edge[4]; 1556 double startT = fTs[start].fT; 1557 double endT = fTs[end].fT; 1558 (*SegmentSubDivide[fVerb])(fPts, startT, endT, edge); 1559 // intersect ray starting at basePt with edge 1560 Intersections intersections; 1561 // FIXME: always use original and limit results to T values within 1562 // start t and end t. 1563 // OPTIMIZE: use specialty function that intersects ray with curve, 1564 // returning t values only for curve (we don't care about t on ray) 1565 int pts = (*VSegmentIntersect[fVerb])(edge, top, bottom, basePt.fX, 1566 false, intersections); 1567 if (pts == 0) { 1568 continue; 1569 } 1570 if (pts > 1 && fVerb == SkPath::kLine_Verb) { 1571 // if the intersection is edge on, wait for another one 1572 continue; 1573 } 1574 for (int index = 0; index < pts; ++index) { 1575 SkPoint pt; 1576 double foundT = intersections.fT[0][index]; 1577 double testT = startT + (endT - startT) * foundT; 1578 (*SegmentXYAtT[fVerb])(fPts, testT, &pt); 1579 if (bestY < pt.fY && pt.fY < basePt.fY) { 1580 if (fVerb > SkPath::kLine_Verb 1581 && !approximately_less_than_zero(foundT) 1582 && !approximately_greater_than_one(foundT)) { 1583 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, testT); 1584 if (approximately_zero(dx)) { 1585 continue; 1586 } 1587 } 1588 bestY = pt.fY; 1589 bestT = foundT < 1 ? start : end; 1590 hitT = testT; 1591 } 1592 } 1593 } while (fTs[end].fT != 1); 1594 return bestT; 1595 } 1596 1597 bool crossedSpanHalves(const SkPoint& basePt, bool leftHalf, bool rightHalf) { 1598 // if a segment is connected to this one, consider it crossing 1599 int tIndex; 1600 if (fPts[0].fX == basePt.fX) { 1601 tIndex = 0; 1602 do { 1603 const Span& sSpan = fTs[tIndex]; 1604 const Segment* sOther = sSpan.fOther; 1605 if (!sOther->fTs[sSpan.fOtherIndex].fWindValue) { 1606 continue; 1607 } 1608 if (leftHalf ? sOther->fBounds.fLeft < basePt.fX 1609 : sOther->fBounds.fRight > basePt.fX) { 1610 return true; 1611 } 1612 } while (fTs[++tIndex].fT == 0); 1613 } 1614 if (fPts[fVerb].fX == basePt.fX) { 1615 tIndex = fTs.count() - 1; 1616 do { 1617 const Span& eSpan = fTs[tIndex]; 1618 const Segment* eOther = eSpan.fOther; 1619 if (!eOther->fTs[eSpan.fOtherIndex].fWindValue) { 1620 continue; 1621 } 1622 if (leftHalf ? eOther->fBounds.fLeft < basePt.fX 1623 : eOther->fBounds.fRight > basePt.fX) { 1624 return true; 1625 } 1626 } while (fTs[--tIndex].fT == 1); 1627 } 1628 return false; 1629 } 1630 1631 bool decrementSpan(Span* span) { 1632 SkASSERT(span->fWindValue > 0); 1633 if (--(span->fWindValue) == 0) { 1634 span->fDone = true; 1635 ++fDoneSpans; 1636 return true; 1637 } 1638 return false; 1639 } 1640 1641 bool done() const { 1642 SkASSERT(fDoneSpans <= fTs.count()); 1643 return fDoneSpans == fTs.count(); 1644 } 1645 1646 bool done(const Angle& angle) const { 1647 int start = angle.start(); 1648 int end = angle.end(); 1649 const Span& mSpan = fTs[SkMin32(start, end)]; 1650 return mSpan.fDone; 1651 } 1652 1653 Segment* findNextOp(SkTDArray<Span*>& chase, bool active, 1654 int& nextStart, int& nextEnd, int& winding, int& spanWinding, ShapeOp op, 1655 const int aXorMask, const int bXorMask) { 1656 const int startIndex = nextStart; 1657 const int endIndex = nextEnd; 1658 int outerWinding = winding; 1659 int innerWinding = winding + spanWinding; 1660 #if DEBUG_WINDING 1661 SkDebugf("%s winding=%d spanWinding=%d outerWinding=%d innerWinding=%d\n", 1662 __FUNCTION__, winding, spanWinding, outerWinding, innerWinding); 1663 #endif 1664 if (useInnerWinding(outerWinding, innerWinding)) { 1665 outerWinding = innerWinding; 1666 } 1667 SkASSERT(startIndex != endIndex); 1668 int count = fTs.count(); 1669 SkASSERT(startIndex < endIndex ? startIndex < count - 1 1670 : startIndex > 0); 1671 int step = SkSign32(endIndex - startIndex); 1672 #if PRECISE_T_SORT 1673 int end = nextExactSpan(startIndex, step); 1674 #else 1675 int end = nextSpan(startIndex, step); 1676 #endif 1677 SkASSERT(end >= 0); 1678 Span* endSpan = &fTs[end]; 1679 Segment* other; 1680 if (isSimple(end)) { 1681 // mark the smaller of startIndex, endIndex done, and all adjacent 1682 // spans with the same T value (but not 'other' spans) 1683 #if DEBUG_WINDING 1684 SkDebugf("%s simple\n", __FUNCTION__); 1685 #endif 1686 markDone(SkMin32(startIndex, endIndex), outerWinding); 1687 other = endSpan->fOther; 1688 nextStart = endSpan->fOtherIndex; 1689 double startT = other->fTs[nextStart].fT; 1690 nextEnd = nextStart; 1691 do { 1692 nextEnd += step; 1693 } 1694 #if PRECISE_T_SORT 1695 while (precisely_zero(startT - other->fTs[nextEnd].fT)); 1696 #else 1697 while (approximately_zero(startT - other->fTs[nextEnd].fT)); 1698 #endif 1699 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count()); 1700 return other; 1701 } 1702 // more than one viable candidate -- measure angles to find best 1703 SkTDArray<Angle> angles; 1704 SkASSERT(startIndex - endIndex != 0); 1705 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); 1706 addTwoAngles(startIndex, end, angles); 1707 buildAngles(end, angles); 1708 SkTDArray<Angle*> sorted; 1709 sortAngles(angles, sorted); 1710 int angleCount = angles.count(); 1711 int firstIndex = findStartingEdge(sorted, startIndex, end); 1712 SkASSERT(firstIndex >= 0); 1713 #if DEBUG_SORT 1714 debugShowSort(__FUNCTION__, sorted, firstIndex, winding); 1715 #endif 1716 SkASSERT(sorted[firstIndex]->segment() == this); 1717 #if DEBUG_WINDING 1718 SkDebugf("%s [%d] sign=%d\n", __FUNCTION__, firstIndex, sorted[firstIndex]->sign()); 1719 #endif 1720 int aSumWinding = winding; 1721 int bSumWinding = winding; 1722 bool angleIsOp = sorted[firstIndex]->segment()->operand(); 1723 int angleSpan = spanSign(sorted[firstIndex]); 1724 if (angleIsOp) { 1725 bSumWinding -= angleSpan; 1726 } else { 1727 aSumWinding -= angleSpan; 1728 } 1729 int nextIndex = firstIndex + 1; 1730 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; 1731 const Angle* foundAngle = NULL; 1732 // FIXME: found done logic probably fails if there are more than 4 1733 // sorted angles. It should bias towards the first and last undone 1734 // edges -- but not sure that it won't choose a middle (incorrect) 1735 // edge if one is undone 1736 bool foundDone = false; 1737 bool foundDone2 = false; 1738 // iterate through the angle, and compute everyone's winding 1739 bool altFlipped = false; 1740 bool foundFlipped = false; 1741 int foundMax = SK_MinS32; 1742 int foundSum = SK_MinS32; 1743 Segment* nextSegment; 1744 int lastNonZeroSum = winding; 1745 do { 1746 if (nextIndex == angleCount) { 1747 nextIndex = 0; 1748 } 1749 const Angle* nextAngle = sorted[nextIndex]; 1750 nextSegment = nextAngle->segment(); 1751 angleIsOp = nextSegment->operand(); 1752 int sumWinding = angleIsOp ? bSumWinding : aSumWinding; 1753 int maxWinding = sumWinding; 1754 if (sumWinding) { 1755 lastNonZeroSum = sumWinding; 1756 } 1757 sumWinding -= nextSegment->spanSign(nextAngle); 1758 int xorMask = nextSegment->operand() ? bXorMask : aXorMask; 1759 bool otherNonZero; 1760 if (angleIsOp) { 1761 bSumWinding = sumWinding; 1762 otherNonZero = aSumWinding & aXorMask; 1763 } else { 1764 aSumWinding = sumWinding; 1765 otherNonZero = bSumWinding & bXorMask; 1766 } 1767 altFlipped ^= lastNonZeroSum * sumWinding < 0; // flip if different signs 1768 #if 0 && DEBUG_WINDING 1769 SkASSERT(abs(sumWinding) <= gDebugMaxWindSum); 1770 SkDebugf("%s [%d] maxWinding=%d sumWinding=%d sign=%d altFlipped=%d\n", __FUNCTION__, 1771 nextIndex, maxWinding, sumWinding, nextAngle->sign(), altFlipped); 1772 #endif 1773 1774 if (!(sumWinding & xorMask) && activeOp(angleIsOp, otherNonZero, op)) { 1775 if (!active) { 1776 markDone(SkMin32(startIndex, endIndex), outerWinding); 1777 // FIXME: seems like a bug that this isn't calling userInnerWinding 1778 nextSegment->markWinding(SkMin32(nextAngle->start(), 1779 nextAngle->end()), maxWinding); 1780 #if DEBUG_WINDING 1781 SkDebugf("%s [%d] inactive\n", __FUNCTION__, nextIndex); 1782 #endif 1783 return NULL; 1784 } 1785 if (!foundAngle || foundDone) { 1786 foundAngle = nextAngle; 1787 foundDone = nextSegment->done(*nextAngle); 1788 foundFlipped = altFlipped; 1789 foundMax = maxWinding; 1790 } 1791 continue; 1792 } 1793 if (!(maxWinding & xorMask) && (!foundAngle || foundDone2) 1794 && activeOp(angleIsOp, otherNonZero, op)) { 1795 #if DEBUG_WINDING 1796 if (foundAngle && foundDone2) { 1797 SkDebugf("%s [%d] !foundAngle && foundDone2\n", __FUNCTION__, nextIndex); 1798 } 1799 #endif 1800 foundAngle = nextAngle; 1801 foundDone2 = nextSegment->done(*nextAngle); 1802 foundFlipped = altFlipped; 1803 foundSum = sumWinding; 1804 } 1805 if (nextSegment->done()) { 1806 continue; 1807 } 1808 // if the winding is non-zero, nextAngle does not connect to 1809 // current chain. If we haven't done so already, mark the angle 1810 // as done, record the winding value, and mark connected unambiguous 1811 // segments as well. 1812 if (nextSegment->windSum(nextAngle) == SK_MinS32) { 1813 if (useInnerWinding(maxWinding, sumWinding)) { 1814 maxWinding = sumWinding; 1815 } 1816 Span* last; 1817 if (foundAngle) { 1818 last = nextSegment->markAndChaseWinding(nextAngle, maxWinding); 1819 } else { 1820 last = nextSegment->markAndChaseDone(nextAngle, maxWinding); 1821 } 1822 if (last) { 1823 *chase.append() = last; 1824 } 1825 } 1826 } while (++nextIndex != lastIndex); 1827 markDone(SkMin32(startIndex, endIndex), outerWinding); 1828 if (!foundAngle) { 1829 return NULL; 1830 } 1831 nextStart = foundAngle->start(); 1832 nextEnd = foundAngle->end(); 1833 nextSegment = foundAngle->segment(); 1834 int flipped = foundFlipped ? -1 : 1; 1835 spanWinding = SkSign32(spanWinding) * flipped * nextSegment->windValue( 1836 SkMin32(nextStart, nextEnd)); 1837 if (winding) { 1838 #if DEBUG_WINDING 1839 SkDebugf("%s ---6 winding=%d foundSum=", __FUNCTION__, winding); 1840 if (foundSum == SK_MinS32) { 1841 SkDebugf("?"); 1842 } else { 1843 SkDebugf("%d", foundSum); 1844 } 1845 SkDebugf(" foundMax="); 1846 if (foundMax == SK_MinS32) { 1847 SkDebugf("?"); 1848 } else { 1849 SkDebugf("%d", foundMax); 1850 } 1851 SkDebugf("\n"); 1852 #endif 1853 winding = foundSum; 1854 } 1855 #if DEBUG_WINDING 1856 SkDebugf("%s spanWinding=%d flipped=%d\n", __FUNCTION__, spanWinding, flipped); 1857 #endif 1858 return nextSegment; 1859 } 1860 1861 // so the span needs to contain the pairing info found here 1862 // this should include the winding computed for the edge, and 1863 // what edge it connects to, and whether it is discarded 1864 // (maybe discarded == abs(winding) > 1) ? 1865 // only need derivatives for duration of sorting, add a new struct 1866 // for pairings, remove extra spans that have zero length and 1867 // reference an unused other 1868 // for coincident, the last span on the other may be marked done 1869 // (always?) 1870 1871 // if loop is exhausted, contour may be closed. 1872 // FIXME: pass in close point so we can check for closure 1873 1874 // given a segment, and a sense of where 'inside' is, return the next 1875 // segment. If this segment has an intersection, or ends in multiple 1876 // segments, find the mate that continues the outside. 1877 // note that if there are multiples, but no coincidence, we can limit 1878 // choices to connections in the correct direction 1879 1880 // mark found segments as done 1881 1882 // start is the index of the beginning T of this edge 1883 // it is guaranteed to have an end which describes a non-zero length (?) 1884 // winding -1 means ccw, 1 means cw 1885 Segment* findNextWinding(SkTDArray<Span*>& chase, bool active, 1886 int& nextStart, int& nextEnd, int& winding, int& spanWinding) { 1887 const int startIndex = nextStart; 1888 const int endIndex = nextEnd; 1889 int outerWinding = winding; 1890 int innerWinding = winding + spanWinding; 1891 #if DEBUG_WINDING 1892 SkDebugf("%s winding=%d spanWinding=%d outerWinding=%d innerWinding=%d\n", 1893 __FUNCTION__, winding, spanWinding, outerWinding, innerWinding); 1894 #endif 1895 if (useInnerWinding(outerWinding, innerWinding)) { 1896 outerWinding = innerWinding; 1897 } 1898 SkASSERT(startIndex != endIndex); 1899 int count = fTs.count(); 1900 SkASSERT(startIndex < endIndex ? startIndex < count - 1 1901 : startIndex > 0); 1902 int step = SkSign32(endIndex - startIndex); 1903 #if PRECISE_T_SORT 1904 int end = nextExactSpan(startIndex, step); 1905 #else 1906 int end = nextSpan(startIndex, step); 1907 #endif 1908 SkASSERT(end >= 0); 1909 Span* endSpan = &fTs[end]; 1910 Segment* other; 1911 if (isSimple(end)) { 1912 // mark the smaller of startIndex, endIndex done, and all adjacent 1913 // spans with the same T value (but not 'other' spans) 1914 #if DEBUG_WINDING 1915 SkDebugf("%s simple\n", __FUNCTION__); 1916 #endif 1917 markDone(SkMin32(startIndex, endIndex), outerWinding); 1918 other = endSpan->fOther; 1919 nextStart = endSpan->fOtherIndex; 1920 double startT = other->fTs[nextStart].fT; 1921 nextEnd = nextStart; 1922 do { 1923 nextEnd += step; 1924 } 1925 #if PRECISE_T_SORT 1926 while (precisely_zero(startT - other->fTs[nextEnd].fT)); 1927 #else 1928 while (approximately_zero(startT - other->fTs[nextEnd].fT)); 1929 #endif 1930 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count()); 1931 return other; 1932 } 1933 // more than one viable candidate -- measure angles to find best 1934 SkTDArray<Angle> angles; 1935 SkASSERT(startIndex - endIndex != 0); 1936 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); 1937 addTwoAngles(startIndex, end, angles); 1938 buildAngles(end, angles); 1939 SkTDArray<Angle*> sorted; 1940 sortAngles(angles, sorted); 1941 int angleCount = angles.count(); 1942 int firstIndex = findStartingEdge(sorted, startIndex, end); 1943 SkASSERT(firstIndex >= 0); 1944 #if DEBUG_SORT 1945 debugShowSort(__FUNCTION__, sorted, firstIndex, winding); 1946 #endif 1947 SkASSERT(sorted[firstIndex]->segment() == this); 1948 #if DEBUG_WINDING 1949 SkDebugf("%s [%d] sign=%d\n", __FUNCTION__, firstIndex, sorted[firstIndex]->sign()); 1950 #endif 1951 int sumWinding = winding - spanSign(sorted[firstIndex]); 1952 int nextIndex = firstIndex + 1; 1953 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; 1954 const Angle* foundAngle = NULL; 1955 // FIXME: found done logic probably fails if there are more than 4 1956 // sorted angles. It should bias towards the first and last undone 1957 // edges -- but not sure that it won't choose a middle (incorrect) 1958 // edge if one is undone 1959 bool foundDone = false; 1960 bool foundDone2 = false; 1961 // iterate through the angle, and compute everyone's winding 1962 bool altFlipped = false; 1963 bool foundFlipped = false; 1964 int foundMax = SK_MinS32; 1965 int foundSum = SK_MinS32; 1966 Segment* nextSegment; 1967 int lastNonZeroSum = winding; 1968 do { 1969 if (nextIndex == angleCount) { 1970 nextIndex = 0; 1971 } 1972 const Angle* nextAngle = sorted[nextIndex]; 1973 int maxWinding = sumWinding; 1974 if (sumWinding) { 1975 lastNonZeroSum = sumWinding; 1976 } 1977 nextSegment = nextAngle->segment(); 1978 sumWinding -= nextSegment->spanSign(nextAngle); 1979 altFlipped ^= lastNonZeroSum * sumWinding < 0; // flip if different signs 1980 #if 0 && DEBUG_WINDING 1981 SkASSERT(abs(sumWinding) <= gDebugMaxWindSum); 1982 SkDebugf("%s [%d] maxWinding=%d sumWinding=%d sign=%d altFlipped=%d\n", __FUNCTION__, 1983 nextIndex, maxWinding, sumWinding, nextAngle->sign(), altFlipped); 1984 #endif 1985 if (!sumWinding) { 1986 if (!active) { 1987 markDone(SkMin32(startIndex, endIndex), outerWinding); 1988 // FIXME: seems like a bug that this isn't calling userInnerWinding 1989 nextSegment->markWinding(SkMin32(nextAngle->start(), 1990 nextAngle->end()), maxWinding); 1991 #if DEBUG_WINDING 1992 SkDebugf("%s [%d] inactive\n", __FUNCTION__, nextIndex); 1993 #endif 1994 return NULL; 1995 } 1996 if (!foundAngle || foundDone) { 1997 foundAngle = nextAngle; 1998 foundDone = nextSegment->done(*nextAngle); 1999 foundFlipped = altFlipped; 2000 foundMax = maxWinding; 2001 } 2002 continue; 2003 } 2004 if (!maxWinding && (!foundAngle || foundDone2)) { 2005 #if DEBUG_WINDING 2006 if (foundAngle && foundDone2) { 2007 SkDebugf("%s [%d] !foundAngle && foundDone2\n", __FUNCTION__, nextIndex); 2008 } 2009 #endif 2010 foundAngle = nextAngle; 2011 foundDone2 = nextSegment->done(*nextAngle); 2012 foundFlipped = altFlipped; 2013 foundSum = sumWinding; 2014 } 2015 if (nextSegment->done()) { 2016 continue; 2017 } 2018 // if the winding is non-zero, nextAngle does not connect to 2019 // current chain. If we haven't done so already, mark the angle 2020 // as done, record the winding value, and mark connected unambiguous 2021 // segments as well. 2022 if (nextSegment->windSum(nextAngle) == SK_MinS32) { 2023 if (useInnerWinding(maxWinding, sumWinding)) { 2024 maxWinding = sumWinding; 2025 } 2026 Span* last; 2027 if (foundAngle) { 2028 last = nextSegment->markAndChaseWinding(nextAngle, maxWinding); 2029 } else { 2030 last = nextSegment->markAndChaseDone(nextAngle, maxWinding); 2031 } 2032 if (last) { 2033 *chase.append() = last; 2034 } 2035 } 2036 } while (++nextIndex != lastIndex); 2037 markDone(SkMin32(startIndex, endIndex), outerWinding); 2038 if (!foundAngle) { 2039 return NULL; 2040 } 2041 nextStart = foundAngle->start(); 2042 nextEnd = foundAngle->end(); 2043 nextSegment = foundAngle->segment(); 2044 int flipped = foundFlipped ? -1 : 1; 2045 spanWinding = SkSign32(spanWinding) * flipped * nextSegment->windValue( 2046 SkMin32(nextStart, nextEnd)); 2047 if (winding) { 2048 #if DEBUG_WINDING 2049 SkDebugf("%s ---6 winding=%d foundSum=", __FUNCTION__, winding); 2050 if (foundSum == SK_MinS32) { 2051 SkDebugf("?"); 2052 } else { 2053 SkDebugf("%d", foundSum); 2054 } 2055 SkDebugf(" foundMax="); 2056 if (foundMax == SK_MinS32) { 2057 SkDebugf("?"); 2058 } else { 2059 SkDebugf("%d", foundMax); 2060 } 2061 SkDebugf("\n"); 2062 #endif 2063 winding = foundSum; 2064 } 2065 #if DEBUG_WINDING 2066 SkDebugf("%s spanWinding=%d flipped=%d\n", __FUNCTION__, spanWinding, flipped); 2067 #endif 2068 return nextSegment; 2069 } 2070 2071 Segment* findNextXor(int& nextStart, int& nextEnd) { 2072 const int startIndex = nextStart; 2073 const int endIndex = nextEnd; 2074 SkASSERT(startIndex != endIndex); 2075 int count = fTs.count(); 2076 SkASSERT(startIndex < endIndex ? startIndex < count - 1 2077 : startIndex > 0); 2078 int step = SkSign32(endIndex - startIndex); 2079 #if PRECISE_T_SORT 2080 int end = nextExactSpan(startIndex, step); 2081 #else 2082 int end = nextSpan(startIndex, step); 2083 #endif 2084 SkASSERT(end >= 0); 2085 Span* endSpan = &fTs[end]; 2086 Segment* other; 2087 markDone(SkMin32(startIndex, endIndex), 1); 2088 if (isSimple(end)) { 2089 #if DEBUG_WINDING 2090 SkDebugf("%s simple\n", __FUNCTION__); 2091 #endif 2092 other = endSpan->fOther; 2093 nextStart = endSpan->fOtherIndex; 2094 double startT = other->fTs[nextStart].fT; 2095 SkDEBUGCODE(bool firstLoop = true;) 2096 if ((approximately_less_than_zero(startT) && step < 0) 2097 || (approximately_greater_than_one(startT) && step > 0)) { 2098 step = -step; 2099 SkDEBUGCODE(firstLoop = false;) 2100 } 2101 do { 2102 nextEnd = nextStart; 2103 do { 2104 nextEnd += step; 2105 } 2106 #if PRECISE_T_SORT 2107 while (precisely_zero(startT - other->fTs[nextEnd].fT)); 2108 #else 2109 while (approximately_zero(startT - other->fTs[nextEnd].fT)); 2110 #endif 2111 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) { 2112 break; 2113 } 2114 #ifdef SK_DEBUG 2115 SkASSERT(firstLoop); 2116 #endif 2117 SkDEBUGCODE(firstLoop = false;) 2118 step = -step; 2119 } while (true); 2120 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count()); 2121 return other; 2122 } 2123 SkTDArray<Angle> angles; 2124 SkASSERT(startIndex - endIndex != 0); 2125 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); 2126 addTwoAngles(startIndex, end, angles); 2127 buildAngles(end, angles); 2128 SkTDArray<Angle*> sorted; 2129 sortAngles(angles, sorted); 2130 int angleCount = angles.count(); 2131 int firstIndex = findStartingEdge(sorted, startIndex, end); 2132 SkASSERT(firstIndex >= 0); 2133 #if DEBUG_SORT 2134 debugShowSort(__FUNCTION__, sorted, firstIndex, 0); 2135 #endif 2136 SkASSERT(sorted[firstIndex]->segment() == this); 2137 int nextIndex = firstIndex + 1; 2138 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; 2139 const Angle* nextAngle; 2140 Segment* nextSegment; 2141 do { 2142 if (nextIndex == angleCount) { 2143 nextIndex = 0; 2144 } 2145 nextAngle = sorted[nextIndex]; 2146 nextSegment = nextAngle->segment(); 2147 if (!nextSegment->done(*nextAngle)) { 2148 break; 2149 } 2150 if (++nextIndex == lastIndex) { 2151 return NULL; 2152 } 2153 } while (true); 2154 nextStart = nextAngle->start(); 2155 nextEnd = nextAngle->end(); 2156 return nextSegment; 2157 } 2158 2159 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) { 2160 int angleCount = sorted.count(); 2161 int firstIndex = -1; 2162 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) { 2163 const Angle* angle = sorted[angleIndex]; 2164 if (angle->segment() == this && angle->start() == end && 2165 angle->end() == start) { 2166 firstIndex = angleIndex; 2167 break; 2168 } 2169 } 2170 return firstIndex; 2171 } 2172 2173 // FIXME: this is tricky code; needs its own unit test 2174 void findTooCloseToCall(bool isXor) { 2175 int count = fTs.count(); 2176 if (count < 3) { // require t=0, x, 1 at minimum 2177 return; 2178 } 2179 int matchIndex = 0; 2180 int moCount; 2181 Span* match; 2182 Segment* mOther; 2183 do { 2184 match = &fTs[matchIndex]; 2185 mOther = match->fOther; 2186 // FIXME: allow quads, cubics to be near coincident? 2187 if (mOther->fVerb == SkPath::kLine_Verb) { 2188 moCount = mOther->fTs.count(); 2189 if (moCount >= 3) { 2190 break; 2191 } 2192 } 2193 if (++matchIndex >= count) { 2194 return; 2195 } 2196 } while (true); // require t=0, x, 1 at minimum 2197 // OPTIMIZATION: defer matchPt until qualifying toCount is found? 2198 const SkPoint* matchPt = &xyAtT(match); 2199 // look for a pair of nearby T values that map to the same (x,y) value 2200 // if found, see if the pair of other segments share a common point. If 2201 // so, the span from here to there is coincident. 2202 for (int index = matchIndex + 1; index < count; ++index) { 2203 Span* test = &fTs[index]; 2204 if (test->fDone) { 2205 continue; 2206 } 2207 Segment* tOther = test->fOther; 2208 if (tOther->fVerb != SkPath::kLine_Verb) { 2209 continue; // FIXME: allow quads, cubics to be near coincident? 2210 } 2211 int toCount = tOther->fTs.count(); 2212 if (toCount < 3) { // require t=0, x, 1 at minimum 2213 continue; 2214 } 2215 const SkPoint* testPt = &xyAtT(test); 2216 if (*matchPt != *testPt) { 2217 matchIndex = index; 2218 moCount = toCount; 2219 match = test; 2220 mOther = tOther; 2221 matchPt = testPt; 2222 continue; 2223 } 2224 int moStart = -1; 2225 int moEnd = -1; 2226 double moStartT, moEndT; 2227 for (int moIndex = 0; moIndex < moCount; ++moIndex) { 2228 Span& moSpan = mOther->fTs[moIndex]; 2229 if (moSpan.fDone) { 2230 continue; 2231 } 2232 if (moSpan.fOther == this) { 2233 if (moSpan.fOtherT == match->fT) { 2234 moStart = moIndex; 2235 moStartT = moSpan.fT; 2236 } 2237 continue; 2238 } 2239 if (moSpan.fOther == tOther) { 2240 if (tOther->fTs[moSpan.fOtherIndex].fWindValue == 0) { 2241 moStart = -1; 2242 break; 2243 } 2244 SkASSERT(moEnd == -1); 2245 moEnd = moIndex; 2246 moEndT = moSpan.fT; 2247 } 2248 } 2249 if (moStart < 0 || moEnd < 0) { 2250 continue; 2251 } 2252 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test 2253 if (approximately_equal(moStartT, moEndT)) { 2254 continue; 2255 } 2256 int toStart = -1; 2257 int toEnd = -1; 2258 double toStartT, toEndT; 2259 for (int toIndex = 0; toIndex < toCount; ++toIndex) { 2260 Span& toSpan = tOther->fTs[toIndex]; 2261 if (toSpan.fDone) { 2262 continue; 2263 } 2264 if (toSpan.fOther == this) { 2265 if (toSpan.fOtherT == test->fT) { 2266 toStart = toIndex; 2267 toStartT = toSpan.fT; 2268 } 2269 continue; 2270 } 2271 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) { 2272 if (mOther->fTs[toSpan.fOtherIndex].fWindValue == 0) { 2273 moStart = -1; 2274 break; 2275 } 2276 SkASSERT(toEnd == -1); 2277 toEnd = toIndex; 2278 toEndT = toSpan.fT; 2279 } 2280 } 2281 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test 2282 if (toStart <= 0 || toEnd <= 0) { 2283 continue; 2284 } 2285 if (approximately_equal(toStartT, toEndT)) { 2286 continue; 2287 } 2288 // test to see if the segment between there and here is linear 2289 if (!mOther->isLinear(moStart, moEnd) 2290 || !tOther->isLinear(toStart, toEnd)) { 2291 continue; 2292 } 2293 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1; 2294 if (flipped) { 2295 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT); 2296 } else { 2297 // FIXME: this is bogus for multiple ops 2298 // the xorMask needs to be accumulated from the union of the two 2299 // edges -- which means that the segment must have its own copy of the mask 2300 mOther->addTCoincident(isXor, moStartT, moEndT, *tOther, toStartT, toEndT); 2301 } 2302 } 2303 } 2304 2305 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached) 2306 // and use more concise logic like the old edge walker code? 2307 // FIXME: this needs to deal with coincident edges 2308 Segment* findTop(int& tIndex, int& endIndex) { 2309 // iterate through T intersections and return topmost 2310 // topmost tangent from y-min to first pt is closer to horizontal 2311 SkASSERT(!done()); 2312 int firstT; 2313 int lastT; 2314 SkPoint topPt; 2315 topPt.fY = SK_ScalarMax; 2316 int count = fTs.count(); 2317 // see if either end is not done since we want smaller Y of the pair 2318 bool lastDone = true; 2319 for (int index = 0; index < count; ++index) { 2320 const Span& span = fTs[index]; 2321 if (!span.fDone || !lastDone) { 2322 const SkPoint& intercept = xyAtT(&span); 2323 if (topPt.fY > intercept.fY || (topPt.fY == intercept.fY 2324 && topPt.fX > intercept.fX)) { 2325 topPt = intercept; 2326 firstT = lastT = index; 2327 } else if (topPt == intercept) { 2328 lastT = index; 2329 } 2330 } 2331 lastDone = span.fDone; 2332 } 2333 // sort the edges to find the leftmost 2334 int step = 1; 2335 int end = nextSpan(firstT, step); 2336 if (end == -1) { 2337 step = -1; 2338 end = nextSpan(firstT, step); 2339 SkASSERT(end != -1); 2340 } 2341 // if the topmost T is not on end, or is three-way or more, find left 2342 // look for left-ness from tLeft to firstT (matching y of other) 2343 SkTDArray<Angle> angles; 2344 SkASSERT(firstT - end != 0); 2345 addTwoAngles(end, firstT, angles); 2346 buildAngles(firstT, angles); 2347 SkTDArray<Angle*> sorted; 2348 sortAngles(angles, sorted); 2349 #if DEBUG_SORT 2350 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0); 2351 #endif 2352 // skip edges that have already been processed 2353 firstT = -1; 2354 Segment* leftSegment; 2355 do { 2356 const Angle* angle = sorted[++firstT]; 2357 leftSegment = angle->segment(); 2358 tIndex = angle->end(); 2359 endIndex = angle->start(); 2360 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone); 2361 return leftSegment; 2362 } 2363 2364 // FIXME: not crazy about this 2365 // when the intersections are performed, the other index is into an 2366 // incomplete array. as the array grows, the indices become incorrect 2367 // while the following fixes the indices up again, it isn't smart about 2368 // skipping segments whose indices are already correct 2369 // assuming we leave the code that wrote the index in the first place 2370 void fixOtherTIndex() { 2371 int iCount = fTs.count(); 2372 for (int i = 0; i < iCount; ++i) { 2373 Span& iSpan = fTs[i]; 2374 double oT = iSpan.fOtherT; 2375 Segment* other = iSpan.fOther; 2376 int oCount = other->fTs.count(); 2377 for (int o = 0; o < oCount; ++o) { 2378 Span& oSpan = other->fTs[o]; 2379 if (oT == oSpan.fT && this == oSpan.fOther) { 2380 iSpan.fOtherIndex = o; 2381 break; 2382 } 2383 } 2384 } 2385 } 2386 2387 // OPTIMIZATION: uses tail recursion. Unwise? 2388 Span* innerChaseDone(int index, int step, int winding) { 2389 int end = nextSpan(index, step); 2390 SkASSERT(end >= 0); 2391 if (multipleSpans(end)) { 2392 return &fTs[end]; 2393 } 2394 const Span& endSpan = fTs[end]; 2395 Segment* other = endSpan.fOther; 2396 index = endSpan.fOtherIndex; 2397 int otherEnd = other->nextSpan(index, step); 2398 Span* last = other->innerChaseDone(index, step, winding); 2399 other->markDone(SkMin32(index, otherEnd), winding); 2400 return last; 2401 } 2402 2403 Span* innerChaseWinding(int index, int step, int winding) { 2404 int end = nextSpan(index, step); 2405 SkASSERT(end >= 0); 2406 if (multipleSpans(end)) { 2407 return &fTs[end]; 2408 } 2409 const Span& endSpan = fTs[end]; 2410 Segment* other = endSpan.fOther; 2411 index = endSpan.fOtherIndex; 2412 int otherEnd = other->nextSpan(index, step); 2413 int min = SkMin32(index, otherEnd); 2414 if (other->fTs[min].fWindSum != SK_MinS32) { 2415 SkASSERT(other->fTs[min].fWindSum == winding); 2416 return NULL; 2417 } 2418 Span* last = other->innerChaseWinding(index, step, winding); 2419 other->markWinding(min, winding); 2420 return last; 2421 } 2422 2423 void init(const SkPoint pts[], SkPath::Verb verb, bool operand) { 2424 fDoneSpans = 0; 2425 fOperand = operand; 2426 fPts = pts; 2427 fVerb = verb; 2428 } 2429 2430 bool intersected() const { 2431 return fTs.count() > 0; 2432 } 2433 2434 bool isConnected(int startIndex, int endIndex) const { 2435 return fTs[startIndex].fWindSum != SK_MinS32 2436 || fTs[endIndex].fWindSum != SK_MinS32; 2437 } 2438 2439 bool isHorizontal() const { 2440 return fBounds.fTop == fBounds.fBottom; 2441 } 2442 2443 bool isLinear(int start, int end) const { 2444 if (fVerb == SkPath::kLine_Verb) { 2445 return true; 2446 } 2447 if (fVerb == SkPath::kQuad_Verb) { 2448 SkPoint qPart[3]; 2449 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart); 2450 return QuadIsLinear(qPart); 2451 } else { 2452 SkASSERT(fVerb == SkPath::kCubic_Verb); 2453 SkPoint cPart[4]; 2454 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart); 2455 return CubicIsLinear(cPart); 2456 } 2457 } 2458 2459 // OPTIMIZE: successive calls could start were the last leaves off 2460 // or calls could specialize to walk forwards or backwards 2461 bool isMissing(double startT) const { 2462 size_t tCount = fTs.count(); 2463 for (size_t index = 0; index < tCount; ++index) { 2464 if (approximately_zero(startT - fTs[index].fT)) { 2465 return false; 2466 } 2467 } 2468 return true; 2469 } 2470 2471 bool isSimple(int end) const { 2472 int count = fTs.count(); 2473 if (count == 2) { 2474 return true; 2475 } 2476 double t = fTs[end].fT; 2477 if (approximately_less_than_zero(t)) { 2478 return !approximately_less_than_zero(fTs[1].fT); 2479 } 2480 if (approximately_greater_than_one(t)) { 2481 return !approximately_greater_than_one(fTs[count - 2].fT); 2482 } 2483 return false; 2484 } 2485 2486 bool isVertical() const { 2487 return fBounds.fLeft == fBounds.fRight; 2488 } 2489 2490 SkScalar leftMost(int start, int end) const { 2491 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT); 2492 } 2493 2494 // this span is excluded by the winding rule -- chase the ends 2495 // as long as they are unambiguous to mark connections as done 2496 // and give them the same winding value 2497 Span* markAndChaseDone(const Angle* angle, int winding) { 2498 int index = angle->start(); 2499 int endIndex = angle->end(); 2500 int step = SkSign32(endIndex - index); 2501 Span* last = innerChaseDone(index, step, winding); 2502 markDone(SkMin32(index, endIndex), winding); 2503 return last; 2504 } 2505 2506 Span* markAndChaseWinding(const Angle* angle, int winding) { 2507 int index = angle->start(); 2508 int endIndex = angle->end(); 2509 int min = SkMin32(index, endIndex); 2510 int step = SkSign32(endIndex - index); 2511 Span* last = innerChaseWinding(index, step, winding); 2512 markWinding(min, winding); 2513 return last; 2514 } 2515 2516 // FIXME: this should also mark spans with equal (x,y) 2517 // This may be called when the segment is already marked done. While this 2518 // wastes time, it shouldn't do any more than spin through the T spans. 2519 // OPTIMIZATION: abort on first done found (assuming that this code is 2520 // always called to mark segments done). 2521 void markDone(int index, int winding) { 2522 // SkASSERT(!done()); 2523 SkASSERT(winding); 2524 double referenceT = fTs[index].fT; 2525 int lesser = index; 2526 #if PRECISE_T_SORT 2527 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 2528 markOneDone(__FUNCTION__, lesser, winding); 2529 } 2530 do { 2531 markOneDone(__FUNCTION__, index, winding); 2532 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT)); 2533 #else 2534 while (--lesser >= 0 && approximately_negative(referenceT - fTs[lesser].fT)) { 2535 markOneDone(__FUNCTION__, lesser, winding); 2536 } 2537 do { 2538 markOneDone(__FUNCTION__, index, winding); 2539 } while (++index < fTs.count() && approximately_negative(fTs[index].fT - referenceT)); 2540 #endif 2541 } 2542 2543 void markOneDone(const char* funName, int tIndex, int winding) { 2544 Span* span = markOneWinding(funName, tIndex, winding); 2545 if (!span) { 2546 return; 2547 } 2548 span->fDone = true; 2549 fDoneSpans++; 2550 } 2551 2552 Span* markOneWinding(const char* funName, int tIndex, int winding) { 2553 Span& span = fTs[tIndex]; 2554 if (span.fDone) { 2555 return NULL; 2556 } 2557 #if DEBUG_MARK_DONE 2558 debugShowNewWinding(funName, span, winding); 2559 #endif 2560 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); 2561 #ifdef SK_DEBUG 2562 SkASSERT(abs(winding) <= gDebugMaxWindSum); 2563 #endif 2564 span.fWindSum = winding; 2565 return &span; 2566 } 2567 2568 void markWinding(int index, int winding) { 2569 // SkASSERT(!done()); 2570 SkASSERT(winding); 2571 double referenceT = fTs[index].fT; 2572 int lesser = index; 2573 #if PRECISE_T_SORT 2574 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 2575 markOneWinding(__FUNCTION__, lesser, winding); 2576 } 2577 do { 2578 markOneWinding(__FUNCTION__, index, winding); 2579 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT)); 2580 #else 2581 while (--lesser >= 0 && approximately_negative(referenceT - fTs[lesser].fT)) { 2582 markOneWinding(__FUNCTION__, lesser, winding); 2583 } 2584 do { 2585 markOneWinding(__FUNCTION__, index, winding); 2586 } while (++index < fTs.count() && approximately_negative(fTs[index].fT - referenceT)); 2587 #endif 2588 } 2589 2590 void matchWindingValue(int tIndex, double t, bool borrowWind) { 2591 int nextDoorWind = SK_MaxS32; 2592 if (tIndex > 0) { 2593 const Span& below = fTs[tIndex - 1]; 2594 if (approximately_negative(t - below.fT)) { 2595 nextDoorWind = below.fWindValue; 2596 } 2597 } 2598 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) { 2599 const Span& above = fTs[tIndex + 1]; 2600 if (approximately_negative(above.fT - t)) { 2601 nextDoorWind = above.fWindValue; 2602 } 2603 } 2604 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) { 2605 const Span& below = fTs[tIndex - 1]; 2606 nextDoorWind = below.fWindValue; 2607 } 2608 if (nextDoorWind != SK_MaxS32) { 2609 Span& newSpan = fTs[tIndex]; 2610 newSpan.fWindValue = nextDoorWind; 2611 if (!nextDoorWind) { 2612 newSpan.fDone = true; 2613 ++fDoneSpans; 2614 } 2615 } 2616 } 2617 2618 // return span if when chasing, two or more radiating spans are not done 2619 // OPTIMIZATION: ? multiple spans is detected when there is only one valid 2620 // candidate and the remaining spans have windValue == 0 (canceled by 2621 // coincidence). The coincident edges could either be removed altogether, 2622 // or this code could be more complicated in detecting this case. Worth it? 2623 bool multipleSpans(int end) const { 2624 return end > 0 && end < fTs.count() - 1; 2625 } 2626 2627 // This has callers for two different situations: one establishes the end 2628 // of the current span, and one establishes the beginning of the next span 2629 // (thus the name). When this is looking for the end of the current span, 2630 // coincidence is found when the beginning Ts contain -step and the end 2631 // contains step. When it is looking for the beginning of the next, the 2632 // first Ts found can be ignored and the last Ts should contain -step. 2633 // OPTIMIZATION: probably should split into two functions 2634 int nextSpan(int from, int step) const { 2635 const Span& fromSpan = fTs[from]; 2636 int count = fTs.count(); 2637 int to = from; 2638 while (step > 0 ? ++to < count : --to >= 0) { 2639 const Span& span = fTs[to]; 2640 if (approximately_zero(span.fT - fromSpan.fT)) { 2641 continue; 2642 } 2643 return to; 2644 } 2645 return -1; 2646 } 2647 2648#if PRECISE_T_SORT 2649 // FIXME 2650 // this returns at any difference in T, vs. a preset minimum. It may be 2651 // that all callers to nextSpan should use this instead. 2652 int nextExactSpan(int from, int step) const { 2653 const Span& fromSpan = fTs[from]; 2654 int count = fTs.count(); 2655 int to = from; 2656 while (step > 0 ? ++to < count : --to >= 0) { 2657 const Span& span = fTs[to]; 2658 if (precisely_zero(span.fT - fromSpan.fT)) { 2659 continue; 2660 } 2661 return to; 2662 } 2663 return -1; 2664 } 2665#endif 2666 2667 bool operand() const { 2668 return fOperand; 2669 } 2670 2671 int oppSign(int startIndex, int endIndex) const { 2672 int result = startIndex < endIndex ? -fTs[startIndex].fWindValueOpp : 2673 fTs[endIndex].fWindValueOpp; 2674#if DEBUG_WIND_BUMP 2675 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result); 2676#endif 2677 return result; 2678 } 2679 2680 const SkPoint* pts() const { 2681 return fPts; 2682 } 2683 2684 void reset() { 2685 init(NULL, (SkPath::Verb) -1, false); 2686 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax); 2687 fTs.reset(); 2688 } 2689 2690 // OPTIMIZATION: mark as debugging only if used solely by tests 2691 const Span& span(int tIndex) const { 2692 return fTs[tIndex]; 2693 } 2694 2695 int spanSign(const Angle* angle) const { 2696 SkASSERT(angle->segment() == this); 2697 return spanSign(angle->start(), angle->end()); 2698 } 2699 2700 int spanSign(int startIndex, int endIndex) const { 2701 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue : 2702 fTs[endIndex].fWindValue; 2703#if DEBUG_WIND_BUMP 2704 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result); 2705#endif 2706 return result; 2707 } 2708 2709 // OPTIMIZATION: mark as debugging only if used solely by tests 2710 double t(int tIndex) const { 2711 return fTs[tIndex].fT; 2712 } 2713 2714 static void TrackOutside(SkTDArray<double>& outsideTs, double end, 2715 double start) { 2716 int outCount = outsideTs.count(); 2717 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) { 2718 *outsideTs.append() = end; 2719 *outsideTs.append() = start; 2720 } 2721 } 2722 2723 void undoneSpan(int& start, int& end) { 2724 size_t tCount = fTs.count(); 2725 size_t index; 2726 for (index = 0; index < tCount; ++index) { 2727 if (!fTs[index].fDone) { 2728 break; 2729 } 2730 } 2731 SkASSERT(index < tCount - 1); 2732 start = index; 2733 double startT = fTs[index].fT; 2734 while (approximately_negative(fTs[++index].fT - startT)) 2735 SkASSERT(index < tCount); 2736 SkASSERT(index < tCount); 2737 end = index; 2738 } 2739 2740 void updatePts(const SkPoint pts[]) { 2741 fPts = pts; 2742 } 2743 2744 SkPath::Verb verb() const { 2745 return fVerb; 2746 } 2747 2748 int windSum(int tIndex) const { 2749 return fTs[tIndex].fWindSum; 2750 } 2751 2752 int windSum(const Angle* angle) const { 2753 int start = angle->start(); 2754 int end = angle->end(); 2755 int index = SkMin32(start, end); 2756 return windSum(index); 2757 } 2758 2759 int windValue(int tIndex) const { 2760 return fTs[tIndex].fWindValue; 2761 } 2762 2763 int windValue(const Angle* angle) const { 2764 int start = angle->start(); 2765 int end = angle->end(); 2766 int index = SkMin32(start, end); 2767 return windValue(index); 2768 } 2769 2770 SkScalar xAtT(const Span* span) const { 2771 return xyAtT(span).fX; 2772 } 2773 2774 const SkPoint& xyAtT(int index) const { 2775 return xyAtT(&fTs[index]); 2776 } 2777 2778 const SkPoint& xyAtT(const Span* span) const { 2779 if (SkScalarIsNaN(span->fPt.fX)) { 2780 if (span->fT == 0) { 2781 span->fPt = fPts[0]; 2782 } else if (span->fT == 1) { 2783 span->fPt = fPts[fVerb]; 2784 } else { 2785 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt); 2786 } 2787 } 2788 return span->fPt; 2789 } 2790 2791 SkScalar yAtT(int index) const { 2792 return yAtT(&fTs[index]); 2793 } 2794 2795 SkScalar yAtT(const Span* span) const { 2796 return xyAtT(span).fY; 2797 } 2798 2799#if DEBUG_DUMP 2800 void dump() const { 2801 const char className[] = "Segment"; 2802 const int tab = 4; 2803 for (int i = 0; i < fTs.count(); ++i) { 2804 SkPoint out; 2805 (*SegmentXYAtT[fVerb])(fPts, t(i), &out); 2806 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d" 2807 " otherT=%1.9g windSum=%d\n", 2808 tab + sizeof(className), className, fID, 2809 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY, 2810 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum); 2811 } 2812 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)", 2813 tab + sizeof(className), className, fID, 2814 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom); 2815 } 2816#endif 2817 2818#if DEBUG_CONCIDENT 2819 // assert if pair has not already been added 2820 void debugAddTPair(double t, const Segment& other, double otherT) const { 2821 for (int i = 0; i < fTs.count(); ++i) { 2822 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) { 2823 return; 2824 } 2825 } 2826 SkASSERT(0); 2827 } 2828#endif 2829 2830#if DEBUG_DUMP 2831 int debugID() const { 2832 return fID; 2833 } 2834#endif 2835 2836#if DEBUG_WINDING 2837 void debugShowSums() const { 2838 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID, 2839 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY); 2840 for (int i = 0; i < fTs.count(); ++i) { 2841 const Span& span = fTs[i]; 2842 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span)); 2843 if (span.fWindSum == SK_MinS32) { 2844 SkDebugf("?"); 2845 } else { 2846 SkDebugf("%d", span.fWindSum); 2847 } 2848 SkDebugf("]"); 2849 } 2850 SkDebugf("\n"); 2851 } 2852#endif 2853 2854#if DEBUG_CONCIDENT 2855 void debugShowTs() const { 2856 SkDebugf("%s id=%d", __FUNCTION__, fID); 2857 for (int i = 0; i < fTs.count(); ++i) { 2858 SkDebugf(" [o=%d t=%1.3g %1.9g,%1.9g w=%d]", fTs[i].fOther->fID, 2859 fTs[i].fT, xAtT(&fTs[i]), yAtT(&fTs[i]), fTs[i].fWindValue); 2860 } 2861 SkDebugf("\n"); 2862 } 2863#endif 2864 2865#if DEBUG_ACTIVE_SPANS 2866 void debugShowActiveSpans() const { 2867 if (done()) { 2868 return; 2869 } 2870 for (int i = 0; i < fTs.count(); ++i) { 2871 if (fTs[i].fDone) { 2872 continue; 2873 } 2874 SkDebugf("%s id=%d", __FUNCTION__, fID); 2875 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); 2876 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) { 2877 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); 2878 } 2879 const Span* span = &fTs[i]; 2880 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT, 2881 xAtT(span), yAtT(span)); 2882 const Segment* other = fTs[i].fOther; 2883 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=", 2884 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex); 2885 if (fTs[i].fWindSum == SK_MinS32) { 2886 SkDebugf("?"); 2887 } else { 2888 SkDebugf("%d", fTs[i].fWindSum); 2889 } 2890 SkDebugf(" windValue=%d\n", fTs[i].fWindValue); 2891 } 2892 } 2893 2894 // This isn't useful yet -- but leaving it in for now in case i think of something 2895 // to use it for 2896 void validateActiveSpans() const { 2897 if (done()) { 2898 return; 2899 } 2900 int tCount = fTs.count(); 2901 for (int index = 0; index < tCount; ++index) { 2902 if (fTs[index].fDone) { 2903 continue; 2904 } 2905 // count number of connections which are not done 2906 int first = index; 2907 double baseT = fTs[index].fT; 2908 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) { 2909 --first; 2910 } 2911 int last = index; 2912 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) { 2913 ++last; 2914 } 2915 int connections = 0; 2916 connections += first > 0 && !fTs[first - 1].fDone; 2917 for (int test = first; test <= last; ++test) { 2918 connections += !fTs[test].fDone; 2919 const Segment* other = fTs[test].fOther; 2920 int oIndex = fTs[test].fOtherIndex; 2921 connections += !other->fTs[oIndex].fDone; 2922 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone; 2923 } 2924 // SkASSERT(!(connections & 1)); 2925 } 2926 } 2927#endif 2928 2929#if DEBUG_MARK_DONE 2930 void debugShowNewWinding(const char* fun, const Span& span, int winding) { 2931 const SkPoint& pt = xyAtT(&span); 2932 SkDebugf("%s id=%d", fun, fID); 2933 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); 2934 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) { 2935 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); 2936 } 2937 SkDebugf(") t=%1.9g (%1.9g,%1.9g) newWindSum=%d windSum=", 2938 span.fT, pt.fX, pt.fY, winding); 2939 if (span.fWindSum == SK_MinS32) { 2940 SkDebugf("?"); 2941 } else { 2942 SkDebugf("%d", span.fWindSum); 2943 } 2944 SkDebugf(" windValue=%d\n", span.fWindValue); 2945 } 2946#endif 2947 2948#if DEBUG_SORT 2949 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first, 2950 const int contourWinding) const { 2951 SkASSERT(angles[first]->segment() == this); 2952 SkASSERT(angles.count() > 1); 2953 int lastSum = contourWinding; 2954 int windSum = lastSum - spanSign(angles[first]); 2955 SkDebugf("%s %s contourWinding=%d sign=%d\n", fun, __FUNCTION__, 2956 contourWinding, spanSign(angles[first])); 2957 int index = first; 2958 bool firstTime = true; 2959 do { 2960 const Angle& angle = *angles[index]; 2961 const Segment& segment = *angle.segment(); 2962 int start = angle.start(); 2963 int end = angle.end(); 2964 const Span& sSpan = segment.fTs[start]; 2965 const Span& eSpan = segment.fTs[end]; 2966 const Span& mSpan = segment.fTs[SkMin32(start, end)]; 2967 if (!firstTime) { 2968 lastSum = windSum; 2969 windSum -= segment.spanSign(&angle); 2970 } 2971 SkDebugf("%s [%d] id=%d %s start=%d (%1.9g,%,1.9g) end=%d (%1.9g,%,1.9g)" 2972 " sign=%d windValue=%d winding: %d->%d (max=%d) done=%d\n", 2973 __FUNCTION__, index, segment.fID, kLVerbStr[segment.fVerb], 2974 start, segment.xAtT(&sSpan), 2975 segment.yAtT(&sSpan), end, segment.xAtT(&eSpan), 2976 segment.yAtT(&eSpan), angle.sign(), mSpan.fWindValue, 2977 lastSum, windSum, useInnerWinding(lastSum, windSum) 2978 ? windSum : lastSum, mSpan.fDone); 2979#if false && DEBUG_ANGLE 2980 angle.debugShow(segment.xyAtT(&sSpan)); 2981#endif 2982 ++index; 2983 if (index == angles.count()) { 2984 index = 0; 2985 } 2986 if (firstTime) { 2987 firstTime = false; 2988 } 2989 } while (index != first); 2990 } 2991#endif 2992 2993#if DEBUG_WINDING 2994 bool debugVerifyWinding(int start, int end, int winding) const { 2995 const Span& span = fTs[SkMin32(start, end)]; 2996 int spanWinding = span.fWindSum; 2997 if (spanWinding == SK_MinS32) { 2998 return true; 2999 } 3000 int spanSign = SkSign32(start - end); 3001 int signedVal = spanSign * span.fWindValue; 3002 if (signedVal < 0) { 3003 spanWinding -= signedVal; 3004 } 3005 return span.fWindSum == winding; 3006 } 3007#endif 3008 3009private: 3010 const SkPoint* fPts; 3011 SkPath::Verb fVerb; 3012 Bounds fBounds; 3013 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1) 3014 int fDoneSpans; // quick check that segment is finished 3015 bool fOperand; 3016#if DEBUG_DUMP 3017 int fID; 3018#endif 3019}; 3020 3021class Contour; 3022 3023struct Coincidence { 3024 Contour* fContours[2]; 3025 int fSegments[2]; 3026 double fTs[2][2]; 3027 bool fXor; 3028}; 3029 3030class Contour { 3031public: 3032 Contour() { 3033 reset(); 3034#if DEBUG_DUMP 3035 fID = ++gContourID; 3036#endif 3037 } 3038 3039 bool operator<(const Contour& rh) const { 3040 return fBounds.fTop == rh.fBounds.fTop 3041 ? fBounds.fLeft < rh.fBounds.fLeft 3042 : fBounds.fTop < rh.fBounds.fTop; 3043 } 3044 3045 void addCoincident(int index, Contour* other, int otherIndex, 3046 const Intersections& ts, bool swap) { 3047 Coincidence& coincidence = *fCoincidences.append(); 3048 coincidence.fContours[0] = this; 3049 coincidence.fContours[1] = other; 3050 coincidence.fSegments[0] = index; 3051 coincidence.fSegments[1] = otherIndex; 3052 if (fSegments[index].verb() == SkPath::kLine_Verb && 3053 other->fSegments[otherIndex].verb() == SkPath::kLine_Verb) { 3054 // FIXME: coincident lines use legacy Ts instead of coincident Ts 3055 coincidence.fTs[swap][0] = ts.fT[0][0]; 3056 coincidence.fTs[swap][1] = ts.fT[0][1]; 3057 coincidence.fTs[!swap][0] = ts.fT[1][0]; 3058 coincidence.fTs[!swap][1] = ts.fT[1][1]; 3059 } else if (fSegments[index].verb() == SkPath::kQuad_Verb && 3060 other->fSegments[otherIndex].verb() == SkPath::kQuad_Verb) { 3061 coincidence.fTs[swap][0] = ts.fCoincidentT[0][0]; 3062 coincidence.fTs[swap][1] = ts.fCoincidentT[0][1]; 3063 coincidence.fTs[!swap][0] = ts.fCoincidentT[1][0]; 3064 coincidence.fTs[!swap][1] = ts.fCoincidentT[1][1]; 3065 } 3066 coincidence.fXor = fOperand == other->fOperand ? fXor : true; 3067 } 3068 3069 void addCross(const Contour* crosser) { 3070#ifdef DEBUG_CROSS 3071 for (int index = 0; index < fCrosses.count(); ++index) { 3072 SkASSERT(fCrosses[index] != crosser); 3073 } 3074#endif 3075 *fCrosses.append() = crosser; 3076 } 3077 3078 void addCubic(const SkPoint pts[4]) { 3079 fSegments.push_back().addCubic(pts, fOperand); 3080 fContainsCurves = true; 3081 } 3082 3083 int addLine(const SkPoint pts[2]) { 3084 fSegments.push_back().addLine(pts, fOperand); 3085 return fSegments.count(); 3086 } 3087 3088 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) { 3089 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex); 3090 } 3091 3092 int addQuad(const SkPoint pts[3]) { 3093 fSegments.push_back().addQuad(pts, fOperand); 3094 fContainsCurves = true; 3095 return fSegments.count(); 3096 } 3097 3098 int addT(int segIndex, double newT, Contour* other, int otherIndex) { 3099 containsIntercepts(); 3100 return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex]); 3101 } 3102 3103 const Bounds& bounds() const { 3104 return fBounds; 3105 } 3106 3107 void collapseTriangles() { 3108 int segmentCount = fSegments.count(); 3109 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { 3110 fSegments[sIndex].collapseTriangles(fXor); 3111 } 3112 } 3113 3114 void complete() { 3115 setBounds(); 3116 fContainsIntercepts = false; 3117 } 3118 3119 void containsIntercepts() { 3120 fContainsIntercepts = true; 3121 } 3122 3123 const Segment* crossedSegment(const SkPoint& basePt, SkScalar& bestY, 3124 int &tIndex, double& hitT) { 3125 int segmentCount = fSegments.count(); 3126 const Segment* bestSegment = NULL; 3127 for (int test = 0; test < segmentCount; ++test) { 3128 Segment* testSegment = &fSegments[test]; 3129 const SkRect& bounds = testSegment->bounds(); 3130 if (bounds.fBottom <= bestY) { 3131 continue; 3132 } 3133 if (bounds.fTop >= basePt.fY) { 3134 continue; 3135 } 3136 if (bounds.fLeft > basePt.fX) { 3137 continue; 3138 } 3139 if (bounds.fRight < basePt.fX) { 3140 continue; 3141 } 3142 if (bounds.fLeft == bounds.fRight) { 3143 continue; 3144 } 3145 #if 0 3146 bool leftHalf = bounds.fLeft == basePt.fX; 3147 bool rightHalf = bounds.fRight == basePt.fX; 3148 if ((leftHalf || rightHalf) && !testSegment->crossedSpanHalves( 3149 basePt, leftHalf, rightHalf)) { 3150 continue; 3151 } 3152 #endif 3153 double testHitT; 3154 int testT = testSegment->crossedSpan(basePt, bestY, testHitT); 3155 if (testT >= 0) { 3156 bestSegment = testSegment; 3157 tIndex = testT; 3158 hitT = testHitT; 3159 } 3160 } 3161 return bestSegment; 3162 } 3163 3164 bool crosses(const Contour* crosser) const { 3165 for (int index = 0; index < fCrosses.count(); ++index) { 3166 if (fCrosses[index] == crosser) { 3167 return true; 3168 } 3169 } 3170 return false; 3171 } 3172 3173 void findTooCloseToCall() { 3174 int segmentCount = fSegments.count(); 3175 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { 3176 fSegments[sIndex].findTooCloseToCall(fXor); 3177 } 3178 } 3179 3180 void fixOtherTIndex() { 3181 int segmentCount = fSegments.count(); 3182 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { 3183 fSegments[sIndex].fixOtherTIndex(); 3184 } 3185 } 3186 3187 void reset() { 3188 fSegments.reset(); 3189 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax); 3190 fContainsCurves = fContainsIntercepts = false; 3191 } 3192 3193 // FIXME: for binary ops, need to keep both ops winding contributions separately 3194 // in edge array 3195 void resolveCoincidence() { 3196 int count = fCoincidences.count(); 3197 for (int index = 0; index < count; ++index) { 3198 Coincidence& coincidence = fCoincidences[index]; 3199 Contour* thisContour = coincidence.fContours[0]; 3200 Contour* otherContour = coincidence.fContours[1]; 3201 int thisIndex = coincidence.fSegments[0]; 3202 int otherIndex = coincidence.fSegments[1]; 3203 Segment& thisOne = thisContour->fSegments[thisIndex]; 3204 Segment& other = otherContour->fSegments[otherIndex]; 3205 #if DEBUG_CONCIDENT 3206 thisOne.debugShowTs(); 3207 other.debugShowTs(); 3208 #endif 3209 double startT = coincidence.fTs[0][0]; 3210 double endT = coincidence.fTs[0][1]; 3211 bool opposite = false; 3212 if (startT > endT) { 3213 SkTSwap<double>(startT, endT); 3214 opposite ^= true; 3215 } 3216 SkASSERT(!approximately_negative(endT - startT)); 3217 double oStartT = coincidence.fTs[1][0]; 3218 double oEndT = coincidence.fTs[1][1]; 3219 if (oStartT > oEndT) { 3220 SkTSwap<double>(oStartT, oEndT); 3221 opposite ^= true; 3222 } 3223 SkASSERT(!approximately_negative(oEndT - oStartT)); 3224 if (opposite) { 3225 // make sure startT and endT have t entries 3226 SkASSERT(opposite); 3227 if (startT > 0 || oEndT < 1 3228 || thisOne.isMissing(startT) || other.isMissing(oEndT)) { 3229 thisOne.addTPair(startT, other, oEndT, true); 3230 } 3231 if (oStartT > 0 || endT < 1 3232 || thisOne.isMissing(endT) || other.isMissing(oStartT)) { 3233 other.addTPair(oStartT, thisOne, endT, true); 3234 } 3235 thisOne.addTCancel(startT, endT, other, oStartT, oEndT); 3236 } else { 3237 if (startT > 0 || oStartT > 0 3238 || thisOne.isMissing(startT) || other.isMissing(oStartT)) { 3239 thisOne.addTPair(startT, other, oStartT, true); 3240 } 3241 if (endT < 1 || oEndT < 1 3242 || thisOne.isMissing(endT) || other.isMissing(oEndT)) { 3243 other.addTPair(oEndT, thisOne, endT, true); 3244 } 3245 thisOne.addTCoincident(coincidence.fXor, startT, endT, other, oStartT, oEndT); 3246 } 3247 #if DEBUG_CONCIDENT 3248 thisOne.debugShowTs(); 3249 other.debugShowTs(); 3250 #endif 3251 } 3252 } 3253 3254 const SkTArray<Segment>& segments() { 3255 return fSegments; 3256 } 3257 3258 void setOperand(bool isOp) { 3259 fOperand = isOp; 3260 } 3261 3262 void setXor(bool isXor) { 3263 fXor = isXor; 3264 } 3265 3266 // OPTIMIZATION: feel pretty uneasy about this. It seems like once again 3267 // we need to sort and walk edges in y, but that on the surface opens the 3268 // same can of worms as before. But then, this is a rough sort based on 3269 // segments' top, and not a true sort, so it could be ameniable to regular 3270 // sorting instead of linear searching. Still feel like I'm missing something 3271 Segment* topSegment(SkScalar& bestY) { 3272 int segmentCount = fSegments.count(); 3273 SkASSERT(segmentCount > 0); 3274 int best = -1; 3275 Segment* bestSegment = NULL; 3276 while (++best < segmentCount) { 3277 Segment* testSegment = &fSegments[best]; 3278 if (testSegment->done()) { 3279 continue; 3280 } 3281 bestSegment = testSegment; 3282 break; 3283 } 3284 if (!bestSegment) { 3285 return NULL; 3286 } 3287 SkScalar bestTop = bestSegment->activeTop(); 3288 for (int test = best + 1; test < segmentCount; ++test) { 3289 Segment* testSegment = &fSegments[test]; 3290 if (testSegment->done()) { 3291 continue; 3292 } 3293 if (testSegment->bounds().fTop > bestTop) { 3294 continue; 3295 } 3296 SkScalar testTop = testSegment->activeTop(); 3297 if (bestTop > testTop) { 3298 bestTop = testTop; 3299 bestSegment = testSegment; 3300 } 3301 } 3302 bestY = bestTop; 3303 return bestSegment; 3304 } 3305 3306 Segment* undoneSegment(int& start, int& end) { 3307 int segmentCount = fSegments.count(); 3308 for (int test = 0; test < segmentCount; ++test) { 3309 Segment* testSegment = &fSegments[test]; 3310 if (testSegment->done()) { 3311 continue; 3312 } 3313 testSegment->undoneSpan(start, end); 3314 return testSegment; 3315 } 3316 return NULL; 3317 } 3318 3319 int updateSegment(int index, const SkPoint* pts) { 3320 Segment& segment = fSegments[index]; 3321 segment.updatePts(pts); 3322 return segment.verb() + 1; 3323 } 3324 3325#if DEBUG_TEST 3326 SkTArray<Segment>& debugSegments() { 3327 return fSegments; 3328 } 3329#endif 3330 3331#if DEBUG_DUMP 3332 void dump() { 3333 int i; 3334 const char className[] = "Contour"; 3335 const int tab = 4; 3336 SkDebugf("%s %p (contour=%d)\n", className, this, fID); 3337 for (i = 0; i < fSegments.count(); ++i) { 3338 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className), 3339 className, i); 3340 fSegments[i].dump(); 3341 } 3342 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n", 3343 tab + sizeof(className), className, 3344 fBounds.fLeft, fBounds.fTop, 3345 fBounds.fRight, fBounds.fBottom); 3346 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className), 3347 className, fContainsIntercepts); 3348 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className), 3349 className, fContainsCurves); 3350 } 3351#endif 3352 3353#if DEBUG_ACTIVE_SPANS 3354 void debugShowActiveSpans() { 3355 for (int index = 0; index < fSegments.count(); ++index) { 3356 fSegments[index].debugShowActiveSpans(); 3357 } 3358 } 3359 3360 void validateActiveSpans() { 3361 for (int index = 0; index < fSegments.count(); ++index) { 3362 fSegments[index].validateActiveSpans(); 3363 } 3364 } 3365#endif 3366 3367protected: 3368 void setBounds() { 3369 int count = fSegments.count(); 3370 if (count == 0) { 3371 SkDebugf("%s empty contour\n", __FUNCTION__); 3372 SkASSERT(0); 3373 // FIXME: delete empty contour? 3374 return; 3375 } 3376 fBounds = fSegments.front().bounds(); 3377 for (int index = 1; index < count; ++index) { 3378 fBounds.add(fSegments[index].bounds()); 3379 } 3380 } 3381 3382private: 3383 SkTArray<Segment> fSegments; 3384 SkTDArray<Coincidence> fCoincidences; 3385 SkTDArray<const Contour*> fCrosses; 3386 Bounds fBounds; 3387 bool fContainsIntercepts; 3388 bool fContainsCurves; 3389 bool fOperand; // true for the second argument to a binary operator 3390 bool fXor; 3391#if DEBUG_DUMP 3392 int fID; 3393#endif 3394}; 3395 3396class EdgeBuilder { 3397public: 3398 3399EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours) 3400 : fPath(&path) 3401 , fContours(contours) 3402 , fCurrentContour(NULL) 3403 , fOperand(false) 3404{ 3405 fXorMask = (path.getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask; 3406#if DEBUG_DUMP 3407 gContourID = 0; 3408 gSegmentID = 0; 3409#endif 3410 fSecondHalf = preFetch(); 3411} 3412 3413void addOperand(const SkPath& path) { 3414 fPath = &path; 3415 fXorMask = (path.getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask; 3416 preFetch(); 3417} 3418 3419void finish() { 3420 walk(); 3421 complete(); 3422 if (fCurrentContour && !fCurrentContour->segments().count()) { 3423 fContours.pop_back(); 3424 } 3425 // correct pointers in contours since fReducePts may have moved as it grew 3426 int cIndex = 0; 3427 int extraCount = fExtra.count(); 3428 SkASSERT(extraCount == 0 || fExtra[0] == -1); 3429 int eIndex = 0; 3430 int rIndex = 0; 3431 while (++eIndex < extraCount) { 3432 int offset = fExtra[eIndex]; 3433 if (offset < 0) { 3434 ++cIndex; 3435 continue; 3436 } 3437 fCurrentContour = &fContours[cIndex]; 3438 rIndex += fCurrentContour->updateSegment(offset - 1, 3439 &fReducePts[rIndex]); 3440 } 3441 fExtra.reset(); // we're done with this 3442} 3443 3444ShapeOpMask xorMask() const { 3445 return fXorMask; 3446} 3447 3448protected: 3449 3450void complete() { 3451 if (fCurrentContour && fCurrentContour->segments().count()) { 3452 fCurrentContour->complete(); 3453 fCurrentContour = NULL; 3454 } 3455} 3456 3457// FIXME:remove once we can access path pts directly 3458int preFetch() { 3459 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed 3460 SkPoint pts[4]; 3461 SkPath::Verb verb; 3462 do { 3463 verb = iter.next(pts); 3464 *fPathVerbs.append() = verb; 3465 if (verb == SkPath::kMove_Verb) { 3466 *fPathPts.append() = pts[0]; 3467 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) { 3468 fPathPts.append(verb, &pts[1]); 3469 } 3470 } while (verb != SkPath::kDone_Verb); 3471 return fPathVerbs.count(); 3472} 3473 3474void walk() { 3475 SkPath::Verb reducedVerb; 3476 uint8_t* verbPtr = fPathVerbs.begin(); 3477 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf]; 3478 const SkPoint* pointsPtr = fPathPts.begin(); 3479 const SkPoint* finalCurveStart = NULL; 3480 const SkPoint* finalCurveEnd = NULL; 3481 SkPath::Verb verb; 3482 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) { 3483 switch (verb) { 3484 case SkPath::kMove_Verb: 3485 complete(); 3486 if (!fCurrentContour) { 3487 fCurrentContour = fContours.push_back_n(1); 3488 fCurrentContour->setOperand(fOperand); 3489 fCurrentContour->setXor(fXorMask == kEvenOdd_Mask); 3490 *fExtra.append() = -1; // start new contour 3491 } 3492 finalCurveEnd = pointsPtr++; 3493 continue; 3494 case SkPath::kLine_Verb: 3495 // skip degenerate points 3496 if (pointsPtr[-1].fX != pointsPtr[0].fX 3497 || pointsPtr[-1].fY != pointsPtr[0].fY) { 3498 fCurrentContour->addLine(&pointsPtr[-1]); 3499 } 3500 break; 3501 case SkPath::kQuad_Verb: 3502 3503 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts); 3504 if (reducedVerb == 0) { 3505 break; // skip degenerate points 3506 } 3507 if (reducedVerb == 1) { 3508 *fExtra.append() = 3509 fCurrentContour->addLine(fReducePts.end() - 2); 3510 break; 3511 } 3512 fCurrentContour->addQuad(&pointsPtr[-1]); 3513 break; 3514 case SkPath::kCubic_Verb: 3515 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts); 3516 if (reducedVerb == 0) { 3517 break; // skip degenerate points 3518 } 3519 if (reducedVerb == 1) { 3520 *fExtra.append() = 3521 fCurrentContour->addLine(fReducePts.end() - 2); 3522 break; 3523 } 3524 if (reducedVerb == 2) { 3525 *fExtra.append() = 3526 fCurrentContour->addQuad(fReducePts.end() - 3); 3527 break; 3528 } 3529 fCurrentContour->addCubic(&pointsPtr[-1]); 3530 break; 3531 case SkPath::kClose_Verb: 3532 SkASSERT(fCurrentContour); 3533 if (finalCurveStart && finalCurveEnd 3534 && *finalCurveStart != *finalCurveEnd) { 3535 *fReducePts.append() = *finalCurveStart; 3536 *fReducePts.append() = *finalCurveEnd; 3537 *fExtra.append() = 3538 fCurrentContour->addLine(fReducePts.end() - 2); 3539 } 3540 complete(); 3541 continue; 3542 default: 3543 SkDEBUGFAIL("bad verb"); 3544 return; 3545 } 3546 finalCurveStart = &pointsPtr[verb - 1]; 3547 pointsPtr += verb; 3548 SkASSERT(fCurrentContour); 3549 if (verbPtr == endOfFirstHalf) { 3550 fOperand = true; 3551 } 3552 } 3553} 3554 3555private: 3556 const SkPath* fPath; 3557 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead 3558 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove 3559 Contour* fCurrentContour; 3560 SkTArray<Contour>& fContours; 3561 SkTDArray<SkPoint> fReducePts; // segments created on the fly 3562 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour 3563 ShapeOpMask fXorMask; 3564 int fSecondHalf; 3565 bool fOperand; 3566}; 3567 3568class Work { 3569public: 3570 enum SegmentType { 3571 kHorizontalLine_Segment = -1, 3572 kVerticalLine_Segment = 0, 3573 kLine_Segment = SkPath::kLine_Verb, 3574 kQuad_Segment = SkPath::kQuad_Verb, 3575 kCubic_Segment = SkPath::kCubic_Verb, 3576 }; 3577 3578 void addCoincident(Work& other, const Intersections& ts, bool swap) { 3579 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap); 3580 } 3581 3582 // FIXME: does it make sense to write otherIndex now if we're going to 3583 // fix it up later? 3584 void addOtherT(int index, double otherT, int otherIndex) { 3585 fContour->addOtherT(fIndex, index, otherT, otherIndex); 3586 } 3587 3588 // Avoid collapsing t values that are close to the same since 3589 // we walk ts to describe consecutive intersections. Since a pair of ts can 3590 // be nearly equal, any problems caused by this should be taken care 3591 // of later. 3592 // On the edge or out of range values are negative; add 2 to get end 3593 int addT(double newT, const Work& other) { 3594 return fContour->addT(fIndex, newT, other.fContour, other.fIndex); 3595 } 3596 3597 bool advance() { 3598 return ++fIndex < fLast; 3599 } 3600 3601 SkScalar bottom() const { 3602 return bounds().fBottom; 3603 } 3604 3605 const Bounds& bounds() const { 3606 return fContour->segments()[fIndex].bounds(); 3607 } 3608 3609 const SkPoint* cubic() const { 3610 return fCubic; 3611 } 3612 3613 void init(Contour* contour) { 3614 fContour = contour; 3615 fIndex = 0; 3616 fLast = contour->segments().count(); 3617 } 3618 3619 bool isAdjacent(const Work& next) { 3620 return fContour == next.fContour && fIndex + 1 == next.fIndex; 3621 } 3622 3623 bool isFirstLast(const Work& next) { 3624 return fContour == next.fContour && fIndex == 0 3625 && next.fIndex == fLast - 1; 3626 } 3627 3628 SkScalar left() const { 3629 return bounds().fLeft; 3630 } 3631 3632 void promoteToCubic() { 3633 fCubic[0] = pts()[0]; 3634 fCubic[2] = pts()[1]; 3635 fCubic[3] = pts()[2]; 3636 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3; 3637 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3; 3638 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3; 3639 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3; 3640 } 3641 3642 const SkPoint* pts() const { 3643 return fContour->segments()[fIndex].pts(); 3644 } 3645 3646 SkScalar right() const { 3647 return bounds().fRight; 3648 } 3649 3650 ptrdiff_t segmentIndex() const { 3651 return fIndex; 3652 } 3653 3654 SegmentType segmentType() const { 3655 const Segment& segment = fContour->segments()[fIndex]; 3656 SegmentType type = (SegmentType) segment.verb(); 3657 if (type != kLine_Segment) { 3658 return type; 3659 } 3660 if (segment.isHorizontal()) { 3661 return kHorizontalLine_Segment; 3662 } 3663 if (segment.isVertical()) { 3664 return kVerticalLine_Segment; 3665 } 3666 return kLine_Segment; 3667 } 3668 3669 bool startAfter(const Work& after) { 3670 fIndex = after.fIndex; 3671 return advance(); 3672 } 3673 3674 SkScalar top() const { 3675 return bounds().fTop; 3676 } 3677 3678 SkPath::Verb verb() const { 3679 return fContour->segments()[fIndex].verb(); 3680 } 3681 3682 SkScalar x() const { 3683 return bounds().fLeft; 3684 } 3685 3686 bool xFlipped() const { 3687 return x() != pts()[0].fX; 3688 } 3689 3690 SkScalar y() const { 3691 return bounds().fTop; 3692 } 3693 3694 bool yFlipped() const { 3695 return y() != pts()[0].fY; 3696 } 3697 3698protected: 3699 Contour* fContour; 3700 SkPoint fCubic[4]; 3701 int fIndex; 3702 int fLast; 3703}; 3704 3705#if DEBUG_ADD_INTERSECTING_TS 3706static void debugShowLineIntersection(int pts, const Work& wt, 3707 const Work& wn, const double wtTs[2], const double wnTs[2]) { 3708 if (!pts) { 3709 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g %1.9g,%1.9g)\n", 3710 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, 3711 wt.pts()[1].fX, wt.pts()[1].fY, wn.pts()[0].fX, wn.pts()[0].fY, 3712 wn.pts()[1].fX, wn.pts()[1].fY); 3713 return; 3714 } 3715 SkPoint wtOutPt, wnOutPt; 3716 LineXYAtT(wt.pts(), wtTs[0], &wtOutPt); 3717 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt); 3718 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)", 3719 __FUNCTION__, 3720 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, 3721 wt.pts()[1].fX, wt.pts()[1].fY, wtOutPt.fX, wtOutPt.fY); 3722 if (pts == 2) { 3723 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]); 3724 } 3725 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)", 3726 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY, 3727 wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY); 3728 if (pts == 2) { 3729 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]); 3730 } 3731 SkDebugf("\n"); 3732} 3733 3734static void debugShowQuadIntersection(int pts, const Work& wt, 3735 const Work& wn, const double wtTs[2], const double wnTs[2]) { 3736 if (!pts) { 3737 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)" 3738 " (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)\n", 3739 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, 3740 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY, 3741 wn.pts()[0].fX, wn.pts()[0].fY, wn.pts()[1].fX, wn.pts()[1].fY, 3742 wt.pts()[2].fX, wt.pts()[2].fY ); 3743 return; 3744 } 3745 SkPoint wtOutPt, wnOutPt; 3746 QuadXYAtT(wt.pts(), wtTs[0], &wtOutPt); 3747 QuadXYAtT(wn.pts(), wnTs[0], &wnOutPt); 3748 SkDebugf("%s wtTs[0]=%1.9g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)", 3749 __FUNCTION__, 3750 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, 3751 wt.pts()[1].fX, wt.pts()[1].fY, wt.pts()[2].fX, wt.pts()[2].fY, 3752 wtOutPt.fX, wtOutPt.fY); 3753 if (pts == 2) { 3754 SkDebugf(" wtTs[1]=%1.9g", wtTs[1]); 3755 } 3756 SkDebugf(" wnTs[0]=%g (%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g)", 3757 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY, 3758 wn.pts()[1].fX, wn.pts()[1].fY, wn.pts()[2].fX, wn.pts()[2].fY, 3759 wnOutPt.fX, wnOutPt.fY); 3760 if (pts == 2) { 3761 SkDebugf(" wnTs[1]=%1.9g", wnTs[1]); 3762 } 3763 SkDebugf("\n"); 3764} 3765#else 3766static void debugShowLineIntersection(int , const Work& , 3767 const Work& , const double [2], const double [2]) { 3768} 3769 3770static void debugShowQuadIntersection(int , const Work& , 3771 const Work& , const double [2], const double [2]) { 3772} 3773#endif 3774 3775static bool addIntersectTs(Contour* test, Contour* next) { 3776 3777 if (test != next) { 3778 if (test->bounds().fBottom < next->bounds().fTop) { 3779 return false; 3780 } 3781 if (!Bounds::Intersects(test->bounds(), next->bounds())) { 3782 return true; 3783 } 3784 } 3785 Work wt; 3786 wt.init(test); 3787 bool foundCommonContour = test == next; 3788 do { 3789 Work wn; 3790 wn.init(next); 3791 if (test == next && !wn.startAfter(wt)) { 3792 continue; 3793 } 3794 do { 3795 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) { 3796 continue; 3797 } 3798 int pts; 3799 Intersections ts; 3800 bool swap = false; 3801 switch (wt.segmentType()) { 3802 case Work::kHorizontalLine_Segment: 3803 swap = true; 3804 switch (wn.segmentType()) { 3805 case Work::kHorizontalLine_Segment: 3806 case Work::kVerticalLine_Segment: 3807 case Work::kLine_Segment: { 3808 pts = HLineIntersect(wn.pts(), wt.left(), 3809 wt.right(), wt.y(), wt.xFlipped(), ts); 3810 debugShowLineIntersection(pts, wt, wn, 3811 ts.fT[1], ts.fT[0]); 3812 break; 3813 } 3814 case Work::kQuad_Segment: { 3815 pts = HQuadIntersect(wn.pts(), wt.left(), 3816 wt.right(), wt.y(), wt.xFlipped(), ts); 3817 break; 3818 } 3819 case Work::kCubic_Segment: { 3820 pts = HCubicIntersect(wn.pts(), wt.left(), 3821 wt.right(), wt.y(), wt.xFlipped(), ts); 3822 break; 3823 } 3824 default: 3825 SkASSERT(0); 3826 } 3827 break; 3828 case Work::kVerticalLine_Segment: 3829 swap = true; 3830 switch (wn.segmentType()) { 3831 case Work::kHorizontalLine_Segment: 3832 case Work::kVerticalLine_Segment: 3833 case Work::kLine_Segment: { 3834 pts = VLineIntersect(wn.pts(), wt.top(), 3835 wt.bottom(), wt.x(), wt.yFlipped(), ts); 3836 debugShowLineIntersection(pts, wt, wn, 3837 ts.fT[1], ts.fT[0]); 3838 break; 3839 } 3840 case Work::kQuad_Segment: { 3841 pts = VQuadIntersect(wn.pts(), wt.top(), 3842 wt.bottom(), wt.x(), wt.yFlipped(), ts); 3843 break; 3844 } 3845 case Work::kCubic_Segment: { 3846 pts = VCubicIntersect(wn.pts(), wt.top(), 3847 wt.bottom(), wt.x(), wt.yFlipped(), ts); 3848 break; 3849 } 3850 default: 3851 SkASSERT(0); 3852 } 3853 break; 3854 case Work::kLine_Segment: 3855 switch (wn.segmentType()) { 3856 case Work::kHorizontalLine_Segment: 3857 pts = HLineIntersect(wt.pts(), wn.left(), 3858 wn.right(), wn.y(), wn.xFlipped(), ts); 3859 debugShowLineIntersection(pts, wt, wn, 3860 ts.fT[1], ts.fT[0]); 3861 break; 3862 case Work::kVerticalLine_Segment: 3863 pts = VLineIntersect(wt.pts(), wn.top(), 3864 wn.bottom(), wn.x(), wn.yFlipped(), ts); 3865 debugShowLineIntersection(pts, wt, wn, 3866 ts.fT[1], ts.fT[0]); 3867 break; 3868 case Work::kLine_Segment: { 3869 pts = LineIntersect(wt.pts(), wn.pts(), ts); 3870 debugShowLineIntersection(pts, wt, wn, 3871 ts.fT[1], ts.fT[0]); 3872 break; 3873 } 3874 case Work::kQuad_Segment: { 3875 swap = true; 3876 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts); 3877 break; 3878 } 3879 case Work::kCubic_Segment: { 3880 swap = true; 3881 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts); 3882 break; 3883 } 3884 default: 3885 SkASSERT(0); 3886 } 3887 break; 3888 case Work::kQuad_Segment: 3889 switch (wn.segmentType()) { 3890 case Work::kHorizontalLine_Segment: 3891 pts = HQuadIntersect(wt.pts(), wn.left(), 3892 wn.right(), wn.y(), wn.xFlipped(), ts); 3893 break; 3894 case Work::kVerticalLine_Segment: 3895 pts = VQuadIntersect(wt.pts(), wn.top(), 3896 wn.bottom(), wn.x(), wn.yFlipped(), ts); 3897 break; 3898 case Work::kLine_Segment: { 3899 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts); 3900 break; 3901 } 3902 case Work::kQuad_Segment: { 3903 pts = QuadIntersect(wt.pts(), wn.pts(), ts); 3904 debugShowQuadIntersection(pts, wt, wn, 3905 ts.fT[1], ts.fT[0]); 3906 break; 3907 } 3908 case Work::kCubic_Segment: { 3909 wt.promoteToCubic(); 3910 pts = CubicIntersect(wt.cubic(), wn.pts(), ts); 3911 break; 3912 } 3913 default: 3914 SkASSERT(0); 3915 } 3916 break; 3917 case Work::kCubic_Segment: 3918 switch (wn.segmentType()) { 3919 case Work::kHorizontalLine_Segment: 3920 pts = HCubicIntersect(wt.pts(), wn.left(), 3921 wn.right(), wn.y(), wn.xFlipped(), ts); 3922 break; 3923 case Work::kVerticalLine_Segment: 3924 pts = VCubicIntersect(wt.pts(), wn.top(), 3925 wn.bottom(), wn.x(), wn.yFlipped(), ts); 3926 break; 3927 case Work::kLine_Segment: { 3928 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts); 3929 break; 3930 } 3931 case Work::kQuad_Segment: { 3932 wn.promoteToCubic(); 3933 pts = CubicIntersect(wt.pts(), wn.cubic(), ts); 3934 break; 3935 } 3936 case Work::kCubic_Segment: { 3937 pts = CubicIntersect(wt.pts(), wn.pts(), ts); 3938 break; 3939 } 3940 default: 3941 SkASSERT(0); 3942 } 3943 break; 3944 default: 3945 SkASSERT(0); 3946 } 3947 if (!foundCommonContour && pts > 0) { 3948 test->addCross(next); 3949 next->addCross(test); 3950 foundCommonContour = true; 3951 } 3952 // in addition to recording T values, record matching segment 3953 if (pts == 2) { 3954 if (wn.segmentType() <= Work::kLine_Segment 3955 && wt.segmentType() <= Work::kLine_Segment) { 3956 wt.addCoincident(wn, ts, swap); 3957 continue; 3958 } 3959 if (wn.segmentType() == Work::kQuad_Segment 3960 && wt.segmentType() == Work::kQuad_Segment 3961 && ts.coincidentUsed() == 2) { 3962 wt.addCoincident(wn, ts, swap); 3963 continue; 3964 } 3965 3966 } 3967 int pt2 = 0; 3968 int pt2inc = 1; 3969 if (ts.fFlip) { 3970 pt2 = pts - 1; 3971 pt2inc = -1; 3972 } 3973 for (int pt = 0; pt < pts; ++pt) { 3974 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1); 3975 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1); 3976 int testTAt = wt.addT(ts.fT[swap][pt], wn); 3977 int nextTAt = wn.addT(ts.fT[!swap][pt], wt); 3978 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt); 3979 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt); 3980 pt2 += pt2inc; 3981 } 3982 } while (wn.advance()); 3983 } while (wt.advance()); 3984 return true; 3985} 3986 3987// resolve any coincident pairs found while intersecting, and 3988// see if coincidence is formed by clipping non-concident segments 3989static void coincidenceCheck(SkTDArray<Contour*>& contourList) { 3990 int contourCount = contourList.count(); 3991 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 3992 Contour* contour = contourList[cIndex]; 3993 contour->resolveCoincidence(); 3994 } 3995 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 3996 Contour* contour = contourList[cIndex]; 3997 contour->findTooCloseToCall(); 3998 } 3999#if 0 4000 // OPTIMIZATION: this check could be folded in with findTooClose -- maybe 4001 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 4002 Contour* contour = contourList[cIndex]; 4003 contour->collapseTriangles(); 4004 } 4005#endif 4006} 4007 4008// project a ray from the top of the contour up and see if it hits anything 4009// note: when we compute line intersections, we keep track of whether 4010// two contours touch, so we need only look at contours not touching this one. 4011// OPTIMIZATION: sort contourList vertically to avoid linear walk 4012static int innerContourCheck(SkTDArray<Contour*>& contourList, 4013 const Segment* current, int index, int endIndex) { 4014 const SkPoint& basePt = current->xyAtT(endIndex); 4015 int contourCount = contourList.count(); 4016 SkScalar bestY = SK_ScalarMin; 4017 const Segment* test = NULL; 4018 int tIndex; 4019 double tHit; 4020 // bool checkCrosses = true; 4021 for (int cTest = 0; cTest < contourCount; ++cTest) { 4022 Contour* contour = contourList[cTest]; 4023 if (basePt.fY < contour->bounds().fTop) { 4024 continue; 4025 } 4026 if (bestY > contour->bounds().fBottom) { 4027 continue; 4028 } 4029#if 0 4030 // even though the contours crossed, if spans cancel through concidence, 4031 // the contours may be not have any span links to chase, and the current 4032 // segment may be isolated. Detect this by seeing if current has 4033 // uninitialized wind sums. If so, project a ray instead of relying on 4034 // previously found intersections. 4035 if (baseContour == contour) { 4036 continue; 4037 } 4038 if (checkCrosses && baseContour->crosses(contour)) { 4039 if (current->isConnected(index, endIndex)) { 4040 continue; 4041 } 4042 checkCrosses = false; 4043 } 4044#endif 4045 const Segment* next = contour->crossedSegment(basePt, bestY, tIndex, tHit); 4046 if (next) { 4047 test = next; 4048 } 4049 } 4050 if (!test) { 4051 return 0; 4052 } 4053 int winding, windValue; 4054 // If the ray hit the end of a span, we need to construct the wheel of 4055 // angles to find the span closest to the ray -- even if there are just 4056 // two spokes on the wheel. 4057 const Angle* angle = NULL; 4058 if (approximately_zero(tHit - test->t(tIndex))) { 4059 SkTDArray<Angle> angles; 4060 int end = test->nextSpan(tIndex, 1); 4061 if (end < 0) { 4062 end = test->nextSpan(tIndex, -1); 4063 } 4064 test->addTwoAngles(end, tIndex, angles); 4065 SkASSERT(angles.count() > 0); 4066 if (angles[0].segment()->yAtT(angles[0].start()) >= basePt.fY) { 4067#if DEBUG_SORT 4068 SkDebugf("%s early return\n", __FUNCTION__); 4069#endif 4070 return 0; 4071 } 4072 test->buildAngles(tIndex, angles); 4073 SkTDArray<Angle*> sorted; 4074 // OPTIMIZATION: call a sort that, if base point is the leftmost, 4075 // returns the first counterclockwise hour before 6 o'clock, 4076 // or if the base point is rightmost, returns the first clockwise 4077 // hour after 6 o'clock 4078 sortAngles(angles, sorted); 4079#if DEBUG_SORT 4080 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0); 4081#endif 4082 // walk the sorted angle fan to find the lowest angle 4083 // above the base point. Currently, the first angle in the sorted array 4084 // is 12 noon or an earlier hour (the next counterclockwise) 4085 int count = sorted.count(); 4086 int left = -1; 4087 int mid = -1; 4088 int right = -1; 4089 bool baseMatches = test->yAtT(tIndex) == basePt.fY; 4090 for (int index = 0; index < count; ++index) { 4091 angle = sorted[index]; 4092 if (baseMatches && angle->isHorizontal()) { 4093 continue; 4094 } 4095 double indexDx = angle->dx(); 4096 test = angle->segment(); 4097 if (test->verb() > SkPath::kLine_Verb && approximately_zero(indexDx)) { 4098 const SkPoint* pts = test->pts(); 4099 indexDx = pts[2].fX - pts[1].fX - indexDx; 4100 } 4101 if (indexDx < 0) { 4102 left = index; 4103 } else if (indexDx > 0) { 4104 right = index; 4105 int previous = index - 1; 4106 if (previous < 0) { 4107 previous = count - 1; 4108 } 4109 const Angle* prev = sorted[previous]; 4110 if (prev->dy() >= 0 && prev->dx() > 0 && angle->dy() < 0) { 4111#if DEBUG_SORT 4112 SkDebugf("%s use prev\n", __FUNCTION__); 4113#endif 4114 right = previous; 4115 } 4116 break; 4117 } else { 4118 mid = index; 4119 } 4120 } 4121 if (left < 0 && right < 0) { 4122 left = mid; 4123 } 4124 SkASSERT(left >= 0 || right >= 0); 4125 if (left < 0) { 4126 left = right; 4127 } else if (left >= 0 && mid >= 0 && right >= 0 4128 && sorted[mid]->sign() == sorted[right]->sign()) { 4129 left = right; 4130 } 4131 angle = sorted[left]; 4132 test = angle->segment(); 4133 winding = test->windSum(angle); 4134 SkASSERT(winding != SK_MinS32); 4135 windValue = test->windValue(angle); 4136#if DEBUG_WINDING 4137 SkDebugf("%s angle winding=%d windValue=%d sign=%d\n", __FUNCTION__, winding, 4138 windValue, angle->sign()); 4139#endif 4140 } else { 4141 winding = test->windSum(tIndex); 4142 SkASSERT(winding != SK_MinS32); 4143 windValue = test->windValue(tIndex); 4144#if DEBUG_WINDING 4145 SkDebugf("%s single winding=%d windValue=%d\n", __FUNCTION__, winding, 4146 windValue); 4147#endif 4148 } 4149 // see if a + change in T results in a +/- change in X (compute x'(T)) 4150 SkScalar dx = (*SegmentDXAtT[test->verb()])(test->pts(), tHit); 4151 if (test->verb() > SkPath::kLine_Verb && approximately_zero(dx)) { 4152 const SkPoint* pts = test->pts(); 4153 dx = pts[2].fX - pts[1].fX - dx; 4154 } 4155#if DEBUG_WINDING 4156 SkDebugf("%s dx=%1.9g\n", __FUNCTION__, dx); 4157#endif 4158 SkASSERT(dx != 0); 4159 if (winding * dx > 0) { // if same signs, result is negative 4160 winding += dx > 0 ? -windValue : windValue; 4161#if DEBUG_WINDING 4162 SkDebugf("%s final winding=%d\n", __FUNCTION__, winding); 4163#endif 4164 } 4165 return winding; 4166} 4167 4168// OPTIMIZATION: not crazy about linear search here to find top active y. 4169// seems like we should break down and do the sort, or maybe sort each 4170// contours' segments? 4171// Once the segment array is built, there's no reason I can think of not to 4172// sort it in Y. hmmm 4173// FIXME: return the contour found to pass to inner contour check 4174static Segment* findTopContour(SkTDArray<Contour*>& contourList) { 4175 int contourCount = contourList.count(); 4176 int cIndex = 0; 4177 Segment* topStart; 4178 SkScalar bestY = SK_ScalarMax; 4179 Contour* contour; 4180 do { 4181 contour = contourList[cIndex]; 4182 topStart = contour->topSegment(bestY); 4183 } while (!topStart && ++cIndex < contourCount); 4184 if (!topStart) { 4185 return NULL; 4186 } 4187 while (++cIndex < contourCount) { 4188 contour = contourList[cIndex]; 4189 if (bestY < contour->bounds().fTop) { 4190 continue; 4191 } 4192 SkScalar testY = SK_ScalarMax; 4193 Segment* test = contour->topSegment(testY); 4194 if (!test || bestY <= testY) { 4195 continue; 4196 } 4197 topStart = test; 4198 bestY = testY; 4199 } 4200 return topStart; 4201} 4202 4203static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) { 4204 int contourCount = contourList.count(); 4205 Segment* result; 4206 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 4207 Contour* contour = contourList[cIndex]; 4208 result = contour->undoneSegment(start, end); 4209 if (result) { 4210 return result; 4211 } 4212 } 4213 return NULL; 4214} 4215 4216 4217 4218static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex, 4219 int contourWinding) { 4220 while (chase.count()) { 4221 Span* span = chase[chase.count() - 1]; 4222 const Span& backPtr = span->fOther->span(span->fOtherIndex); 4223 Segment* segment = backPtr.fOther; 4224 tIndex = backPtr.fOtherIndex; 4225 SkTDArray<Angle> angles; 4226 int done = 0; 4227 if (segment->activeAngle(tIndex, done, angles)) { 4228 Angle* last = angles.end() - 1; 4229 tIndex = last->start(); 4230 endIndex = last->end(); 4231 return last->segment(); 4232 } 4233 if (done == angles.count()) { 4234 chase.pop(&span); 4235 continue; 4236 } 4237 SkTDArray<Angle*> sorted; 4238 sortAngles(angles, sorted); 4239#if DEBUG_SORT 4240 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0); 4241#endif 4242 // find first angle, initialize winding to computed fWindSum 4243 int firstIndex = -1; 4244 const Angle* angle; 4245 int winding; 4246 do { 4247 angle = sorted[++firstIndex]; 4248 segment = angle->segment(); 4249 winding = segment->windSum(angle); 4250 } while (winding == SK_MinS32); 4251 int spanWinding = segment->spanSign(angle->start(), angle->end()); 4252 #if DEBUG_WINDING 4253 SkDebugf("%s winding=%d spanWinding=%d contourWinding=%d\n", 4254 __FUNCTION__, winding, spanWinding, contourWinding); 4255 #endif 4256 // turn swinding into contourWinding 4257 if (spanWinding * winding < 0) { 4258 winding += spanWinding; 4259 } 4260 #if DEBUG_SORT 4261 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding); 4262 #endif 4263 // we care about first sign and whether wind sum indicates this 4264 // edge is inside or outside. Maybe need to pass span winding 4265 // or first winding or something into this function? 4266 // advance to first undone angle, then return it and winding 4267 // (to set whether edges are active or not) 4268 int nextIndex = firstIndex + 1; 4269 int angleCount = sorted.count(); 4270 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; 4271 angle = sorted[firstIndex]; 4272 winding -= angle->segment()->spanSign(angle); 4273 do { 4274 SkASSERT(nextIndex != firstIndex); 4275 if (nextIndex == angleCount) { 4276 nextIndex = 0; 4277 } 4278 angle = sorted[nextIndex]; 4279 segment = angle->segment(); 4280 int maxWinding = winding; 4281 winding -= segment->spanSign(angle); 4282 #if DEBUG_SORT 4283 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__, 4284 segment->debugID(), maxWinding, winding, angle->sign()); 4285 #endif 4286 tIndex = angle->start(); 4287 endIndex = angle->end(); 4288 int lesser = SkMin32(tIndex, endIndex); 4289 const Span& nextSpan = segment->span(lesser); 4290 if (!nextSpan.fDone) { 4291#if 1 4292 // FIXME: this be wrong. assign startWinding if edge is in 4293 // same direction. If the direction is opposite, winding to 4294 // assign is flipped sign or +/- 1? 4295 if (useInnerWinding(maxWinding, winding)) { 4296 maxWinding = winding; 4297 } 4298 segment->markWinding(lesser, maxWinding); 4299#endif 4300 break; 4301 } 4302 } while (++nextIndex != lastIndex); 4303 return segment; 4304 } 4305 return NULL; 4306} 4307 4308#if DEBUG_ACTIVE_SPANS 4309static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) { 4310 int index; 4311 for (index = 0; index < contourList.count(); ++ index) { 4312 contourList[index]->debugShowActiveSpans(); 4313 } 4314 for (index = 0; index < contourList.count(); ++ index) { 4315 contourList[index]->validateActiveSpans(); 4316 } 4317} 4318#endif 4319 4320static bool windingIsActive(int winding, int spanWinding) { 4321 return winding * spanWinding <= 0 && abs(winding) <= abs(spanWinding) 4322 && (!winding || !spanWinding || winding == -spanWinding); 4323} 4324 4325// Each segment may have an inside or an outside. Segments contained within 4326// winding may have insides on either side, and form a contour that should be 4327// ignored. Segments that are coincident with opposing direction segments may 4328// have outsides on either side, and should also disappear. 4329// 'Normal' segments will have one inside and one outside. Subsequent connections 4330// when winding should follow the intersection direction. If more than one edge 4331// is an option, choose first edge that continues the inside. 4332 // since we start with leftmost top edge, we'll traverse through a 4333 // smaller angle counterclockwise to get to the next edge. 4334static void bridgeWinding(SkTDArray<Contour*>& contourList, SkPath& simple) { 4335 bool firstContour = true; 4336 do { 4337 Segment* topStart = findTopContour(contourList); 4338 if (!topStart) { 4339 break; 4340 } 4341 // Start at the top. Above the top is outside, below is inside. 4342 // follow edges to intersection by changing the index by direction. 4343 int index, endIndex; 4344 Segment* current = topStart->findTop(index, endIndex); 4345 int contourWinding; 4346 if (firstContour) { 4347 contourWinding = 0; 4348 firstContour = false; 4349 } else { 4350 int sumWinding = current->windSum(SkMin32(index, endIndex)); 4351 // FIXME: don't I have to adjust windSum to get contourWinding? 4352 if (sumWinding == SK_MinS32) { 4353 sumWinding = current->computeSum(index, endIndex); 4354 } 4355 if (sumWinding == SK_MinS32) { 4356 contourWinding = innerContourCheck(contourList, current, 4357 index, endIndex); 4358 } else { 4359 contourWinding = sumWinding; 4360 int spanWinding = current->spanSign(index, endIndex); 4361 bool inner = useInnerWinding(sumWinding - spanWinding, sumWinding); 4362 if (inner) { 4363 contourWinding -= spanWinding; 4364 } 4365#if DEBUG_WINDING 4366 SkDebugf("%s sumWinding=%d spanWinding=%d sign=%d inner=%d result=%d\n", __FUNCTION__, 4367 sumWinding, spanWinding, SkSign32(index - endIndex), 4368 inner, contourWinding); 4369#endif 4370 } 4371#if DEBUG_WINDING 4372 // SkASSERT(current->debugVerifyWinding(index, endIndex, contourWinding)); 4373 SkDebugf("%s contourWinding=%d\n", __FUNCTION__, contourWinding); 4374#endif 4375 } 4376 SkPoint lastPt; 4377 int winding = contourWinding; 4378 int spanWinding = current->spanSign(index, endIndex); 4379 // FIXME: needs work. While it works in limited situations, it does 4380 // not always compute winding correctly. Active should be removed and instead 4381 // the initial winding should be correctly passed in so that if the 4382 // inner contour is wound the same way, it never finds an accumulated 4383 // winding of zero. Inside 'find next', we need to look for transitions 4384 // other than zero when resolving sorted angles. 4385 bool active = windingIsActive(winding, spanWinding); 4386 SkTDArray<Span*> chaseArray; 4387 do { 4388 #if DEBUG_WINDING 4389 SkDebugf("%s active=%s winding=%d spanWinding=%d\n", 4390 __FUNCTION__, active ? "true" : "false", 4391 winding, spanWinding); 4392 #endif 4393 const SkPoint* firstPt = NULL; 4394 do { 4395 SkASSERT(!current->done()); 4396 int nextStart = index; 4397 int nextEnd = endIndex; 4398 Segment* next = current->findNextWinding(chaseArray, active, 4399 nextStart, nextEnd, winding, spanWinding); 4400 if (!next) { 4401 if (active && firstPt && current->verb() != SkPath::kLine_Verb && *firstPt != lastPt) { 4402 lastPt = current->addCurveTo(index, endIndex, simple, true); 4403 SkASSERT(*firstPt == lastPt); 4404 } 4405 break; 4406 } 4407 if (!firstPt) { 4408 firstPt = ¤t->addMoveTo(index, simple, active); 4409 } 4410 lastPt = current->addCurveTo(index, endIndex, simple, active); 4411 current = next; 4412 index = nextStart; 4413 endIndex = nextEnd; 4414 } while (*firstPt != lastPt && (active || !current->done())); 4415 if (firstPt && active) { 4416 #if DEBUG_PATH_CONSTRUCTION 4417 SkDebugf("path.close();\n"); 4418 #endif 4419 simple.close(); 4420 } 4421 current = findChase(chaseArray, index, endIndex, contourWinding); 4422 #if DEBUG_ACTIVE_SPANS 4423 debugShowActiveSpans(contourList); 4424 #endif 4425 if (!current) { 4426 break; 4427 } 4428 int lesser = SkMin32(index, endIndex); 4429 spanWinding = current->spanSign(index, endIndex); 4430 winding = current->windSum(lesser); 4431 bool inner = useInnerWinding(winding - spanWinding, winding); 4432 #if DEBUG_WINDING 4433 SkDebugf("%s id=%d t=%1.9g spanWinding=%d winding=%d sign=%d" 4434 " inner=%d result=%d\n", 4435 __FUNCTION__, current->debugID(), current->t(lesser), 4436 spanWinding, winding, SkSign32(index - endIndex), 4437 useInnerWinding(winding - spanWinding, winding), 4438 inner ? winding - spanWinding : winding); 4439 #endif 4440 if (inner) { 4441 winding -= spanWinding; 4442 } 4443 active = windingIsActive(winding, spanWinding); 4444 } while (true); 4445 } while (true); 4446} 4447 4448static void bridgeXor(SkTDArray<Contour*>& contourList, SkPath& simple) { 4449 Segment* current; 4450 int start, end; 4451 while ((current = findUndone(contourList, start, end))) { 4452 const SkPoint* firstPt = NULL; 4453 SkPoint lastPt; 4454 do { 4455 SkASSERT(!current->done()); 4456 int nextStart = start; 4457 int nextEnd = end; 4458 Segment* next = current->findNextXor(nextStart, nextEnd); 4459 if (!next) { 4460 if (firstPt && current->verb() != SkPath::kLine_Verb && *firstPt != lastPt) { 4461 lastPt = current->addCurveTo(start, end, simple, true); 4462 SkASSERT(*firstPt == lastPt); 4463 } 4464 break; 4465 } 4466 if (!firstPt) { 4467 firstPt = ¤t->addMoveTo(start, simple, true); 4468 } 4469 lastPt = current->addCurveTo(start, end, simple, true); 4470 current = next; 4471 start = nextStart; 4472 end = nextEnd; 4473 } while (*firstPt != lastPt); 4474 if (firstPt) { 4475 #if DEBUG_PATH_CONSTRUCTION 4476 SkDebugf("%s close\n", __FUNCTION__); 4477 #endif 4478 simple.close(); 4479 } 4480 #if DEBUG_ACTIVE_SPANS 4481 debugShowActiveSpans(contourList); 4482 #endif 4483 } 4484} 4485 4486static void fixOtherTIndex(SkTDArray<Contour*>& contourList) { 4487 int contourCount = contourList.count(); 4488 for (int cTest = 0; cTest < contourCount; ++cTest) { 4489 Contour* contour = contourList[cTest]; 4490 contour->fixOtherTIndex(); 4491 } 4492} 4493 4494static void makeContourList(SkTArray<Contour>& contours, 4495 SkTDArray<Contour*>& list) { 4496 int count = contours.count(); 4497 if (count == 0) { 4498 return; 4499 } 4500 for (int index = 0; index < count; ++index) { 4501 *list.append() = &contours[index]; 4502 } 4503 QSort<Contour>(list.begin(), list.end() - 1); 4504} 4505 4506void simplifyx(const SkPath& path, SkPath& simple) { 4507 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness 4508 simple.reset(); 4509 simple.setFillType(SkPath::kEvenOdd_FillType); 4510 4511 // turn path into list of segments 4512 SkTArray<Contour> contours; 4513 // FIXME: add self-intersecting cubics' T values to segment 4514 EdgeBuilder builder(path, contours); 4515 builder.finish(); 4516 SkTDArray<Contour*> contourList; 4517 makeContourList(contours, contourList); 4518 Contour** currentPtr = contourList.begin(); 4519 if (!currentPtr) { 4520 return; 4521 } 4522 Contour** listEnd = contourList.end(); 4523 // find all intersections between segments 4524 do { 4525 Contour** nextPtr = currentPtr; 4526 Contour* current = *currentPtr++; 4527 Contour* next; 4528 do { 4529 next = *nextPtr++; 4530 } while (addIntersectTs(current, next) && nextPtr != listEnd); 4531 } while (currentPtr != listEnd); 4532 // eat through coincident edges 4533 coincidenceCheck(contourList); 4534 fixOtherTIndex(contourList); 4535 // construct closed contours 4536 if (builder.xorMask() == kWinding_Mask) { 4537 bridgeWinding(contourList, simple); 4538 } else { 4539 bridgeXor(contourList, simple); 4540 } 4541} 4542 4543