Simplify.cpp revision 4aaaaeace7e617ddc473645756fb7c20790bc270
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 PIN_ADD_T 0 29#define TRY_ROTATE 1 30#define ONE_PASS_COINCIDENCE_CHECK 0 31#define APPROXIMATE_CUBICS 1 32 33#define DEBUG_UNUSED 0 // set to expose unused functions 34 35#define FORCE_RELEASE 0 // set force release to 1 for multiple thread -- no debugging 36 37#if FORCE_RELEASE || defined SK_RELEASE 38 39const bool gRunTestsInOneThread = false; 40 41#define DEBUG_ACTIVE_OP 0 42#define DEBUG_ACTIVE_SPANS 0 43#define DEBUG_ACTIVE_SPANS_SHORT_FORM 0 44#define DEBUG_ADD_INTERSECTING_TS 0 45#define DEBUG_ADD_T_PAIR 0 46#define DEBUG_ANGLE 0 47#define DEBUG_AS_C_CODE 1 48#define DEBUG_ASSEMBLE 0 49#define DEBUG_CONCIDENT 0 50#define DEBUG_CROSS 0 51#define DEBUG_FLOW 0 52#define DEBUG_MARK_DONE 0 53#define DEBUG_PATH_CONSTRUCTION 0 54#define DEBUG_SHOW_WINDING 0 55#define DEBUG_SORT 0 56#define DEBUG_SWAP_TOP 0 57#define DEBUG_UNSORTABLE 0 58#define DEBUG_WIND_BUMP 0 59#define DEBUG_WINDING 0 60#define DEBUG_WINDING_AT_T 0 61 62#else 63 64const bool gRunTestsInOneThread = true; 65 66#define DEBUG_ACTIVE_OP 1 67#define DEBUG_ACTIVE_SPANS 1 68#define DEBUG_ACTIVE_SPANS_SHORT_FORM 1 69#define DEBUG_ADD_INTERSECTING_TS 1 70#define DEBUG_ADD_T_PAIR 1 71#define DEBUG_ANGLE 1 72#define DEBUG_AS_C_CODE 1 73#define DEBUG_ASSEMBLE 1 74#define DEBUG_CONCIDENT 1 75#define DEBUG_CROSS 0 76#define DEBUG_FLOW 1 77#define DEBUG_MARK_DONE 1 78#define DEBUG_PATH_CONSTRUCTION 1 79#define DEBUG_SHOW_WINDING 0 80#define DEBUG_SORT 1 81#define DEBUG_SWAP_TOP 1 82#define DEBUG_UNSORTABLE 1 83#define DEBUG_WIND_BUMP 0 84#define DEBUG_WINDING 1 85#define DEBUG_WINDING_AT_T 1 86 87#endif 88 89#define DEBUG_DUMP (DEBUG_ACTIVE_OP | DEBUG_ACTIVE_SPANS | DEBUG_CONCIDENT | DEBUG_SORT | \ 90 DEBUG_PATH_CONSTRUCTION) 91 92#if DEBUG_DUMP 93static const char* kLVerbStr[] = {"", "line", "quad", "cubic"}; 94// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"}; 95static int gContourID; 96static int gSegmentID; 97#endif 98 99#if DEBUG_SORT 100static int gDebugSortCountDefault = SK_MaxS32; 101static int gDebugSortCount; 102#endif 103 104#if DEBUG_ACTIVE_OP 105static const char* kShapeOpStr[] = {"diff", "sect", "union", "xor"}; 106#endif 107 108#ifndef DEBUG_TEST 109#define DEBUG_TEST 0 110#endif 111 112#define MAKE_CONST_LINE(line, pts) \ 113 const _Line line = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}} 114#define MAKE_CONST_QUAD(quad, pts) \ 115 const Quadratic quad = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \ 116 {pts[2].fX, pts[2].fY}} 117#define MAKE_CONST_CUBIC(cubic, pts) \ 118 const Cubic cubic = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}, \ 119 {pts[2].fX, pts[2].fY}, {pts[3].fX, pts[3].fY}} 120 121static int LineIntersect(const SkPoint a[2], const SkPoint b[2], 122 Intersections& intersections) { 123 MAKE_CONST_LINE(aLine, a); 124 MAKE_CONST_LINE(bLine, b); 125 return intersect(aLine, bLine, intersections); 126} 127 128static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2], 129 Intersections& intersections) { 130 MAKE_CONST_QUAD(aQuad, a); 131 MAKE_CONST_LINE(bLine, b); 132 return intersect(aQuad, bLine, intersections); 133} 134 135static int CubicLineIntersect(const SkPoint a[4], const SkPoint b[2], 136 Intersections& intersections) { 137 MAKE_CONST_CUBIC(aCubic, a); 138 MAKE_CONST_LINE(bLine, b); 139 return intersect(aCubic, bLine, intersections); 140} 141 142static int QuadIntersect(const SkPoint a[3], const SkPoint b[3], 143 Intersections& intersections) { 144 MAKE_CONST_QUAD(aQuad, a); 145 MAKE_CONST_QUAD(bQuad, b); 146#define TRY_QUARTIC_SOLUTION 1 147#if TRY_QUARTIC_SOLUTION 148 intersect2(aQuad, bQuad, intersections); 149#else 150 intersect(aQuad, bQuad, intersections); 151#endif 152 return intersections.fUsed; 153} 154 155#if APPROXIMATE_CUBICS 156static int CubicQuadIntersect(const SkPoint a[4], const SkPoint b[3], 157 Intersections& intersections) { 158 MAKE_CONST_CUBIC(aCubic, a); 159 MAKE_CONST_QUAD(bQuad, b); 160 return intersect(aCubic, bQuad, intersections); 161} 162#endif 163 164static int CubicIntersect(const SkPoint a[4], const SkPoint b[4], Intersections& intersections) { 165 MAKE_CONST_CUBIC(aCubic, a); 166 MAKE_CONST_CUBIC(bCubic, b); 167#if APPROXIMATE_CUBICS 168 intersect3(aCubic, bCubic, intersections); 169#else 170 intersect(aCubic, bCubic, intersections); 171#endif 172 return intersections.fUsed; 173} 174 175static int CubicIntersect(const SkPoint a[4], Intersections& intersections) { 176 MAKE_CONST_CUBIC(aCubic, a); 177 return intersect(aCubic, intersections); 178} 179 180static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right, 181 SkScalar y, bool flipped, Intersections& intersections) { 182 MAKE_CONST_LINE(aLine, a); 183 return horizontalIntersect(aLine, left, right, y, flipped, intersections); 184} 185 186static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right, 187 SkScalar y, bool flipped, Intersections& intersections) { 188 MAKE_CONST_QUAD(aQuad, a); 189 return horizontalIntersect(aQuad, left, right, y, flipped, intersections); 190} 191 192static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right, 193 SkScalar y, bool flipped, Intersections& intersections) { 194 MAKE_CONST_CUBIC(aCubic, a); 195 return horizontalIntersect(aCubic, left, right, y, flipped, intersections); 196} 197 198static int (* const HSegmentIntersect[])(const SkPoint [], SkScalar , 199 SkScalar , SkScalar , bool , Intersections& ) = { 200 NULL, 201 HLineIntersect, 202 HQuadIntersect, 203 HCubicIntersect 204}; 205 206static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom, 207 SkScalar x, bool flipped, Intersections& intersections) { 208 MAKE_CONST_LINE(aLine, a); 209 return verticalIntersect(aLine, top, bottom, x, flipped, intersections); 210} 211 212static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom, 213 SkScalar x, bool flipped, Intersections& intersections) { 214 MAKE_CONST_QUAD(aQuad, a); 215 return verticalIntersect(aQuad, top, bottom, x, flipped, intersections); 216} 217 218static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom, 219 SkScalar x, bool flipped, Intersections& intersections) { 220 MAKE_CONST_CUBIC(aCubic, a); 221 return verticalIntersect(aCubic, top, bottom, x, flipped, intersections); 222} 223 224static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar , 225 SkScalar , SkScalar , bool , Intersections& ) = { 226 NULL, 227 VLineIntersect, 228 VQuadIntersect, 229 VCubicIntersect 230}; 231 232static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) { 233 MAKE_CONST_LINE(line, a); 234 double x, y; 235 xy_at_t(line, t, x, y); 236 out->fX = SkDoubleToScalar(x); 237 out->fY = SkDoubleToScalar(y); 238} 239 240static void LineXYAtT(const SkPoint a[2], double t, _Point* out) { 241 MAKE_CONST_LINE(line, a); 242 xy_at_t(line, t, out->x, out->y); 243} 244 245static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) { 246 MAKE_CONST_QUAD(quad, a); 247 double x, y; 248 xy_at_t(quad, t, x, y); 249 out->fX = SkDoubleToScalar(x); 250 out->fY = SkDoubleToScalar(y); 251} 252 253static void QuadXYAtT(const SkPoint a[3], double t, _Point* out) { 254 MAKE_CONST_QUAD(quad, a); 255 xy_at_t(quad, t, out->x, out->y); 256} 257 258static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) { 259 MAKE_CONST_CUBIC(cubic, a); 260 double x, y; 261 xy_at_t(cubic, t, x, y); 262 out->fX = SkDoubleToScalar(x); 263 out->fY = SkDoubleToScalar(y); 264} 265 266static void CubicXYAtT(const SkPoint a[4], double t, _Point* out) { 267 MAKE_CONST_CUBIC(cubic, a); 268 xy_at_t(cubic, t, out->x, out->y); 269} 270 271static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = { 272 NULL, 273 LineXYAtT, 274 QuadXYAtT, 275 CubicXYAtT 276}; 277 278static void (* const SegmentXYAtT2[])(const SkPoint [], double , _Point* ) = { 279 NULL, 280 LineXYAtT, 281 QuadXYAtT, 282 CubicXYAtT 283}; 284 285static SkScalar LineXAtT(const SkPoint a[2], double t) { 286 MAKE_CONST_LINE(aLine, a); 287 double x; 288 xy_at_t(aLine, t, x, *(double*) 0); 289 return SkDoubleToScalar(x); 290} 291 292static SkScalar QuadXAtT(const SkPoint a[3], double t) { 293 MAKE_CONST_QUAD(quad, a); 294 double x; 295 xy_at_t(quad, t, x, *(double*) 0); 296 return SkDoubleToScalar(x); 297} 298 299static SkScalar CubicXAtT(const SkPoint a[4], double t) { 300 MAKE_CONST_CUBIC(cubic, a); 301 double x; 302 xy_at_t(cubic, t, x, *(double*) 0); 303 return SkDoubleToScalar(x); 304} 305 306static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = { 307 NULL, 308 LineXAtT, 309 QuadXAtT, 310 CubicXAtT 311}; 312 313static SkScalar LineYAtT(const SkPoint a[2], double t) { 314 MAKE_CONST_LINE(aLine, a); 315 double y; 316 xy_at_t(aLine, t, *(double*) 0, y); 317 return SkDoubleToScalar(y); 318} 319 320static SkScalar QuadYAtT(const SkPoint a[3], double t) { 321 MAKE_CONST_QUAD(quad, a); 322 double y; 323 xy_at_t(quad, t, *(double*) 0, y); 324 return SkDoubleToScalar(y); 325} 326 327static SkScalar CubicYAtT(const SkPoint a[4], double t) { 328 MAKE_CONST_CUBIC(cubic, a); 329 double y; 330 xy_at_t(cubic, t, *(double*) 0, y); 331 return SkDoubleToScalar(y); 332} 333 334static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = { 335 NULL, 336 LineYAtT, 337 QuadYAtT, 338 CubicYAtT 339}; 340 341static SkScalar LineDXAtT(const SkPoint a[2], double ) { 342 return a[1].fX - a[0].fX; 343} 344 345static SkScalar QuadDXAtT(const SkPoint a[3], double t) { 346 MAKE_CONST_QUAD(quad, a); 347 double x = dx_at_t(quad, t); 348 return SkDoubleToScalar(x); 349} 350 351static SkScalar CubicDXAtT(const SkPoint a[4], double t) { 352 MAKE_CONST_CUBIC(cubic, a); 353 double x = dx_at_t(cubic, t); 354 return SkDoubleToScalar(x); 355} 356 357static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = { 358 NULL, 359 LineDXAtT, 360 QuadDXAtT, 361 CubicDXAtT 362}; 363 364static SkScalar LineDYAtT(const SkPoint a[2], double ) { 365 return a[1].fY - a[0].fY; 366} 367 368static SkScalar QuadDYAtT(const SkPoint a[3], double t) { 369 MAKE_CONST_QUAD(quad, a); 370 double y = dy_at_t(quad, t); 371 return SkDoubleToScalar(y); 372} 373 374static SkScalar CubicDYAtT(const SkPoint a[4], double t) { 375 MAKE_CONST_CUBIC(cubic, a); 376 double y = dy_at_t(cubic, t); 377 return SkDoubleToScalar(y); 378} 379 380static SkScalar (* const SegmentDYAtT[])(const SkPoint [], double ) = { 381 NULL, 382 LineDYAtT, 383 QuadDYAtT, 384 CubicDYAtT 385}; 386 387static SkVector LineDXDYAtT(const SkPoint a[2], double ) { 388 return a[1] - a[0]; 389} 390 391static SkVector QuadDXDYAtT(const SkPoint a[3], double t) { 392 MAKE_CONST_QUAD(quad, a); 393 _Vector v = dxdy_at_t(quad, t); 394 return v.asSkVector(); 395} 396 397static SkVector CubicDXDYAtT(const SkPoint a[4], double t) { 398 MAKE_CONST_CUBIC(cubic, a); 399 _Vector v = dxdy_at_t(cubic, t); 400 return v.asSkVector(); 401} 402 403static SkVector (* const SegmentDXDYAtT[])(const SkPoint [], double ) = { 404 NULL, 405 LineDXDYAtT, 406 QuadDXDYAtT, 407 CubicDXDYAtT 408}; 409 410static void LineSubDivide(const SkPoint a[2], double startT, double endT, 411 SkPoint sub[2]) { 412 MAKE_CONST_LINE(aLine, a); 413 _Line dst; 414 sub_divide(aLine, startT, endT, dst); 415 sub[0].fX = SkDoubleToScalar(dst[0].x); 416 sub[0].fY = SkDoubleToScalar(dst[0].y); 417 sub[1].fX = SkDoubleToScalar(dst[1].x); 418 sub[1].fY = SkDoubleToScalar(dst[1].y); 419} 420 421static void QuadSubDivide(const SkPoint a[3], double startT, double endT, 422 SkPoint sub[3]) { 423 MAKE_CONST_QUAD(aQuad, a); 424 Quadratic dst; 425 sub_divide(aQuad, startT, endT, dst); 426 sub[0].fX = SkDoubleToScalar(dst[0].x); 427 sub[0].fY = SkDoubleToScalar(dst[0].y); 428 sub[1].fX = SkDoubleToScalar(dst[1].x); 429 sub[1].fY = SkDoubleToScalar(dst[1].y); 430 sub[2].fX = SkDoubleToScalar(dst[2].x); 431 sub[2].fY = SkDoubleToScalar(dst[2].y); 432} 433 434static void CubicSubDivide(const SkPoint a[4], double startT, double endT, 435 SkPoint sub[4]) { 436 MAKE_CONST_CUBIC(aCubic, a); 437 Cubic dst; 438 sub_divide(aCubic, startT, endT, dst); 439 sub[0].fX = SkDoubleToScalar(dst[0].x); 440 sub[0].fY = SkDoubleToScalar(dst[0].y); 441 sub[1].fX = SkDoubleToScalar(dst[1].x); 442 sub[1].fY = SkDoubleToScalar(dst[1].y); 443 sub[2].fX = SkDoubleToScalar(dst[2].x); 444 sub[2].fY = SkDoubleToScalar(dst[2].y); 445 sub[3].fX = SkDoubleToScalar(dst[3].x); 446 sub[3].fY = SkDoubleToScalar(dst[3].y); 447} 448 449static void (* const SegmentSubDivide[])(const SkPoint [], double , double , 450 SkPoint []) = { 451 NULL, 452 LineSubDivide, 453 QuadSubDivide, 454 CubicSubDivide 455}; 456 457static void LineSubDivideHD(const SkPoint a[2], double startT, double endT, _Line& dst) { 458 MAKE_CONST_LINE(aLine, a); 459 sub_divide(aLine, startT, endT, dst); 460} 461 462static void QuadSubDivideHD(const SkPoint a[3], double startT, double endT, Quadratic& dst) { 463 MAKE_CONST_QUAD(aQuad, a); 464 sub_divide(aQuad, startT, endT, dst); 465} 466 467static void CubicSubDivideHD(const SkPoint a[4], double startT, double endT, Cubic& dst) { 468 MAKE_CONST_CUBIC(aCubic, a); 469 sub_divide(aCubic, startT, endT, dst); 470} 471 472static SkPoint QuadTop(const SkPoint a[3], double startT, double endT) { 473 MAKE_CONST_QUAD(quad, a); 474 _Point topPt = top(quad, startT, endT); 475 return topPt.asSkPoint(); 476} 477 478static SkPoint CubicTop(const SkPoint a[3], double startT, double endT) { 479 MAKE_CONST_CUBIC(cubic, a); 480 _Point topPt = top(cubic, startT, endT); 481 return topPt.asSkPoint(); 482} 483 484static SkPoint (* SegmentTop[])(const SkPoint[], double , double ) = { 485 NULL, 486 NULL, 487 QuadTop, 488 CubicTop 489}; 490 491#if DEBUG_UNUSED 492static void QuadSubBounds(const SkPoint a[3], double startT, double endT, 493 SkRect& bounds) { 494 SkPoint dst[3]; 495 QuadSubDivide(a, startT, endT, dst); 496 bounds.fLeft = bounds.fRight = dst[0].fX; 497 bounds.fTop = bounds.fBottom = dst[0].fY; 498 for (int index = 1; index < 3; ++index) { 499 bounds.growToInclude(dst[index].fX, dst[index].fY); 500 } 501} 502 503static void CubicSubBounds(const SkPoint a[4], double startT, double endT, 504 SkRect& bounds) { 505 SkPoint dst[4]; 506 CubicSubDivide(a, startT, endT, dst); 507 bounds.fLeft = bounds.fRight = dst[0].fX; 508 bounds.fTop = bounds.fBottom = dst[0].fY; 509 for (int index = 1; index < 4; ++index) { 510 bounds.growToInclude(dst[index].fX, dst[index].fY); 511 } 512} 513#endif 514 515static SkPath::Verb QuadReduceOrder(const SkPoint a[3], 516 SkTDArray<SkPoint>& reducePts) { 517 MAKE_CONST_QUAD(aQuad, a); 518 Quadratic dst; 519 int order = reduceOrder(aQuad, dst, kReduceOrder_TreatAsFill); 520 if (order == 2) { // quad became line 521 for (int index = 0; index < order; ++index) { 522 SkPoint* pt = reducePts.append(); 523 pt->fX = SkDoubleToScalar(dst[index].x); 524 pt->fY = SkDoubleToScalar(dst[index].y); 525 } 526 } 527 return (SkPath::Verb) (order - 1); 528} 529 530static SkPath::Verb CubicReduceOrder(const SkPoint a[4], 531 SkTDArray<SkPoint>& reducePts) { 532 MAKE_CONST_CUBIC(aCubic, a); 533 Cubic dst; 534 int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed, kReduceOrder_TreatAsFill); 535 if (order == 2 || order == 3) { // cubic became line or quad 536 for (int index = 0; index < order; ++index) { 537 SkPoint* pt = reducePts.append(); 538 pt->fX = SkDoubleToScalar(dst[index].x); 539 pt->fY = SkDoubleToScalar(dst[index].y); 540 } 541 } 542 return (SkPath::Verb) (order - 1); 543} 544 545static bool QuadIsLinear(const SkPoint a[3]) { 546 MAKE_CONST_QUAD(aQuad, a); 547 return isLinear(aQuad, 0, 2); 548} 549 550static bool CubicIsLinear(const SkPoint a[4]) { 551 MAKE_CONST_CUBIC(aCubic, a); 552 return isLinear(aCubic, 0, 3); 553} 554 555static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) { 556 MAKE_CONST_LINE(aLine, a); 557 double x[2]; 558 xy_at_t(aLine, startT, x[0], *(double*) 0); 559 xy_at_t(aLine, endT, x[1], *(double*) 0); 560 return SkMinScalar((float) x[0], (float) x[1]); 561} 562 563static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) { 564 MAKE_CONST_QUAD(aQuad, a); 565 return (float) leftMostT(aQuad, startT, endT); 566} 567 568static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) { 569 MAKE_CONST_CUBIC(aCubic, a); 570 return (float) leftMostT(aCubic, startT, endT); 571} 572 573static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = { 574 NULL, 575 LineLeftMost, 576 QuadLeftMost, 577 CubicLeftMost 578}; 579 580#if 0 // currently unused 581static int QuadRayIntersect(const SkPoint a[3], const SkPoint b[2], 582 Intersections& intersections) { 583 MAKE_CONST_QUAD(aQuad, a); 584 MAKE_CONST_LINE(bLine, b); 585 return intersectRay(aQuad, bLine, intersections); 586} 587#endif 588 589static int QuadRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) { 590 MAKE_CONST_QUAD(aQuad, a); 591 return intersectRay(aQuad, bLine, intersections); 592} 593 594static int CubicRayIntersect(const SkPoint a[3], const _Line& bLine, Intersections& intersections) { 595 MAKE_CONST_CUBIC(aCubic, a); 596 return intersectRay(aCubic, bLine, intersections); 597} 598 599static int (* const SegmentRayIntersect[])(const SkPoint [], const _Line& , Intersections&) = { 600 NULL, 601 NULL, 602 QuadRayIntersect, 603 CubicRayIntersect 604}; 605 606 607 608static bool LineVertical(const SkPoint a[2], double startT, double endT) { 609 MAKE_CONST_LINE(aLine, a); 610 double x[2]; 611 xy_at_t(aLine, startT, x[0], *(double*) 0); 612 xy_at_t(aLine, endT, x[1], *(double*) 0); 613 return AlmostEqualUlps((float) x[0], (float) x[1]); 614} 615 616static bool QuadVertical(const SkPoint a[3], double startT, double endT) { 617 SkPoint dst[3]; 618 QuadSubDivide(a, startT, endT, dst); 619 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX); 620} 621 622static bool CubicVertical(const SkPoint a[4], double startT, double endT) { 623 SkPoint dst[4]; 624 CubicSubDivide(a, startT, endT, dst); 625 return AlmostEqualUlps(dst[0].fX, dst[1].fX) && AlmostEqualUlps(dst[1].fX, dst[2].fX) 626 && AlmostEqualUlps(dst[2].fX, dst[3].fX); 627} 628 629static bool (* const SegmentVertical[])(const SkPoint [], double , double) = { 630 NULL, 631 LineVertical, 632 QuadVertical, 633 CubicVertical 634}; 635 636class Segment; 637 638struct Span { 639 Segment* fOther; 640 mutable SkPoint fPt; // lazily computed as needed 641 double fT; 642 double fOtherT; // value at fOther[fOtherIndex].fT 643 int fOtherIndex; // can't be used during intersection 644 int fWindSum; // accumulated from contours surrounding this one. 645 int fOppSum; // for binary operators: the opposite winding sum 646 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident 647 int fOppValue; // normally 0 -- when binary coincident edges combine, opp value goes here 648 bool fDone; // if set, this span to next higher T has been processed 649 bool fUnsortableStart; // set when start is part of an unsortable pair 650 bool fUnsortableEnd; // set when end is part of an unsortable pair 651 bool fTiny; // if set, span may still be considered once for edge following 652 bool fLoop; // set when a cubic loops back to this point 653}; 654 655// sorting angles 656// given angles of {dx dy ddx ddy dddx dddy} sort them 657class Angle { 658public: 659 // FIXME: this is bogus for quads and cubics 660 // if the quads and cubics' line from end pt to ctrl pt are coincident, 661 // there's no obvious way to determine the curve ordering from the 662 // derivatives alone. In particular, if one quadratic's coincident tangent 663 // is longer than the other curve, the final control point can place the 664 // longer curve on either side of the shorter one. 665 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf 666 // may provide some help, but nothing has been figured out yet. 667 668 /*( 669 for quads and cubics, set up a parameterized line (e.g. LineParameters ) 670 for points [0] to [1]. See if point [2] is on that line, or on one side 671 or the other. If it both quads' end points are on the same side, choose 672 the shorter tangent. If the tangents are equal, choose the better second 673 tangent angle 674 675 maybe I could set up LineParameters lazily 676 */ 677 bool operator<(const Angle& rh) const { 678 double y = dy(); 679 double ry = rh.dy(); 680 if ((y < 0) ^ (ry < 0)) { // OPTIMIZATION: better to use y * ry < 0 ? 681 return y < 0; 682 } 683 double x = dx(); 684 double rx = rh.dx(); 685 if (y == 0 && ry == 0 && x * rx < 0) { 686 return x < rx; 687 } 688 double x_ry = x * ry; 689 double rx_y = rx * y; 690 double cmp = x_ry - rx_y; 691 if (!approximately_zero(cmp)) { 692 return cmp < 0; 693 } 694 if (approximately_zero(x_ry) && approximately_zero(rx_y) 695 && !approximately_zero_squared(cmp)) { 696 return cmp < 0; 697 } 698 // at this point, the initial tangent line is coincident 699 // see if edges curl away from each other 700 if (fSide * rh.fSide <= 0 && (!approximately_zero(fSide) 701 || !approximately_zero(rh.fSide))) { 702 // FIXME: running demo will trigger this assertion 703 // (don't know if commenting out will trigger further assertion or not) 704 // commenting it out allows demo to run in release, though 705 // SkASSERT(fSide != rh.fSide); 706 return fSide < rh.fSide; 707 } 708 // see if either curve can be lengthened and try the tangent compare again 709 if (cmp && (*fSpans)[fEnd].fOther != rh.fSegment // tangents not absolutely identical 710 && (*rh.fSpans)[rh.fEnd].fOther != fSegment) { // and not intersecting 711 Angle longer = *this; 712 Angle rhLonger = rh; 713 if (longer.lengthen() | rhLonger.lengthen()) { 714 return longer < rhLonger; 715 } 716 #if 0 717 // what if we extend in the other direction? 718 longer = *this; 719 rhLonger = rh; 720 if (longer.reverseLengthen() | rhLonger.reverseLengthen()) { 721 return longer < rhLonger; 722 } 723 #endif 724 } 725 if ((fVerb == SkPath::kLine_Verb && approximately_zero(x) && approximately_zero(y)) 726 || (rh.fVerb == SkPath::kLine_Verb 727 && approximately_zero(rx) && approximately_zero(ry))) { 728 // See general unsortable comment below. This case can happen when 729 // one line has a non-zero change in t but no change in x and y. 730 fUnsortable = true; 731 rh.fUnsortable = true; 732 return this < &rh; // even with no solution, return a stable sort 733 } 734 if ((*rh.fSpans)[SkMin32(rh.fStart, rh.fEnd)].fTiny 735 || (*fSpans)[SkMin32(fStart, fEnd)].fTiny) { 736 fUnsortable = true; 737 rh.fUnsortable = true; 738 return this < &rh; // even with no solution, return a stable sort 739 } 740 SkASSERT(fVerb >= SkPath::kQuad_Verb); 741 SkASSERT(rh.fVerb >= SkPath::kQuad_Verb); 742 // FIXME: until I can think of something better, project a ray from the 743 // end of the shorter tangent to midway between the end points 744 // through both curves and use the resulting angle to sort 745 // FIXME: some of this setup can be moved to set() if it works, or cached if it's expensive 746 double len = fTangent1.normalSquared(); 747 double rlen = rh.fTangent1.normalSquared(); 748 _Line ray; 749 Intersections i, ri; 750 int roots, rroots; 751 bool flip = false; 752 do { 753 bool useThis = (len < rlen) ^ flip; 754 const Cubic& part = useThis ? fCurvePart : rh.fCurvePart; 755 SkPath::Verb partVerb = useThis ? fVerb : rh.fVerb; 756 ray[0] = partVerb == SkPath::kCubic_Verb && part[0].approximatelyEqual(part[1]) ? 757 part[2] : part[1]; 758 ray[1].x = (part[0].x + part[partVerb].x) / 2; 759 ray[1].y = (part[0].y + part[partVerb].y) / 2; 760 SkASSERT(ray[0] != ray[1]); 761 roots = (*SegmentRayIntersect[fVerb])(fPts, ray, i); 762 rroots = (*SegmentRayIntersect[rh.fVerb])(rh.fPts, ray, ri); 763 } while ((roots == 0 || rroots == 0) && (flip ^= true)); 764 if (roots == 0 || rroots == 0) { 765 // FIXME: we don't have a solution in this case. The interim solution 766 // is to mark the edges as unsortable, exclude them from this and 767 // future computations, and allow the returned path to be fragmented 768 fUnsortable = true; 769 rh.fUnsortable = true; 770 return this < &rh; // even with no solution, return a stable sort 771 } 772 _Point loc; 773 double best = SK_ScalarInfinity; 774 double dx, dy, dist; 775 int index; 776 for (index = 0; index < roots; ++index) { 777 (*SegmentXYAtT2[fVerb])(fPts, i.fT[0][index], &loc); 778 dx = loc.x - ray[0].x; 779 dy = loc.y - ray[0].y; 780 dist = dx * dx + dy * dy; 781 if (best > dist) { 782 best = dist; 783 } 784 } 785 for (index = 0; index < rroots; ++index) { 786 (*SegmentXYAtT2[rh.fVerb])(rh.fPts, ri.fT[0][index], &loc); 787 dx = loc.x - ray[0].x; 788 dy = loc.y - ray[0].y; 789 dist = dx * dx + dy * dy; 790 if (best > dist) { 791 return fSide < 0; 792 } 793 } 794 return fSide > 0; 795 } 796 797 double dx() const { 798 return fTangent1.dx(); 799 } 800 801 double dy() const { 802 return fTangent1.dy(); 803 } 804 805 int end() const { 806 return fEnd; 807 } 808 809 bool isHorizontal() const { 810 return dy() == 0 && fVerb == SkPath::kLine_Verb; 811 } 812 813 bool lengthen() { 814 int newEnd = fEnd; 815 if (fStart < fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) { 816 fEnd = newEnd; 817 setSpans(); 818 return true; 819 } 820 return false; 821 } 822 823 bool reverseLengthen() { 824 if (fReversed) { 825 return false; 826 } 827 int newEnd = fStart; 828 if (fStart > fEnd ? ++newEnd < fSpans->count() : --newEnd >= 0) { 829 fEnd = newEnd; 830 fReversed = true; 831 setSpans(); 832 return true; 833 } 834 return false; 835 } 836 837 void set(const SkPoint* orig, SkPath::Verb verb, const Segment* segment, 838 int start, int end, const SkTDArray<Span>& spans) { 839 fSegment = segment; 840 fStart = start; 841 fEnd = end; 842 fPts = orig; 843 fVerb = verb; 844 fSpans = &spans; 845 fReversed = false; 846 fUnsortable = false; 847 setSpans(); 848 } 849 850 851 void setSpans() { 852 double startT = (*fSpans)[fStart].fT; 853 double endT = (*fSpans)[fEnd].fT; 854 switch (fVerb) { 855 case SkPath::kLine_Verb: 856 _Line l; 857 LineSubDivideHD(fPts, startT, endT, l); 858 // OPTIMIZATION: for pure line compares, we never need fTangent1.c 859 fTangent1.lineEndPoints(l); 860 fSide = 0; 861 break; 862 case SkPath::kQuad_Verb: { 863 Quadratic& quad = (Quadratic&)fCurvePart; 864 QuadSubDivideHD(fPts, startT, endT, quad); 865 fTangent1.quadEndPoints(quad, 0, 1); 866 if (dx() == 0 && dy() == 0) { 867 // SkDebugf("*** %s quad is line\n", __FUNCTION__); 868 fTangent1.quadEndPoints(quad); 869 } 870 fSide = -fTangent1.pointDistance(fCurvePart[2]); // not normalized -- compare sign only 871 } break; 872 case SkPath::kCubic_Verb: { 873 int nextC = 2; 874 CubicSubDivideHD(fPts, startT, endT, fCurvePart); 875 fTangent1.cubicEndPoints(fCurvePart, 0, 1); 876 if (dx() == 0 && dy() == 0) { 877 fTangent1.cubicEndPoints(fCurvePart, 0, 2); 878 nextC = 3; 879 if (dx() == 0 && dy() == 0) { 880 // SkDebugf("*** %s cubic is line\n", __FUNCTION__); 881 fTangent1.cubicEndPoints(fCurvePart, 0, 3); 882 } 883 } 884 fSide = -fTangent1.pointDistance(fCurvePart[nextC]); // compare sign only 885 if (nextC == 2 && approximately_zero(fSide)) { 886 fSide = -fTangent1.pointDistance(fCurvePart[3]); 887 } 888 } break; 889 default: 890 SkASSERT(0); 891 } 892 fUnsortable = dx() == 0 && dy() == 0; 893 if (fUnsortable) { 894 return; 895 } 896 SkASSERT(fStart != fEnd); 897 int step = fStart < fEnd ? 1 : -1; // OPTIMIZE: worth fStart - fEnd >> 31 type macro? 898 for (int index = fStart; index != fEnd; index += step) { 899#if 1 900 const Span& thisSpan = (*fSpans)[index]; 901 const Span& nextSpan = (*fSpans)[index + step]; 902 if (thisSpan.fTiny || precisely_equal(thisSpan.fT, nextSpan.fT)) { 903 continue; 904 } 905 fUnsortable = step > 0 ? thisSpan.fUnsortableStart : nextSpan.fUnsortableEnd; 906#if DEBUG_UNSORTABLE 907 if (fUnsortable) { 908 SkPoint iPt, ePt; 909 (*SegmentXYAtT[fVerb])(fPts, thisSpan.fT, &iPt); 910 (*SegmentXYAtT[fVerb])(fPts, nextSpan.fT, &ePt); 911 SkDebugf("%s unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__, 912 index, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); 913 } 914#endif 915 return; 916#else 917 if ((*fSpans)[index].fUnsortableStart) { 918 fUnsortable = true; 919 return; 920 } 921#endif 922 } 923#if 1 924#if DEBUG_UNSORTABLE 925 SkPoint iPt, ePt; 926 (*SegmentXYAtT[fVerb])(fPts, startT, &iPt); 927 (*SegmentXYAtT[fVerb])(fPts, endT, &ePt); 928 SkDebugf("%s all tiny unsortable [%d] (%1.9g,%1.9g) [%d] (%1.9g,%1.9g)\n", __FUNCTION__, 929 fStart, iPt.fX, iPt.fY, fEnd, ePt.fX, ePt.fY); 930#endif 931 fUnsortable = true; 932#endif 933 } 934 935 Segment* segment() const { 936 return const_cast<Segment*>(fSegment); 937 } 938 939 int sign() const { 940 return SkSign32(fStart - fEnd); 941 } 942 943 const SkTDArray<Span>* spans() const { 944 return fSpans; 945 } 946 947 int start() const { 948 return fStart; 949 } 950 951 bool unsortable() const { 952 return fUnsortable; 953 } 954 955#if DEBUG_ANGLE 956 const SkPoint* pts() const { 957 return fPts; 958 } 959 960 SkPath::Verb verb() const { 961 return fVerb; 962 } 963 964 void debugShow(const SkPoint& a) const { 965 SkDebugf(" d=(%1.9g,%1.9g) side=%1.9g\n", dx(), dy(), fSide); 966 } 967#endif 968 969private: 970 const SkPoint* fPts; 971 Cubic fCurvePart; 972 SkPath::Verb fVerb; 973 double fSide; 974 LineParameters fTangent1; 975 const SkTDArray<Span>* fSpans; 976 const Segment* fSegment; 977 int fStart; 978 int fEnd; 979 bool fReversed; 980 mutable bool fUnsortable; // this alone is editable by the less than operator 981}; 982 983// Bounds, unlike Rect, does not consider a line to be empty. 984struct Bounds : public SkRect { 985 static bool Intersects(const Bounds& a, const Bounds& b) { 986 return a.fLeft <= b.fRight && b.fLeft <= a.fRight && 987 a.fTop <= b.fBottom && b.fTop <= a.fBottom; 988 } 989 990 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { 991 if (left < fLeft) { 992 fLeft = left; 993 } 994 if (top < fTop) { 995 fTop = top; 996 } 997 if (right > fRight) { 998 fRight = right; 999 } 1000 if (bottom > fBottom) { 1001 fBottom = bottom; 1002 } 1003 } 1004 1005 void add(const Bounds& toAdd) { 1006 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom); 1007 } 1008 1009 void add(const SkPoint& pt) { 1010 if (pt.fX < fLeft) fLeft = pt.fX; 1011 if (pt.fY < fTop) fTop = pt.fY; 1012 if (pt.fX > fRight) fRight = pt.fX; 1013 if (pt.fY > fBottom) fBottom = pt.fY; 1014 } 1015 1016 bool isEmpty() { 1017 return fLeft > fRight || fTop > fBottom 1018 || (fLeft == fRight && fTop == fBottom) 1019 || sk_double_isnan(fLeft) || sk_double_isnan(fRight) 1020 || sk_double_isnan(fTop) || sk_double_isnan(fBottom); 1021 } 1022 1023 void setCubicBounds(const SkPoint a[4]) { 1024 _Rect dRect; 1025 MAKE_CONST_CUBIC(cubic, a); 1026 dRect.setBounds(cubic); 1027 set((float) dRect.left, (float) dRect.top, (float) dRect.right, 1028 (float) dRect.bottom); 1029 } 1030 1031 void setQuadBounds(const SkPoint a[3]) { 1032 MAKE_CONST_QUAD(quad, a); 1033 _Rect dRect; 1034 dRect.setBounds(quad); 1035 set((float) dRect.left, (float) dRect.top, (float) dRect.right, 1036 (float) dRect.bottom); 1037 } 1038 1039 void setPoint(const SkPoint& pt) { 1040 fLeft = fRight = pt.fX; 1041 fTop = fBottom = pt.fY; 1042 } 1043}; 1044 1045// OPTIMIZATION: does the following also work, and is it any faster? 1046// return outerWinding * innerWinding > 0 1047// || ((outerWinding + innerWinding < 0) ^ ((outerWinding - innerWinding) < 0))) 1048static bool useInnerWinding(int outerWinding, int innerWinding) { 1049 SkASSERT(outerWinding != SK_MaxS32); 1050 SkASSERT(innerWinding != SK_MaxS32); 1051 int absOut = abs(outerWinding); 1052 int absIn = abs(innerWinding); 1053 bool result = absOut == absIn ? outerWinding < 0 : absOut < absIn; 1054#if 0 && DEBUG_WINDING 1055 if (outerWinding * innerWinding < 0) { 1056 SkDebugf("%s outer=%d inner=%d result=%s\n", __FUNCTION__, 1057 outerWinding, innerWinding, result ? "true" : "false"); 1058 } 1059#endif 1060 return result; 1061} 1062 1063#define F (false) // discard the edge 1064#define T (true) // keep the edge 1065 1066static const bool gUnaryActiveEdge[2][2] = { 1067// from=0 from=1 1068// to=0,1 to=0,1 1069 {F, T}, {T, F}, 1070}; 1071 1072static const bool gActiveEdge[kShapeOp_Count][2][2][2][2] = { 1073// miFrom=0 miFrom=1 1074// miTo=0 miTo=1 miTo=0 miTo=1 1075// suFrom=0 1 suFrom=0 1 suFrom=0 1 suFrom=0 1 1076// suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 suTo=0,1 1077 {{{{F, F}, {F, F}}, {{T, F}, {T, F}}}, {{{T, T}, {F, F}}, {{F, T}, {T, F}}}}, // mi - su 1078 {{{{F, F}, {F, F}}, {{F, T}, {F, T}}}, {{{F, F}, {T, T}}, {{F, T}, {T, F}}}}, // mi & su 1079 {{{{F, T}, {T, F}}, {{T, T}, {F, F}}}, {{{T, F}, {T, F}}, {{F, F}, {F, F}}}}, // mi | su 1080 {{{{F, T}, {T, F}}, {{T, F}, {F, T}}}, {{{T, F}, {F, T}}, {{F, T}, {T, F}}}}, // mi ^ su 1081}; 1082 1083#undef F 1084#undef T 1085 1086// wrap path to keep track of whether the contour is initialized and non-empty 1087class PathWrapper { 1088public: 1089 PathWrapper(SkPath& path) 1090 : fPathPtr(&path) 1091 , fCloses(0) 1092 , fMoves(0) 1093 { 1094 init(); 1095 } 1096 1097 void close() { 1098 if (!fHasMove) { 1099 return; 1100 } 1101 bool callClose = isClosed(); 1102 lineTo(); 1103 if (fEmpty) { 1104 return; 1105 } 1106 if (callClose) { 1107 #if DEBUG_PATH_CONSTRUCTION 1108 SkDebugf("path.close();\n"); 1109 #endif 1110 fPathPtr->close(); 1111 fCloses++; 1112 } 1113 init(); 1114 } 1115 1116 void cubicTo(const SkPoint& pt1, const SkPoint& pt2, const SkPoint& pt3) { 1117 lineTo(); 1118 moveTo(); 1119 fDefer[1] = pt3; 1120 nudge(); 1121 fDefer[0] = fDefer[1]; 1122#if DEBUG_PATH_CONSTRUCTION 1123 SkDebugf("path.cubicTo(%1.9g,%1.9g, %1.9g,%1.9g, %1.9g,%1.9g);\n", 1124 pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY); 1125#endif 1126 fPathPtr->cubicTo(pt1.fX, pt1.fY, pt2.fX, pt2.fY, fDefer[1].fX, fDefer[1].fY); 1127 fEmpty = false; 1128 } 1129 1130 void deferredLine(const SkPoint& pt) { 1131 if (pt == fDefer[1]) { 1132 return; 1133 } 1134 if (changedSlopes(pt)) { 1135 lineTo(); 1136 fDefer[0] = fDefer[1]; 1137 } 1138 fDefer[1] = pt; 1139 } 1140 1141 void deferredMove(const SkPoint& pt) { 1142 fMoved = true; 1143 fHasMove = true; 1144 fEmpty = true; 1145 fDefer[0] = fDefer[1] = pt; 1146 } 1147 1148 void deferredMoveLine(const SkPoint& pt) { 1149 if (!fHasMove) { 1150 deferredMove(pt); 1151 } 1152 deferredLine(pt); 1153 } 1154 1155 bool hasMove() const { 1156 return fHasMove; 1157 } 1158 1159 void init() { 1160 fEmpty = true; 1161 fHasMove = false; 1162 fMoved = false; 1163 } 1164 1165 bool isClosed() const { 1166 return !fEmpty && fFirstPt == fDefer[1]; 1167 } 1168 1169 void lineTo() { 1170 if (fDefer[0] == fDefer[1]) { 1171 return; 1172 } 1173 moveTo(); 1174 nudge(); 1175 fEmpty = false; 1176#if DEBUG_PATH_CONSTRUCTION 1177 SkDebugf("path.lineTo(%1.9g,%1.9g);\n", fDefer[1].fX, fDefer[1].fY); 1178#endif 1179 fPathPtr->lineTo(fDefer[1].fX, fDefer[1].fY); 1180 fDefer[0] = fDefer[1]; 1181 } 1182 1183 const SkPath* nativePath() const { 1184 return fPathPtr; 1185 } 1186 1187 void nudge() { 1188 if (fEmpty || !AlmostEqualUlps(fDefer[1].fX, fFirstPt.fX) 1189 || !AlmostEqualUlps(fDefer[1].fY, fFirstPt.fY)) { 1190 return; 1191 } 1192 fDefer[1] = fFirstPt; 1193 } 1194 1195 void quadTo(const SkPoint& pt1, const SkPoint& pt2) { 1196 lineTo(); 1197 moveTo(); 1198 fDefer[1] = pt2; 1199 nudge(); 1200 fDefer[0] = fDefer[1]; 1201#if DEBUG_PATH_CONSTRUCTION 1202 SkDebugf("path.quadTo(%1.9g,%1.9g, %1.9g,%1.9g);\n", 1203 pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY); 1204#endif 1205 fPathPtr->quadTo(pt1.fX, pt1.fY, fDefer[1].fX, fDefer[1].fY); 1206 fEmpty = false; 1207 } 1208 1209 bool someAssemblyRequired() const { 1210 return fCloses < fMoves; 1211 } 1212 1213protected: 1214 bool changedSlopes(const SkPoint& pt) const { 1215 if (fDefer[0] == fDefer[1]) { 1216 return false; 1217 } 1218 SkScalar deferDx = fDefer[1].fX - fDefer[0].fX; 1219 SkScalar deferDy = fDefer[1].fY - fDefer[0].fY; 1220 SkScalar lineDx = pt.fX - fDefer[1].fX; 1221 SkScalar lineDy = pt.fY - fDefer[1].fY; 1222 return deferDx * lineDy != deferDy * lineDx; 1223 } 1224 1225 void moveTo() { 1226 if (!fMoved) { 1227 return; 1228 } 1229 fFirstPt = fDefer[0]; 1230#if DEBUG_PATH_CONSTRUCTION 1231 SkDebugf("path.moveTo(%1.9g,%1.9g);\n", fDefer[0].fX, fDefer[0].fY); 1232#endif 1233 fPathPtr->moveTo(fDefer[0].fX, fDefer[0].fY); 1234 fMoved = false; 1235 fMoves++; 1236 } 1237 1238private: 1239 SkPath* fPathPtr; 1240 SkPoint fDefer[2]; 1241 SkPoint fFirstPt; 1242 int fCloses; 1243 int fMoves; 1244 bool fEmpty; 1245 bool fHasMove; 1246 bool fMoved; 1247}; 1248 1249class Segment { 1250public: 1251 Segment() { 1252#if DEBUG_DUMP 1253 fID = ++gSegmentID; 1254#endif 1255 } 1256 1257 bool operator<(const Segment& rh) const { 1258 return fBounds.fTop < rh.fBounds.fTop; 1259 } 1260 1261 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) { 1262 if (activeAngleInner(index, done, angles)) { 1263 return true; 1264 } 1265 int lesser = index; 1266 while (--lesser >= 0 && equalPoints(index, lesser)) { 1267 if (activeAngleOther(lesser, done, angles)) { 1268 return true; 1269 } 1270 } 1271 lesser = index; 1272 do { 1273 if (activeAngleOther(index, done, angles)) { 1274 return true; 1275 } 1276 } while (++index < fTs.count() && equalPoints(index, lesser)); 1277 return false; 1278 } 1279 1280 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) { 1281 Span* span = &fTs[index]; 1282 Segment* other = span->fOther; 1283 int oIndex = span->fOtherIndex; 1284 return other->activeAngleInner(oIndex, done, angles); 1285 } 1286 1287 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) { 1288 int next = nextExactSpan(index, 1); 1289 if (next > 0) { 1290 Span& upSpan = fTs[index]; 1291 if (upSpan.fWindValue || upSpan.fOppValue) { 1292 addAngle(angles, index, next); 1293 if (upSpan.fDone || upSpan.fUnsortableEnd) { 1294 done++; 1295 } else if (upSpan.fWindSum != SK_MinS32) { 1296 return true; 1297 } 1298 } else if (!upSpan.fDone) { 1299 upSpan.fDone = true; 1300 fDoneSpans++; 1301 } 1302 } 1303 int prev = nextExactSpan(index, -1); 1304 // edge leading into junction 1305 if (prev >= 0) { 1306 Span& downSpan = fTs[prev]; 1307 if (downSpan.fWindValue || downSpan.fOppValue) { 1308 addAngle(angles, index, prev); 1309 if (downSpan.fDone) { 1310 done++; 1311 } else if (downSpan.fWindSum != SK_MinS32) { 1312 return true; 1313 } 1314 } else if (!downSpan.fDone) { 1315 downSpan.fDone = true; 1316 fDoneSpans++; 1317 } 1318 } 1319 return false; 1320 } 1321 1322 SkPoint activeLeftTop(bool onlySortable, int* firstT) const { 1323 SkASSERT(!done()); 1324 SkPoint topPt = {SK_ScalarMax, SK_ScalarMax}; 1325 int count = fTs.count(); 1326 // see if either end is not done since we want smaller Y of the pair 1327 bool lastDone = true; 1328 bool lastUnsortable = false; 1329 double lastT = -1; 1330 for (int index = 0; index < count; ++index) { 1331 const Span& span = fTs[index]; 1332 if (onlySortable && (span.fUnsortableStart || lastUnsortable)) { 1333 goto next; 1334 } 1335 if (span.fDone && lastDone) { 1336 goto next; 1337 } 1338 if (approximately_negative(span.fT - lastT)) { 1339 goto next; 1340 } 1341 { 1342 const SkPoint& xy = xyAtT(&span); 1343 if (topPt.fY > xy.fY || (topPt.fY == xy.fY && topPt.fX > xy.fX)) { 1344 topPt = xy; 1345 if (firstT) { 1346 *firstT = index; 1347 } 1348 } 1349 if (fVerb != SkPath::kLine_Verb && !lastDone) { 1350 SkPoint curveTop = (*SegmentTop[fVerb])(fPts, lastT, span.fT); 1351 if (topPt.fY > curveTop.fY || (topPt.fY == curveTop.fY 1352 && topPt.fX > curveTop.fX)) { 1353 topPt = curveTop; 1354 if (firstT) { 1355 *firstT = index; 1356 } 1357 } 1358 } 1359 lastT = span.fT; 1360 } 1361 next: 1362 lastDone = span.fDone; 1363 lastUnsortable = span.fUnsortableEnd; 1364 } 1365 return topPt; 1366 } 1367 1368 bool activeOp(int index, int endIndex, int xorMiMask, int xorSuMask, ShapeOp op) { 1369 int sumMiWinding = updateWinding(endIndex, index); 1370 int sumSuWinding = updateOppWinding(endIndex, index); 1371 if (fOperand) { 1372 SkTSwap<int>(sumMiWinding, sumSuWinding); 1373 } 1374 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; 1375 return activeOp(xorMiMask, xorSuMask, index, endIndex, op, sumMiWinding, sumSuWinding, 1376 maxWinding, sumWinding, oppMaxWinding, oppSumWinding); 1377 } 1378 1379 bool activeOp(int xorMiMask, int xorSuMask, int index, int endIndex, ShapeOp op, 1380 int& sumMiWinding, int& sumSuWinding, 1381 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) { 1382 setUpWindings(index, endIndex, sumMiWinding, sumSuWinding, 1383 maxWinding, sumWinding, oppMaxWinding, oppSumWinding); 1384 bool miFrom; 1385 bool miTo; 1386 bool suFrom; 1387 bool suTo; 1388 if (operand()) { 1389 miFrom = (oppMaxWinding & xorMiMask) != 0; 1390 miTo = (oppSumWinding & xorMiMask) != 0; 1391 suFrom = (maxWinding & xorSuMask) != 0; 1392 suTo = (sumWinding & xorSuMask) != 0; 1393 } else { 1394 miFrom = (maxWinding & xorMiMask) != 0; 1395 miTo = (sumWinding & xorMiMask) != 0; 1396 suFrom = (oppMaxWinding & xorSuMask) != 0; 1397 suTo = (oppSumWinding & xorSuMask) != 0; 1398 } 1399 bool result = gActiveEdge[op][miFrom][miTo][suFrom][suTo]; 1400#if DEBUG_ACTIVE_OP 1401 SkDebugf("%s op=%s miFrom=%d miTo=%d suFrom=%d suTo=%d result=%d\n", __FUNCTION__, 1402 kShapeOpStr[op], miFrom, miTo, suFrom, suTo, result); 1403#endif 1404 SkASSERT(result != -1); 1405 return result; 1406 } 1407 1408 bool activeWinding(int index, int endIndex) { 1409 int sumWinding = updateWinding(endIndex, index); 1410 int maxWinding; 1411 return activeWinding(index, endIndex, maxWinding, sumWinding); 1412 } 1413 1414 bool activeWinding(int index, int endIndex, int& maxWinding, int& sumWinding) { 1415 setUpWinding(index, endIndex, maxWinding, sumWinding); 1416 bool from = maxWinding != 0; 1417 bool to = sumWinding != 0; 1418 bool result = gUnaryActiveEdge[from][to]; 1419 SkASSERT(result != -1); 1420 return result; 1421 } 1422 1423 void addAngle(SkTDArray<Angle>& angles, int start, int end) const { 1424 SkASSERT(start != end); 1425 Angle* angle = angles.append(); 1426#if DEBUG_ANGLE 1427 if (angles.count() > 1 && !fTs[start].fTiny) { 1428 SkPoint angle0Pt, newPt; 1429 (*SegmentXYAtT[angles[0].verb()])(angles[0].pts(), 1430 (*angles[0].spans())[angles[0].start()].fT, &angle0Pt); 1431 (*SegmentXYAtT[fVerb])(fPts, fTs[start].fT, &newPt); 1432 SkASSERT(AlmostEqualUlps(angle0Pt.fX, newPt.fX)); 1433 SkASSERT(AlmostEqualUlps(angle0Pt.fY, newPt.fY)); 1434 } 1435#endif 1436 angle->set(fPts, fVerb, this, start, end, fTs); 1437 } 1438 1439 void addCancelOutsides(double tStart, double oStart, Segment& other, 1440 double oEnd) { 1441 int tIndex = -1; 1442 int tCount = fTs.count(); 1443 int oIndex = -1; 1444 int oCount = other.fTs.count(); 1445 do { 1446 ++tIndex; 1447 } while (!approximately_negative(tStart - fTs[tIndex].fT) && tIndex < tCount); 1448 int tIndexStart = tIndex; 1449 do { 1450 ++oIndex; 1451 } while (!approximately_negative(oStart - other.fTs[oIndex].fT) && oIndex < oCount); 1452 int oIndexStart = oIndex; 1453 double nextT; 1454 do { 1455 nextT = fTs[++tIndex].fT; 1456 } while (nextT < 1 && approximately_negative(nextT - tStart)); 1457 double oNextT; 1458 do { 1459 oNextT = other.fTs[++oIndex].fT; 1460 } while (oNextT < 1 && approximately_negative(oNextT - oStart)); 1461 // at this point, spans before and after are at: 1462 // fTs[tIndexStart - 1], fTs[tIndexStart], fTs[tIndex] 1463 // if tIndexStart == 0, no prior span 1464 // if nextT == 1, no following span 1465 1466 // advance the span with zero winding 1467 // if the following span exists (not past the end, non-zero winding) 1468 // connect the two edges 1469 if (!fTs[tIndexStart].fWindValue) { 1470 if (tIndexStart > 0 && fTs[tIndexStart - 1].fWindValue) { 1471 #if DEBUG_CONCIDENT 1472 SkDebugf("%s 1 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", 1473 __FUNCTION__, fID, other.fID, tIndexStart - 1, 1474 fTs[tIndexStart].fT, xyAtT(tIndexStart).fX, 1475 xyAtT(tIndexStart).fY); 1476 #endif 1477 addTPair(fTs[tIndexStart].fT, other, other.fTs[oIndex].fT, false, 1478 fTs[tIndexStart].fPt); 1479 } 1480 if (nextT < 1 && fTs[tIndex].fWindValue) { 1481 #if DEBUG_CONCIDENT 1482 SkDebugf("%s 2 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", 1483 __FUNCTION__, fID, other.fID, tIndex, 1484 fTs[tIndex].fT, xyAtT(tIndex).fX, 1485 xyAtT(tIndex).fY); 1486 #endif 1487 addTPair(fTs[tIndex].fT, other, other.fTs[oIndexStart].fT, false, fTs[tIndex].fPt); 1488 } 1489 } else { 1490 SkASSERT(!other.fTs[oIndexStart].fWindValue); 1491 if (oIndexStart > 0 && other.fTs[oIndexStart - 1].fWindValue) { 1492 #if DEBUG_CONCIDENT 1493 SkDebugf("%s 3 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", 1494 __FUNCTION__, fID, other.fID, oIndexStart - 1, 1495 other.fTs[oIndexStart].fT, other.xyAtT(oIndexStart).fX, 1496 other.xyAtT(oIndexStart).fY); 1497 other.debugAddTPair(other.fTs[oIndexStart].fT, *this, fTs[tIndex].fT); 1498 #endif 1499 } 1500 if (oNextT < 1 && other.fTs[oIndex].fWindValue) { 1501 #if DEBUG_CONCIDENT 1502 SkDebugf("%s 4 this=%d other=%d t [%d] %1.9g (%1.9g,%1.9g)\n", 1503 __FUNCTION__, fID, other.fID, oIndex, 1504 other.fTs[oIndex].fT, other.xyAtT(oIndex).fX, 1505 other.xyAtT(oIndex).fY); 1506 other.debugAddTPair(other.fTs[oIndex].fT, *this, fTs[tIndexStart].fT); 1507 #endif 1508 } 1509 } 1510 } 1511 1512 void addCoinOutsides(const SkTDArray<double>& outsideTs, Segment& other, 1513 double oEnd) { 1514 // walk this to outsideTs[0] 1515 // walk other to outsideTs[1] 1516 // if either is > 0, add a pointer to the other, copying adjacent winding 1517 int tIndex = -1; 1518 int oIndex = -1; 1519 double tStart = outsideTs[0]; 1520 double oStart = outsideTs[1]; 1521 do { 1522 ++tIndex; 1523 } while (!approximately_negative(tStart - fTs[tIndex].fT)); 1524 SkPoint ptStart = fTs[tIndex].fPt; 1525 do { 1526 ++oIndex; 1527 } while (!approximately_negative(oStart - other.fTs[oIndex].fT)); 1528 if (tIndex > 0 || oIndex > 0 || fOperand != other.fOperand) { 1529 addTPair(tStart, other, oStart, false, ptStart); 1530 } 1531 tStart = fTs[tIndex].fT; 1532 oStart = other.fTs[oIndex].fT; 1533 do { 1534 double nextT; 1535 do { 1536 nextT = fTs[++tIndex].fT; 1537 } while (approximately_negative(nextT - tStart)); 1538 tStart = nextT; 1539 ptStart = fTs[tIndex].fPt; 1540 do { 1541 nextT = other.fTs[++oIndex].fT; 1542 } while (approximately_negative(nextT - oStart)); 1543 oStart = nextT; 1544 if (tStart == 1 && oStart == 1 && fOperand == other.fOperand) { 1545 break; 1546 } 1547 addTPair(tStart, other, oStart, false, ptStart); 1548 } while (tStart < 1 && oStart < 1 && !approximately_negative(oEnd - oStart)); 1549 } 1550 1551 void addCubic(const SkPoint pts[4], bool operand, bool evenOdd) { 1552 init(pts, SkPath::kCubic_Verb, operand, evenOdd); 1553 fBounds.setCubicBounds(pts); 1554 } 1555 1556 /* SkPoint */ void addCurveTo(int start, int end, PathWrapper& path, bool active) const { 1557 SkPoint edge[4]; 1558 const SkPoint* ePtr; 1559 int lastT = fTs.count() - 1; 1560 if (lastT < 0 || (start == 0 && end == lastT) || (start == lastT && end == 0)) { 1561 ePtr = fPts; 1562 } else { 1563 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end) 1564 subDivide(start, end, edge); 1565 ePtr = edge; 1566 } 1567 if (active) { 1568 bool reverse = ePtr == fPts && start != 0; 1569 if (reverse) { 1570 path.deferredMoveLine(ePtr[fVerb]); 1571 switch (fVerb) { 1572 case SkPath::kLine_Verb: 1573 path.deferredLine(ePtr[0]); 1574 break; 1575 case SkPath::kQuad_Verb: 1576 path.quadTo(ePtr[1], ePtr[0]); 1577 break; 1578 case SkPath::kCubic_Verb: 1579 path.cubicTo(ePtr[2], ePtr[1], ePtr[0]); 1580 break; 1581 default: 1582 SkASSERT(0); 1583 } 1584 // return ePtr[0]; 1585 } else { 1586 path.deferredMoveLine(ePtr[0]); 1587 switch (fVerb) { 1588 case SkPath::kLine_Verb: 1589 path.deferredLine(ePtr[1]); 1590 break; 1591 case SkPath::kQuad_Verb: 1592 path.quadTo(ePtr[1], ePtr[2]); 1593 break; 1594 case SkPath::kCubic_Verb: 1595 path.cubicTo(ePtr[1], ePtr[2], ePtr[3]); 1596 break; 1597 default: 1598 SkASSERT(0); 1599 } 1600 } 1601 } 1602 // return ePtr[fVerb]; 1603 } 1604 1605 void addLine(const SkPoint pts[2], bool operand, bool evenOdd) { 1606 init(pts, SkPath::kLine_Verb, operand, evenOdd); 1607 fBounds.set(pts, 2); 1608 } 1609 1610#if 0 1611 const SkPoint& addMoveTo(int tIndex, PathWrapper& path, bool active) const { 1612 const SkPoint& pt = xyAtT(tIndex); 1613 if (active) { 1614 path.deferredMove(pt); 1615 } 1616 return pt; 1617 } 1618#endif 1619 1620 // add 2 to edge or out of range values to get T extremes 1621 void addOtherT(int index, double otherT, int otherIndex) { 1622 Span& span = fTs[index]; 1623 #if PIN_ADD_T 1624 if (precisely_less_than_zero(otherT)) { 1625 otherT = 0; 1626 } else if (precisely_greater_than_one(otherT)) { 1627 otherT = 1; 1628 } 1629 #endif 1630 span.fOtherT = otherT; 1631 span.fOtherIndex = otherIndex; 1632 } 1633 1634 void addQuad(const SkPoint pts[3], bool operand, bool evenOdd) { 1635 init(pts, SkPath::kQuad_Verb, operand, evenOdd); 1636 fBounds.setQuadBounds(pts); 1637 } 1638 1639 // Defer all coincident edge processing until 1640 // after normal intersections have been computed 1641 1642// no need to be tricky; insert in normal T order 1643// resolve overlapping ts when considering coincidence later 1644 1645 // add non-coincident intersection. Resulting edges are sorted in T. 1646 int addT(Segment* other, const SkPoint& pt, double& newT) { 1647 // FIXME: in the pathological case where there is a ton of intercepts, 1648 // binary search? 1649 int insertedAt = -1; 1650 size_t tCount = fTs.count(); 1651 #if PIN_ADD_T 1652 // FIXME: only do this pinning here (e.g. this is done also in quad/line intersect) 1653 if (precisely_less_than_zero(newT)) { 1654 newT = 0; 1655 } else if (precisely_greater_than_one(newT)) { 1656 newT = 1; 1657 } 1658 #endif 1659 for (size_t index = 0; index < tCount; ++index) { 1660 // OPTIMIZATION: if there are three or more identical Ts, then 1661 // the fourth and following could be further insertion-sorted so 1662 // that all the edges are clockwise or counterclockwise. 1663 // This could later limit segment tests to the two adjacent 1664 // neighbors, although it doesn't help with determining which 1665 // circular direction to go in. 1666 if (newT < fTs[index].fT) { 1667 insertedAt = index; 1668 break; 1669 } 1670 } 1671 Span* span; 1672 if (insertedAt >= 0) { 1673 span = fTs.insert(insertedAt); 1674 } else { 1675 insertedAt = tCount; 1676 span = fTs.append(); 1677 } 1678 span->fT = newT; 1679 span->fOther = other; 1680 span->fPt = pt; 1681 span->fWindSum = SK_MinS32; 1682 span->fOppSum = SK_MinS32; 1683 span->fWindValue = 1; 1684 span->fOppValue = 0; 1685 span->fTiny = false; 1686 span->fLoop = false; 1687 if ((span->fDone = newT == 1)) { 1688 ++fDoneSpans; 1689 } 1690 span->fUnsortableStart = false; 1691 span->fUnsortableEnd = false; 1692 int less = -1; 1693 while (&span[less + 1] - fTs.begin() > 0 && xyAtT(&span[less]) == xyAtT(span)) { 1694#if 1 1695 if (span[less].fDone) { 1696 break; 1697 } 1698 double tInterval = newT - span[less].fT; 1699 if (precisely_negative(tInterval)) { 1700 break; 1701 } 1702 if (fVerb == SkPath::kCubic_Verb) { 1703 double tMid = newT - tInterval / 2; 1704 _Point midPt; 1705 CubicXYAtT(fPts, tMid, &midPt); 1706 if (!midPt.approximatelyEqual(xyAtT(span))) { 1707 break; 1708 } 1709 } 1710 span[less].fTiny = true; 1711 span[less].fDone = true; 1712 if (approximately_negative(newT - span[less].fT)) { 1713 if (approximately_greater_than_one(newT)) { 1714 span[less].fUnsortableStart = true; 1715 span[less - 1].fUnsortableEnd = true; 1716 } 1717 if (approximately_less_than_zero(span[less].fT)) { 1718 span[less + 1].fUnsortableStart = true; 1719 span[less].fUnsortableEnd = true; 1720 } 1721 } 1722 ++fDoneSpans; 1723#else 1724 double tInterval = newT - span[less].fT; 1725 if (precisely_negative(tInterval)) { 1726 break; 1727 } 1728 if (fVerb == SkPath::kCubic_Verb) { 1729 double tMid = newT - tInterval / 2; 1730 _Point midPt; 1731 CubicXYAtT(fPts, tMid, &midPt); 1732 if (!midPt.approximatelyEqual(xyAtT(span))) { 1733 break; 1734 } 1735 } 1736 SkASSERT(span[less].fDone == span->fDone); 1737 if (span[less].fT == 0) { 1738 span->fT = newT = 0; 1739 } else { 1740 setSpanT(less, newT); 1741 } 1742#endif 1743 --less; 1744 } 1745 int more = 1; 1746 while (fTs.end() - &span[more - 1] > 1 && xyAtT(&span[more]) == xyAtT(span)) { 1747#if 1 1748 if (span[more - 1].fDone) { 1749 break; 1750 } 1751 double tEndInterval = span[more].fT - newT; 1752 if (precisely_negative(tEndInterval)) { 1753 break; 1754 } 1755 if (fVerb == SkPath::kCubic_Verb) { 1756 double tMid = newT - tEndInterval / 2; 1757 _Point midEndPt; 1758 CubicXYAtT(fPts, tMid, &midEndPt); 1759 if (!midEndPt.approximatelyEqual(xyAtT(span))) { 1760 break; 1761 } 1762 } 1763 span[more - 1].fTiny = true; 1764 span[more - 1].fDone = true; 1765 if (approximately_negative(span[more].fT - newT)) { 1766 if (approximately_greater_than_one(span[more].fT)) { 1767 span[more + 1].fUnsortableStart = true; 1768 span[more].fUnsortableEnd = true; 1769 } 1770 if (approximately_less_than_zero(newT)) { 1771 span[more].fUnsortableStart = true; 1772 span[more - 1].fUnsortableEnd = true; 1773 } 1774 } 1775 ++fDoneSpans; 1776#else 1777 double tEndInterval = span[more].fT - newT; 1778 if (precisely_negative(tEndInterval)) { 1779 break; 1780 } 1781 if (fVerb == SkPath::kCubic_Verb) { 1782 double tMid = newT - tEndInterval / 2; 1783 _Point midEndPt; 1784 CubicXYAtT(fPts, tMid, &midEndPt); 1785 if (!midEndPt.approximatelyEqual(xyAtT(span))) { 1786 break; 1787 } 1788 } 1789 SkASSERT(span[more - 1].fDone == span[more].fDone); 1790 if (newT == 0) { 1791 setSpanT(more, 0); 1792 } else { 1793 span->fT = newT = span[more].fT; 1794 } 1795#endif 1796 ++more; 1797 } 1798 return insertedAt; 1799 } 1800 1801 // set spans from start to end to decrement by one 1802 // note this walks other backwards 1803 // FIMXE: there's probably an edge case that can be constructed where 1804 // two span in one segment are separated by float epsilon on one span but 1805 // not the other, if one segment is very small. For this 1806 // case the counts asserted below may or may not be enough to separate the 1807 // spans. Even if the counts work out, what if the spans aren't correctly 1808 // sorted? It feels better in such a case to match the span's other span 1809 // pointer since both coincident segments must contain the same spans. 1810 void addTCancel(double startT, double endT, Segment& other, 1811 double oStartT, double oEndT) { 1812 SkASSERT(!approximately_negative(endT - startT)); 1813 SkASSERT(!approximately_negative(oEndT - oStartT)); 1814 bool binary = fOperand != other.fOperand; 1815 int index = 0; 1816 while (!approximately_negative(startT - fTs[index].fT)) { 1817 ++index; 1818 } 1819 int oIndex = other.fTs.count(); 1820 while (approximately_positive(other.fTs[--oIndex].fT - oEndT)) 1821 ; 1822 double tRatio = (oEndT - oStartT) / (endT - startT); 1823 Span* test = &fTs[index]; 1824 Span* oTest = &other.fTs[oIndex]; 1825 SkTDArray<double> outsideTs; 1826 SkTDArray<double> oOutsideTs; 1827 do { 1828 bool decrement = test->fWindValue && oTest->fWindValue && !binary; 1829 bool track = test->fWindValue || oTest->fWindValue; 1830 double testT = test->fT; 1831 double oTestT = oTest->fT; 1832 Span* span = test; 1833 do { 1834 if (decrement) { 1835 decrementSpan(span); 1836 } else if (track && span->fT < 1 && oTestT < 1) { 1837 TrackOutside(outsideTs, span->fT, oTestT); 1838 } 1839 span = &fTs[++index]; 1840 } while (approximately_negative(span->fT - testT)); 1841 Span* oSpan = oTest; 1842 double otherTMatchStart = oEndT - (span->fT - startT) * tRatio; 1843 double otherTMatchEnd = oEndT - (test->fT - startT) * tRatio; 1844 SkDEBUGCODE(int originalWindValue = oSpan->fWindValue); 1845 while (approximately_negative(otherTMatchStart - oSpan->fT) 1846 && !approximately_negative(otherTMatchEnd - oSpan->fT)) { 1847 #ifdef SK_DEBUG 1848 SkASSERT(originalWindValue == oSpan->fWindValue); 1849 #endif 1850 if (decrement) { 1851 other.decrementSpan(oSpan); 1852 } else if (track && oSpan->fT < 1 && testT < 1) { 1853 TrackOutside(oOutsideTs, oSpan->fT, testT); 1854 } 1855 if (!oIndex) { 1856 break; 1857 } 1858 oSpan = &other.fTs[--oIndex]; 1859 } 1860 test = span; 1861 oTest = oSpan; 1862 } while (!approximately_negative(endT - test->fT)); 1863 SkASSERT(!oIndex || approximately_negative(oTest->fT - oStartT)); 1864 // FIXME: determine if canceled edges need outside ts added 1865 if (!done() && outsideTs.count()) { 1866 double tStart = outsideTs[0]; 1867 double oStart = outsideTs[1]; 1868 addCancelOutsides(tStart, oStart, other, oEndT); 1869 int count = outsideTs.count(); 1870 if (count > 2) { 1871 double tStart = outsideTs[count - 2]; 1872 double oStart = outsideTs[count - 1]; 1873 addCancelOutsides(tStart, oStart, other, oEndT); 1874 } 1875 } 1876 if (!other.done() && oOutsideTs.count()) { 1877 double tStart = oOutsideTs[0]; 1878 double oStart = oOutsideTs[1]; 1879 other.addCancelOutsides(tStart, oStart, *this, endT); 1880 } 1881 } 1882 1883 int addSelfT(Segment* other, const SkPoint& pt, double& newT) { 1884 int result = addT(other, pt, newT); 1885 Span* span = &fTs[result]; 1886 span->fLoop = true; 1887 return result; 1888 } 1889 1890 int addUnsortableT(Segment* other, bool start, const SkPoint& pt, double& newT) { 1891 int result = addT(other, pt, newT); 1892 Span* span = &fTs[result]; 1893 if (start) { 1894 if (result > 0) { 1895 span[result - 1].fUnsortableEnd = true; 1896 } 1897 span[result].fUnsortableStart = true; 1898 } else { 1899 span[result].fUnsortableEnd = true; 1900 if (result + 1 < fTs.count()) { 1901 span[result + 1].fUnsortableStart = true; 1902 } 1903 } 1904 return result; 1905 } 1906 1907 int bumpCoincidentThis(const Span* oTest, bool opp, int index, 1908 SkTDArray<double>& outsideTs) { 1909 int oWindValue = oTest->fWindValue; 1910 int oOppValue = oTest->fOppValue; 1911 if (opp) { 1912 SkTSwap<int>(oWindValue, oOppValue); 1913 } 1914 Span* const test = &fTs[index]; 1915 Span* end = test; 1916 const double oStartT = oTest->fT; 1917 do { 1918 if (bumpSpan(end, oWindValue, oOppValue)) { 1919 TrackOutside(outsideTs, end->fT, oStartT); 1920 } 1921 end = &fTs[++index]; 1922 } while (approximately_negative(end->fT - test->fT)); 1923 return index; 1924 } 1925 1926 // because of the order in which coincidences are resolved, this and other 1927 // may not have the same intermediate points. Compute the corresponding 1928 // intermediate T values (using this as the master, other as the follower) 1929 // and walk other conditionally -- hoping that it catches up in the end 1930 int bumpCoincidentOther(const Span* test, double oEndT, int& oIndex, 1931 SkTDArray<double>& oOutsideTs) { 1932 Span* const oTest = &fTs[oIndex]; 1933 Span* oEnd = oTest; 1934 const double startT = test->fT; 1935 const double oStartT = oTest->fT; 1936 while (!approximately_negative(oEndT - oEnd->fT) 1937 && approximately_negative(oEnd->fT - oStartT)) { 1938 zeroSpan(oEnd); 1939 TrackOutside(oOutsideTs, oEnd->fT, startT); 1940 oEnd = &fTs[++oIndex]; 1941 } 1942 return oIndex; 1943 } 1944 1945 // FIXME: need to test this case: 1946 // contourA has two segments that are coincident 1947 // contourB has two segments that are coincident in the same place 1948 // each ends up with +2/0 pairs for winding count 1949 // since logic below doesn't transfer count (only increments/decrements) can this be 1950 // resolved to +4/0 ? 1951 1952 // set spans from start to end to increment the greater by one and decrement 1953 // the lesser 1954 void addTCoincident(double startT, double endT, Segment& other, double oStartT, double oEndT) { 1955 SkASSERT(!approximately_negative(endT - startT)); 1956 SkASSERT(!approximately_negative(oEndT - oStartT)); 1957 bool opp = fOperand ^ other.fOperand; 1958 int index = 0; 1959 while (!approximately_negative(startT - fTs[index].fT)) { 1960 ++index; 1961 } 1962 int oIndex = 0; 1963 while (!approximately_negative(oStartT - other.fTs[oIndex].fT)) { 1964 ++oIndex; 1965 } 1966 Span* test = &fTs[index]; 1967 Span* oTest = &other.fTs[oIndex]; 1968 SkTDArray<double> outsideTs; 1969 SkTDArray<double> oOutsideTs; 1970 do { 1971 // if either span has an opposite value and the operands don't match, resolve first 1972 // SkASSERT(!test->fDone || !oTest->fDone); 1973 if (test->fDone || oTest->fDone) { 1974 index = advanceCoincidentThis(oTest, opp, index); 1975 oIndex = other.advanceCoincidentOther(test, oEndT, oIndex); 1976 } else { 1977 index = bumpCoincidentThis(oTest, opp, index, outsideTs); 1978 oIndex = other.bumpCoincidentOther(test, oEndT, oIndex, oOutsideTs); 1979 } 1980 test = &fTs[index]; 1981 oTest = &other.fTs[oIndex]; 1982 } while (!approximately_negative(endT - test->fT)); 1983 SkASSERT(approximately_negative(oTest->fT - oEndT)); 1984 SkASSERT(approximately_negative(oEndT - oTest->fT)); 1985 if (!done() && outsideTs.count()) { 1986 addCoinOutsides(outsideTs, other, oEndT); 1987 } 1988 if (!other.done() && oOutsideTs.count()) { 1989 other.addCoinOutsides(oOutsideTs, *this, endT); 1990 } 1991 } 1992 1993 // FIXME: this doesn't prevent the same span from being added twice 1994 // fix in caller, SkASSERT here? 1995 void addTPair(double t, Segment& other, double otherT, bool borrowWind, const SkPoint& pt) { 1996 int tCount = fTs.count(); 1997 for (int tIndex = 0; tIndex < tCount; ++tIndex) { 1998 const Span& span = fTs[tIndex]; 1999 if (!approximately_negative(span.fT - t)) { 2000 break; 2001 } 2002 if (approximately_negative(span.fT - t) && span.fOther == &other 2003 && approximately_equal(span.fOtherT, otherT)) { 2004#if DEBUG_ADD_T_PAIR 2005 SkDebugf("%s addTPair duplicate this=%d %1.9g other=%d %1.9g\n", 2006 __FUNCTION__, fID, t, other.fID, otherT); 2007#endif 2008 return; 2009 } 2010 } 2011#if DEBUG_ADD_T_PAIR 2012 SkDebugf("%s addTPair this=%d %1.9g other=%d %1.9g\n", 2013 __FUNCTION__, fID, t, other.fID, otherT); 2014#endif 2015 int insertedAt = addT(&other, pt, t); 2016 int otherInsertedAt = other.addT(this, pt, otherT); 2017 addOtherT(insertedAt, otherT, otherInsertedAt); 2018 other.addOtherT(otherInsertedAt, t, insertedAt); 2019 matchWindingValue(insertedAt, t, borrowWind); 2020 other.matchWindingValue(otherInsertedAt, otherT, borrowWind); 2021 } 2022 2023 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const { 2024 // add edge leading into junction 2025 int min = SkMin32(end, start); 2026 if (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0) { 2027 addAngle(angles, end, start); 2028 } 2029 // add edge leading away from junction 2030 int step = SkSign32(end - start); 2031 int tIndex = nextExactSpan(end, step); 2032 min = SkMin32(end, tIndex); 2033 if (tIndex >= 0 && (fTs[min].fWindValue > 0 || fTs[min].fOppValue > 0)) { 2034 addAngle(angles, end, tIndex); 2035 } 2036 } 2037 2038 int advanceCoincidentThis(const Span* oTest, bool opp, int index) { 2039 Span* const test = &fTs[index]; 2040 Span* end = test; 2041 do { 2042 end = &fTs[++index]; 2043 } while (approximately_negative(end->fT - test->fT)); 2044 return index; 2045 } 2046 2047 int advanceCoincidentOther(const Span* test, double oEndT, int& oIndex) { 2048 Span* const oTest = &fTs[oIndex]; 2049 Span* oEnd = oTest; 2050 const double oStartT = oTest->fT; 2051 while (!approximately_negative(oEndT - oEnd->fT) 2052 && approximately_negative(oEnd->fT - oStartT)) { 2053 oEnd = &fTs[++oIndex]; 2054 } 2055 return oIndex; 2056 } 2057 2058 bool betweenTs(int lesser, double testT, int greater) { 2059 if (lesser > greater) { 2060 SkTSwap<int>(lesser, greater); 2061 } 2062 return approximately_between(fTs[lesser].fT, testT, fTs[greater].fT); 2063 } 2064 2065 const Bounds& bounds() const { 2066 return fBounds; 2067 } 2068 2069 void buildAngles(int index, SkTDArray<Angle>& angles, bool includeOpp) const { 2070 double referenceT = fTs[index].fT; 2071 int lesser = index; 2072 while (--lesser >= 0 && (includeOpp || fTs[lesser].fOther->fOperand == fOperand) 2073 && precisely_negative(referenceT - fTs[lesser].fT)) { 2074 buildAnglesInner(lesser, angles); 2075 } 2076 do { 2077 buildAnglesInner(index, angles); 2078 } while (++index < fTs.count() && (includeOpp || fTs[index].fOther->fOperand == fOperand) 2079 && precisely_negative(fTs[index].fT - referenceT)); 2080 } 2081 2082 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const { 2083 Span* span = &fTs[index]; 2084 Segment* other = span->fOther; 2085 // if there is only one live crossing, and no coincidence, continue 2086 // in the same direction 2087 // if there is coincidence, the only choice may be to reverse direction 2088 // find edge on either side of intersection 2089 int oIndex = span->fOtherIndex; 2090 // if done == -1, prior span has already been processed 2091 int step = 1; 2092 int next = other->nextExactSpan(oIndex, step); 2093 if (next < 0) { 2094 step = -step; 2095 next = other->nextExactSpan(oIndex, step); 2096 } 2097 // add candidate into and away from junction 2098 other->addTwoAngles(next, oIndex, angles); 2099 } 2100 2101 int computeSum(int startIndex, int endIndex, bool binary) { 2102 SkTDArray<Angle> angles; 2103 addTwoAngles(startIndex, endIndex, angles); 2104 buildAngles(endIndex, angles, false); 2105 // OPTIMIZATION: check all angles to see if any have computed wind sum 2106 // before sorting (early exit if none) 2107 SkTDArray<Angle*> sorted; 2108 bool sortable = SortAngles(angles, sorted); 2109#if DEBUG_SORT 2110 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0); 2111#endif 2112 if (!sortable) { 2113 return SK_MinS32; 2114 } 2115 int angleCount = angles.count(); 2116 const Angle* angle; 2117 const Segment* base; 2118 int winding; 2119 int oWinding; 2120 int firstIndex = 0; 2121 do { 2122 angle = sorted[firstIndex]; 2123 base = angle->segment(); 2124 winding = base->windSum(angle); 2125 if (winding != SK_MinS32) { 2126 oWinding = base->oppSum(angle); 2127 break; 2128 } 2129 if (++firstIndex == angleCount) { 2130 return SK_MinS32; 2131 } 2132 } while (true); 2133 // turn winding into contourWinding 2134 int spanWinding = base->spanSign(angle); 2135 bool inner = useInnerWinding(winding + spanWinding, winding); 2136 #if DEBUG_WINDING 2137 SkDebugf("%s spanWinding=%d winding=%d sign=%d inner=%d result=%d\n", __FUNCTION__, 2138 spanWinding, winding, angle->sign(), inner, 2139 inner ? winding + spanWinding : winding); 2140 #endif 2141 if (inner) { 2142 winding += spanWinding; 2143 } 2144 #if DEBUG_SORT 2145 base->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, oWinding); 2146 #endif 2147 int nextIndex = firstIndex + 1; 2148 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; 2149 winding -= base->spanSign(angle); 2150 oWinding -= base->oppSign(angle); 2151 do { 2152 if (nextIndex == angleCount) { 2153 nextIndex = 0; 2154 } 2155 angle = sorted[nextIndex]; 2156 Segment* segment = angle->segment(); 2157 bool opp = base->fOperand ^ segment->fOperand; 2158 int maxWinding, oMaxWinding; 2159 int spanSign = segment->spanSign(angle); 2160 int oppoSign = segment->oppSign(angle); 2161 if (opp) { 2162 oMaxWinding = oWinding; 2163 oWinding -= spanSign; 2164 maxWinding = winding; 2165 if (oppoSign) { 2166 winding -= oppoSign; 2167 } 2168 } else { 2169 maxWinding = winding; 2170 winding -= spanSign; 2171 oMaxWinding = oWinding; 2172 if (oppoSign) { 2173 oWinding -= oppoSign; 2174 } 2175 } 2176 if (segment->windSum(angle) == SK_MinS32) { 2177 if (opp) { 2178 if (useInnerWinding(oMaxWinding, oWinding)) { 2179 oMaxWinding = oWinding; 2180 } 2181 if (oppoSign && useInnerWinding(maxWinding, winding)) { 2182 maxWinding = winding; 2183 } 2184 (void) segment->markAndChaseWinding(angle, oMaxWinding, maxWinding); 2185 } else { 2186 if (useInnerWinding(maxWinding, winding)) { 2187 maxWinding = winding; 2188 } 2189 if (oppoSign && useInnerWinding(oMaxWinding, oWinding)) { 2190 oMaxWinding = oWinding; 2191 } 2192 (void) segment->markAndChaseWinding(angle, maxWinding, 2193 binary ? oMaxWinding : 0); 2194 } 2195 } 2196 } while (++nextIndex != lastIndex); 2197 int minIndex = SkMin32(startIndex, endIndex); 2198 return windSum(minIndex); 2199 } 2200 2201 int crossedSpanY(const SkPoint& basePt, SkScalar& bestY, double& hitT, bool& hitSomething, 2202 double mid, bool opp, bool current) const { 2203 SkScalar bottom = fBounds.fBottom; 2204 int bestTIndex = -1; 2205 if (bottom <= bestY) { 2206 return bestTIndex; 2207 } 2208 SkScalar top = fBounds.fTop; 2209 if (top >= basePt.fY) { 2210 return bestTIndex; 2211 } 2212 if (fBounds.fLeft > basePt.fX) { 2213 return bestTIndex; 2214 } 2215 if (fBounds.fRight < basePt.fX) { 2216 return bestTIndex; 2217 } 2218 if (fBounds.fLeft == fBounds.fRight) { 2219 // if vertical, and directly above test point, wait for another one 2220 return AlmostEqualUlps(basePt.fX, fBounds.fLeft) ? SK_MinS32 : bestTIndex; 2221 } 2222 // intersect ray starting at basePt with edge 2223 Intersections intersections; 2224 // OPTIMIZE: use specialty function that intersects ray with curve, 2225 // returning t values only for curve (we don't care about t on ray) 2226 int pts = (*VSegmentIntersect[fVerb])(fPts, top, bottom, basePt.fX, false, intersections); 2227 if (pts == 0 || (current && pts == 1)) { 2228 return bestTIndex; 2229 } 2230 if (current) { 2231 SkASSERT(pts > 1); 2232 int closestIdx = 0; 2233 double closest = fabs(intersections.fT[0][0] - mid); 2234 for (int idx = 1; idx < pts; ++idx) { 2235 double test = fabs(intersections.fT[0][idx] - mid); 2236 if (closest > test) { 2237 closestIdx = idx; 2238 closest = test; 2239 } 2240 } 2241 if (closestIdx < pts - 1) { 2242 intersections.fT[0][closestIdx] = intersections.fT[0][pts - 1]; 2243 } 2244 --pts; 2245 } 2246 double bestT = -1; 2247 for (int index = 0; index < pts; ++index) { 2248 double foundT = intersections.fT[0][index]; 2249 if (approximately_less_than_zero(foundT) 2250 || approximately_greater_than_one(foundT)) { 2251 continue; 2252 } 2253 SkScalar testY = (*SegmentYAtT[fVerb])(fPts, foundT); 2254 if (approximately_negative(testY - bestY) 2255 || approximately_negative(basePt.fY - testY)) { 2256 continue; 2257 } 2258 if (pts > 1 && fVerb == SkPath::kLine_Verb) { 2259 return SK_MinS32; // if the intersection is edge on, wait for another one 2260 } 2261 if (fVerb > SkPath::kLine_Verb) { 2262 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, foundT); 2263 if (approximately_zero(dx)) { 2264 return SK_MinS32; // hit vertical, wait for another one 2265 } 2266 } 2267 bestY = testY; 2268 bestT = foundT; 2269 } 2270 if (bestT < 0) { 2271 return bestTIndex; 2272 } 2273 SkASSERT(bestT >= 0); 2274 SkASSERT(bestT <= 1); 2275 int start; 2276 int end = 0; 2277 do { 2278 start = end; 2279 end = nextSpan(start, 1); 2280 } while (fTs[end].fT < bestT); 2281 // FIXME: see next candidate for a better pattern to find the next start/end pair 2282 while (start + 1 < end && fTs[start].fDone) { 2283 ++start; 2284 } 2285 if (!isCanceled(start)) { 2286 hitT = bestT; 2287 bestTIndex = start; 2288 hitSomething = true; 2289 } 2290 return bestTIndex; 2291 } 2292 2293 void decrementSpan(Span* span) { 2294 SkASSERT(span->fWindValue > 0); 2295 if (--(span->fWindValue) == 0) { 2296 if (!span->fOppValue && !span->fDone) { 2297 span->fDone = true; 2298 ++fDoneSpans; 2299 } 2300 } 2301 } 2302 2303 bool bumpSpan(Span* span, int windDelta, int oppDelta) { 2304 SkASSERT(!span->fDone); 2305 span->fWindValue += windDelta; 2306 SkASSERT(span->fWindValue >= 0); 2307 span->fOppValue += oppDelta; 2308 SkASSERT(span->fOppValue >= 0); 2309 if (fXor) { 2310 span->fWindValue &= 1; 2311 } 2312 if (fOppXor) { 2313 span->fOppValue &= 1; 2314 } 2315 if (!span->fWindValue && !span->fOppValue) { 2316 span->fDone = true; 2317 ++fDoneSpans; 2318 return true; 2319 } 2320 return false; 2321 } 2322 2323 // OPTIMIZE 2324 // when the edges are initially walked, they don't automatically get the prior and next 2325 // edges assigned to positions t=0 and t=1. Doing that would remove the need for this check, 2326 // and would additionally remove the need for similar checks in condition edges. It would 2327 // also allow intersection code to assume end of segment intersections (maybe?) 2328 bool complete() const { 2329 int count = fTs.count(); 2330 return count > 1 && fTs[0].fT == 0 && fTs[--count].fT == 1; 2331 } 2332 2333 bool done() const { 2334 SkASSERT(fDoneSpans <= fTs.count()); 2335 return fDoneSpans == fTs.count(); 2336 } 2337 2338 bool done(int min) const { 2339 return fTs[min].fDone; 2340 } 2341 2342 bool done(const Angle* angle) const { 2343 return done(SkMin32(angle->start(), angle->end())); 2344 } 2345 2346 SkVector dxdy(int index) const { 2347 return (*SegmentDXDYAtT[fVerb])(fPts, fTs[index].fT); 2348 } 2349 2350 SkScalar dy(int index) const { 2351 return (*SegmentDYAtT[fVerb])(fPts, fTs[index].fT); 2352 } 2353 2354 bool equalPoints(int greaterTIndex, int lesserTIndex) { 2355 SkASSERT(greaterTIndex >= lesserTIndex); 2356 double greaterT = fTs[greaterTIndex].fT; 2357 double lesserT = fTs[lesserTIndex].fT; 2358 if (greaterT == lesserT) { 2359 return true; 2360 } 2361 if (!approximately_negative(greaterT - lesserT)) { 2362 return false; 2363 } 2364 return xyAtT(greaterTIndex) == xyAtT(lesserTIndex); 2365 } 2366 2367 /* 2368 The M and S variable name parts stand for the operators. 2369 Mi stands for Minuend (see wiki subtraction, analogous to difference) 2370 Su stands for Subtrahend 2371 The Opp variable name part designates that the value is for the Opposite operator. 2372 Opposite values result from combining coincident spans. 2373 */ 2374 2375 Segment* findNextOp(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd, 2376 bool& unsortable, ShapeOp op, const int xorMiMask, const int xorSuMask) { 2377 const int startIndex = nextStart; 2378 const int endIndex = nextEnd; 2379 SkASSERT(startIndex != endIndex); 2380 const int count = fTs.count(); 2381 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0); 2382 const int step = SkSign32(endIndex - startIndex); 2383 const int end = nextExactSpan(startIndex, step); 2384 SkASSERT(end >= 0); 2385 Span* endSpan = &fTs[end]; 2386 Segment* other; 2387 if (isSimple(end)) { 2388 // mark the smaller of startIndex, endIndex done, and all adjacent 2389 // spans with the same T value (but not 'other' spans) 2390 #if DEBUG_WINDING 2391 SkDebugf("%s simple\n", __FUNCTION__); 2392 #endif 2393 int min = SkMin32(startIndex, endIndex); 2394 if (fTs[min].fDone) { 2395 return NULL; 2396 } 2397 markDoneBinary(min); 2398 other = endSpan->fOther; 2399 nextStart = endSpan->fOtherIndex; 2400 double startT = other->fTs[nextStart].fT; 2401 nextEnd = nextStart; 2402 do { 2403 nextEnd += step; 2404 } 2405 while (precisely_zero(startT - other->fTs[nextEnd].fT)); 2406 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count()); 2407 return other; 2408 } 2409 // more than one viable candidate -- measure angles to find best 2410 SkTDArray<Angle> angles; 2411 SkASSERT(startIndex - endIndex != 0); 2412 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); 2413 addTwoAngles(startIndex, end, angles); 2414 buildAngles(end, angles, true); 2415 SkTDArray<Angle*> sorted; 2416 bool sortable = SortAngles(angles, sorted); 2417 int angleCount = angles.count(); 2418 int firstIndex = findStartingEdge(sorted, startIndex, end); 2419 SkASSERT(firstIndex >= 0); 2420 #if DEBUG_SORT 2421 debugShowSort(__FUNCTION__, sorted, firstIndex); 2422 #endif 2423 if (!sortable) { 2424 unsortable = true; 2425 return NULL; 2426 } 2427 SkASSERT(sorted[firstIndex]->segment() == this); 2428 #if DEBUG_WINDING 2429 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex, 2430 sorted[firstIndex]->sign()); 2431 #endif 2432 int sumMiWinding = updateWinding(endIndex, startIndex); 2433 int sumSuWinding = updateOppWinding(endIndex, startIndex); 2434 if (operand()) { 2435 SkTSwap<int>(sumMiWinding, sumSuWinding); 2436 } 2437 int nextIndex = firstIndex + 1; 2438 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; 2439 const Angle* foundAngle = NULL; 2440 bool foundDone = false; 2441 // iterate through the angle, and compute everyone's winding 2442 Segment* nextSegment; 2443 int activeCount = 0; 2444 do { 2445 SkASSERT(nextIndex != firstIndex); 2446 if (nextIndex == angleCount) { 2447 nextIndex = 0; 2448 } 2449 const Angle* nextAngle = sorted[nextIndex]; 2450 nextSegment = nextAngle->segment(); 2451 int maxWinding, sumWinding, oppMaxWinding, oppSumWinding; 2452 bool activeAngle = nextSegment->activeOp(xorMiMask, xorSuMask, nextAngle->start(), 2453 nextAngle->end(), op, sumMiWinding, sumSuWinding, 2454 maxWinding, sumWinding, oppMaxWinding, oppSumWinding); 2455 if (activeAngle) { 2456 ++activeCount; 2457 if (!foundAngle || (foundDone && activeCount & 1)) { 2458 if (nextSegment->tiny(nextAngle)) { 2459 unsortable = true; 2460 return NULL; 2461 } 2462 foundAngle = nextAngle; 2463 foundDone = nextSegment->done(nextAngle) && !nextSegment->tiny(nextAngle); 2464 } 2465 } 2466 if (nextSegment->done()) { 2467 continue; 2468 } 2469 if (nextSegment->windSum(nextAngle) != SK_MinS32) { 2470 continue; 2471 } 2472 Span* last = nextSegment->markAngle(maxWinding, sumWinding, oppMaxWinding, 2473 oppSumWinding, activeAngle, nextAngle); 2474 if (last) { 2475 *chase.append() = last; 2476#if DEBUG_WINDING 2477 SkDebugf("%s chase.append id=%d\n", __FUNCTION__, 2478 last->fOther->fTs[last->fOtherIndex].fOther->debugID()); 2479#endif 2480 } 2481 } while (++nextIndex != lastIndex); 2482 markDoneBinary(SkMin32(startIndex, endIndex)); 2483 if (!foundAngle) { 2484 return NULL; 2485 } 2486 nextStart = foundAngle->start(); 2487 nextEnd = foundAngle->end(); 2488 nextSegment = foundAngle->segment(); 2489 2490 #if DEBUG_WINDING 2491 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 2492 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd); 2493 #endif 2494 return nextSegment; 2495 } 2496 2497 Segment* findNextWinding(SkTDArray<Span*>& chase, int& nextStart, int& nextEnd, 2498 bool& unsortable) { 2499 const int startIndex = nextStart; 2500 const int endIndex = nextEnd; 2501 SkASSERT(startIndex != endIndex); 2502 const int count = fTs.count(); 2503 SkASSERT(startIndex < endIndex ? startIndex < count - 1 : startIndex > 0); 2504 const int step = SkSign32(endIndex - startIndex); 2505 const int end = nextExactSpan(startIndex, step); 2506 SkASSERT(end >= 0); 2507 Span* endSpan = &fTs[end]; 2508 Segment* other; 2509 if (isSimple(end)) { 2510 // mark the smaller of startIndex, endIndex done, and all adjacent 2511 // spans with the same T value (but not 'other' spans) 2512 #if DEBUG_WINDING 2513 SkDebugf("%s simple\n", __FUNCTION__); 2514 #endif 2515 int min = SkMin32(startIndex, endIndex); 2516 if (fTs[min].fDone) { 2517 return NULL; 2518 } 2519 markDoneUnary(min); 2520 other = endSpan->fOther; 2521 nextStart = endSpan->fOtherIndex; 2522 double startT = other->fTs[nextStart].fT; 2523 nextEnd = nextStart; 2524 do { 2525 nextEnd += step; 2526 } 2527 while (precisely_zero(startT - other->fTs[nextEnd].fT)); 2528 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count()); 2529 return other; 2530 } 2531 // more than one viable candidate -- measure angles to find best 2532 SkTDArray<Angle> angles; 2533 SkASSERT(startIndex - endIndex != 0); 2534 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); 2535 addTwoAngles(startIndex, end, angles); 2536 buildAngles(end, angles, true); 2537 SkTDArray<Angle*> sorted; 2538 bool sortable = SortAngles(angles, sorted); 2539 int angleCount = angles.count(); 2540 int firstIndex = findStartingEdge(sorted, startIndex, end); 2541 SkASSERT(firstIndex >= 0); 2542 #if DEBUG_SORT 2543 debugShowSort(__FUNCTION__, sorted, firstIndex); 2544 #endif 2545 if (!sortable) { 2546 unsortable = true; 2547 return NULL; 2548 } 2549 SkASSERT(sorted[firstIndex]->segment() == this); 2550 #if DEBUG_WINDING 2551 SkDebugf("%s firstIndex=[%d] sign=%d\n", __FUNCTION__, firstIndex, 2552 sorted[firstIndex]->sign()); 2553 #endif 2554 int sumWinding = updateWinding(endIndex, startIndex); 2555 int nextIndex = firstIndex + 1; 2556 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; 2557 const Angle* foundAngle = NULL; 2558 bool foundDone = false; 2559 // iterate through the angle, and compute everyone's winding 2560 Segment* nextSegment; 2561 int activeCount = 0; 2562 do { 2563 SkASSERT(nextIndex != firstIndex); 2564 if (nextIndex == angleCount) { 2565 nextIndex = 0; 2566 } 2567 const Angle* nextAngle = sorted[nextIndex]; 2568 nextSegment = nextAngle->segment(); 2569 int maxWinding; 2570 bool activeAngle = nextSegment->activeWinding(nextAngle->start(), nextAngle->end(), 2571 maxWinding, sumWinding); 2572 if (activeAngle) { 2573 ++activeCount; 2574 if (!foundAngle || (foundDone && activeCount & 1)) { 2575 if (nextSegment->tiny(nextAngle)) { 2576 unsortable = true; 2577 return NULL; 2578 } 2579 foundAngle = nextAngle; 2580 foundDone = nextSegment->done(nextAngle); 2581 } 2582 } 2583 if (nextSegment->done()) { 2584 continue; 2585 } 2586 if (nextSegment->windSum(nextAngle) != SK_MinS32) { 2587 continue; 2588 } 2589 Span* last = nextSegment->markAngle(maxWinding, sumWinding, activeAngle, nextAngle); 2590 if (last) { 2591 *chase.append() = last; 2592#if DEBUG_WINDING 2593 SkDebugf("%s chase.append id=%d\n", __FUNCTION__, 2594 last->fOther->fTs[last->fOtherIndex].fOther->debugID()); 2595#endif 2596 } 2597 } while (++nextIndex != lastIndex); 2598 markDoneUnary(SkMin32(startIndex, endIndex)); 2599 if (!foundAngle) { 2600 return NULL; 2601 } 2602 nextStart = foundAngle->start(); 2603 nextEnd = foundAngle->end(); 2604 nextSegment = foundAngle->segment(); 2605 #if DEBUG_WINDING 2606 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 2607 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd); 2608 #endif 2609 return nextSegment; 2610 } 2611 2612 Segment* findNextXor(int& nextStart, int& nextEnd, bool& unsortable) { 2613 const int startIndex = nextStart; 2614 const int endIndex = nextEnd; 2615 SkASSERT(startIndex != endIndex); 2616 int count = fTs.count(); 2617 SkASSERT(startIndex < endIndex ? startIndex < count - 1 2618 : startIndex > 0); 2619 int step = SkSign32(endIndex - startIndex); 2620 int end = nextExactSpan(startIndex, step); 2621 SkASSERT(end >= 0); 2622 Span* endSpan = &fTs[end]; 2623 Segment* other; 2624 if (isSimple(end)) { 2625 #if DEBUG_WINDING 2626 SkDebugf("%s simple\n", __FUNCTION__); 2627 #endif 2628 int min = SkMin32(startIndex, endIndex); 2629 if (fTs[min].fDone) { 2630 return NULL; 2631 } 2632 markDone(min, 1); 2633 other = endSpan->fOther; 2634 nextStart = endSpan->fOtherIndex; 2635 double startT = other->fTs[nextStart].fT; 2636 #if 01 // FIXME: I don't know why the logic here is difference from the winding case 2637 SkDEBUGCODE(bool firstLoop = true;) 2638 if ((approximately_less_than_zero(startT) && step < 0) 2639 || (approximately_greater_than_one(startT) && step > 0)) { 2640 step = -step; 2641 SkDEBUGCODE(firstLoop = false;) 2642 } 2643 do { 2644 #endif 2645 nextEnd = nextStart; 2646 do { 2647 nextEnd += step; 2648 } 2649 while (precisely_zero(startT - other->fTs[nextEnd].fT)); 2650 #if 01 2651 if (other->fTs[SkMin32(nextStart, nextEnd)].fWindValue) { 2652 break; 2653 } 2654 #ifdef SK_DEBUG 2655 SkASSERT(firstLoop); 2656 #endif 2657 SkDEBUGCODE(firstLoop = false;) 2658 step = -step; 2659 } while (true); 2660 #endif 2661 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count()); 2662 return other; 2663 } 2664 SkTDArray<Angle> angles; 2665 SkASSERT(startIndex - endIndex != 0); 2666 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); 2667 addTwoAngles(startIndex, end, angles); 2668 buildAngles(end, angles, false); 2669 SkTDArray<Angle*> sorted; 2670 bool sortable = SortAngles(angles, sorted); 2671 if (!sortable) { 2672 unsortable = true; 2673 #if DEBUG_SORT 2674 debugShowSort(__FUNCTION__, sorted, findStartingEdge(sorted, startIndex, end), 0, 0); 2675 #endif 2676 return NULL; 2677 } 2678 int angleCount = angles.count(); 2679 int firstIndex = findStartingEdge(sorted, startIndex, end); 2680 SkASSERT(firstIndex >= 0); 2681 #if DEBUG_SORT 2682 debugShowSort(__FUNCTION__, sorted, firstIndex, 0, 0); 2683 #endif 2684 SkASSERT(sorted[firstIndex]->segment() == this); 2685 int nextIndex = firstIndex + 1; 2686 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; 2687 const Angle* foundAngle = NULL; 2688 bool foundDone = false; 2689 Segment* nextSegment; 2690 int activeCount = 0; 2691 do { 2692 SkASSERT(nextIndex != firstIndex); 2693 if (nextIndex == angleCount) { 2694 nextIndex = 0; 2695 } 2696 const Angle* nextAngle = sorted[nextIndex]; 2697 nextSegment = nextAngle->segment(); 2698 ++activeCount; 2699 if (!foundAngle || (foundDone && activeCount & 1)) { 2700 if (nextSegment->tiny(nextAngle)) { 2701 unsortable = true; 2702 return NULL; 2703 } 2704 foundAngle = nextAngle; 2705 foundDone = nextSegment->done(nextAngle); 2706 } 2707 if (nextSegment->done()) { 2708 continue; 2709 } 2710 } while (++nextIndex != lastIndex); 2711 markDone(SkMin32(startIndex, endIndex), 1); 2712 if (!foundAngle) { 2713 return NULL; 2714 } 2715 nextStart = foundAngle->start(); 2716 nextEnd = foundAngle->end(); 2717 nextSegment = foundAngle->segment(); 2718 #if DEBUG_WINDING 2719 SkDebugf("%s from:[%d] to:[%d] start=%d end=%d\n", 2720 __FUNCTION__, debugID(), nextSegment->debugID(), nextStart, nextEnd); 2721 #endif 2722 return nextSegment; 2723 } 2724 2725 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) { 2726 int angleCount = sorted.count(); 2727 int firstIndex = -1; 2728 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) { 2729 const Angle* angle = sorted[angleIndex]; 2730 if (angle->segment() == this && angle->start() == end && 2731 angle->end() == start) { 2732 firstIndex = angleIndex; 2733 break; 2734 } 2735 } 2736 return firstIndex; 2737 } 2738 2739 // FIXME: this is tricky code; needs its own unit test 2740 // note that fOtherIndex isn't computed yet, so it can't be used here 2741 void findTooCloseToCall() { 2742 int count = fTs.count(); 2743 if (count < 3) { // require t=0, x, 1 at minimum 2744 return; 2745 } 2746 int matchIndex = 0; 2747 int moCount; 2748 Span* match; 2749 Segment* mOther; 2750 do { 2751 match = &fTs[matchIndex]; 2752 mOther = match->fOther; 2753 // FIXME: allow quads, cubics to be near coincident? 2754 if (mOther->fVerb == SkPath::kLine_Verb) { 2755 moCount = mOther->fTs.count(); 2756 if (moCount >= 3) { 2757 break; 2758 } 2759 } 2760 if (++matchIndex >= count) { 2761 return; 2762 } 2763 } while (true); // require t=0, x, 1 at minimum 2764 // OPTIMIZATION: defer matchPt until qualifying toCount is found? 2765 const SkPoint* matchPt = &xyAtT(match); 2766 // look for a pair of nearby T values that map to the same (x,y) value 2767 // if found, see if the pair of other segments share a common point. If 2768 // so, the span from here to there is coincident. 2769 for (int index = matchIndex + 1; index < count; ++index) { 2770 Span* test = &fTs[index]; 2771 if (test->fDone) { 2772 continue; 2773 } 2774 Segment* tOther = test->fOther; 2775 if (tOther->fVerb != SkPath::kLine_Verb) { 2776 continue; // FIXME: allow quads, cubics to be near coincident? 2777 } 2778 int toCount = tOther->fTs.count(); 2779 if (toCount < 3) { // require t=0, x, 1 at minimum 2780 continue; 2781 } 2782 const SkPoint* testPt = &xyAtT(test); 2783 if (*matchPt != *testPt) { 2784 matchIndex = index; 2785 moCount = toCount; 2786 match = test; 2787 mOther = tOther; 2788 matchPt = testPt; 2789 continue; 2790 } 2791 int moStart = -1; 2792 int moEnd = -1; 2793 double moStartT, moEndT; 2794 for (int moIndex = 0; moIndex < moCount; ++moIndex) { 2795 Span& moSpan = mOther->fTs[moIndex]; 2796 if (moSpan.fDone) { 2797 continue; 2798 } 2799 if (moSpan.fOther == this) { 2800 if (moSpan.fOtherT == match->fT) { 2801 moStart = moIndex; 2802 moStartT = moSpan.fT; 2803 } 2804 continue; 2805 } 2806 if (moSpan.fOther == tOther) { 2807 if (tOther->windValueAt(moSpan.fOtherT) == 0) { 2808 moStart = -1; 2809 break; 2810 } 2811 SkASSERT(moEnd == -1); 2812 moEnd = moIndex; 2813 moEndT = moSpan.fT; 2814 } 2815 } 2816 if (moStart < 0 || moEnd < 0) { 2817 continue; 2818 } 2819 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test 2820 if (approximately_equal(moStartT, moEndT)) { 2821 continue; 2822 } 2823 int toStart = -1; 2824 int toEnd = -1; 2825 double toStartT, toEndT; 2826 for (int toIndex = 0; toIndex < toCount; ++toIndex) { 2827 Span& toSpan = tOther->fTs[toIndex]; 2828 if (toSpan.fDone) { 2829 continue; 2830 } 2831 if (toSpan.fOther == this) { 2832 if (toSpan.fOtherT == test->fT) { 2833 toStart = toIndex; 2834 toStartT = toSpan.fT; 2835 } 2836 continue; 2837 } 2838 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) { 2839 if (mOther->windValueAt(toSpan.fOtherT) == 0) { 2840 moStart = -1; 2841 break; 2842 } 2843 SkASSERT(toEnd == -1); 2844 toEnd = toIndex; 2845 toEndT = toSpan.fT; 2846 } 2847 } 2848 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test 2849 if (toStart <= 0 || toEnd <= 0) { 2850 continue; 2851 } 2852 if (approximately_equal(toStartT, toEndT)) { 2853 continue; 2854 } 2855 // test to see if the segment between there and here is linear 2856 if (!mOther->isLinear(moStart, moEnd) 2857 || !tOther->isLinear(toStart, toEnd)) { 2858 continue; 2859 } 2860 bool flipped = (moStart - moEnd) * (toStart - toEnd) < 1; 2861 if (flipped) { 2862 mOther->addTCancel(moStartT, moEndT, *tOther, toEndT, toStartT); 2863 } else { 2864 mOther->addTCoincident(moStartT, moEndT, *tOther, toStartT, toEndT); 2865 } 2866 } 2867 } 2868 2869 // FIXME: either: 2870 // a) mark spans with either end unsortable as done, or 2871 // b) rewrite findTop / findTopSegment / findTopContour to iterate further 2872 // when encountering an unsortable span 2873 2874 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached) 2875 // and use more concise logic like the old edge walker code? 2876 // FIXME: this needs to deal with coincident edges 2877 Segment* findTop(int& tIndex, int& endIndex, bool& unsortable, bool onlySortable) { 2878 // iterate through T intersections and return topmost 2879 // topmost tangent from y-min to first pt is closer to horizontal 2880 SkASSERT(!done()); 2881 int firstT = -1; 2882 /* SkPoint topPt = */ activeLeftTop(onlySortable, &firstT); 2883 SkASSERT(firstT >= 0); 2884 // sort the edges to find the leftmost 2885 int step = 1; 2886 int end = nextSpan(firstT, step); 2887 if (end == -1) { 2888 step = -1; 2889 end = nextSpan(firstT, step); 2890 SkASSERT(end != -1); 2891 } 2892 // if the topmost T is not on end, or is three-way or more, find left 2893 // look for left-ness from tLeft to firstT (matching y of other) 2894 SkTDArray<Angle> angles; 2895 SkASSERT(firstT - end != 0); 2896 addTwoAngles(end, firstT, angles); 2897 buildAngles(firstT, angles, true); 2898 SkTDArray<Angle*> sorted; 2899 bool sortable = SortAngles(angles, sorted); 2900 #if DEBUG_SORT 2901 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0); 2902 #endif 2903 if (onlySortable && !sortable) { 2904 unsortable = true; 2905 return NULL; 2906 } 2907 // skip edges that have already been processed 2908 firstT = -1; 2909 Segment* leftSegment; 2910 do { 2911 const Angle* angle = sorted[++firstT]; 2912 SkASSERT(!onlySortable || !angle->unsortable()); 2913 leftSegment = angle->segment(); 2914 tIndex = angle->end(); 2915 endIndex = angle->start(); 2916 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone); 2917 if (leftSegment->verb() >= SkPath::kQuad_Verb) { 2918 bool bumpsUp = leftSegment->bumpsUp(tIndex, endIndex); 2919 SkPoint xyE = leftSegment->xyAtT(endIndex); 2920 SkPoint xyS = leftSegment->xyAtT(tIndex); 2921 SkVector dxyE = leftSegment->dxdy(endIndex); 2922 SkVector dxyS = leftSegment->dxdy(tIndex); 2923 double cross = dxyE.cross(dxyS); 2924 bool bumpCheck = bumpsUp && xyE.fY < xyS.fY && dxyE.fX < 0; 2925 if (xyE == xyS){ 2926 SkDebugf("%s ignore loops\n", __FUNCTION__); 2927 cross = 0; 2928 } 2929 #if DEBUG_SWAP_TOP 2930 SkDebugf("%s xyE=(%1.9g,%1.9g) xyS=(%1.9g,%1.9g)\n", __FUNCTION__, 2931 xyE.fX, xyE.fY, xyS.fX, xyS.fY); 2932 SkDebugf("%s dxyE=(%1.9g,%1.9g) dxyS=(%1.9g,%1.9g) cross=%1.9g bumpsUp=%s\n", 2933 __FUNCTION__, 2934 dxyE.fX, dxyE.fY, dxyS.fX, dxyS.fY, cross, bumpsUp ? "true" : "false"); 2935 if ((cross > 0) ^ bumpCheck) { 2936 leftSegment->bumpsUp(tIndex, endIndex); 2937 SkDebugf("%s cross bump disagree\n", __FUNCTION__); 2938 } 2939 #endif 2940 if (cross > 0 || bumpCheck) { 2941 #if DEBUG_SWAP_TOP 2942 SkDebugf("%s swap\n", __FUNCTION__); 2943 #endif 2944 SkTSwap(tIndex, endIndex); 2945 } 2946 } 2947 SkASSERT(!leftSegment->fTs[SkMin32(tIndex, endIndex)].fTiny); 2948 return leftSegment; 2949 } 2950 2951 // FIXME: not crazy about this 2952 // when the intersections are performed, the other index is into an 2953 // incomplete array. as the array grows, the indices become incorrect 2954 // while the following fixes the indices up again, it isn't smart about 2955 // skipping segments whose indices are already correct 2956 // assuming we leave the code that wrote the index in the first place 2957 void fixOtherTIndex() { 2958 int iCount = fTs.count(); 2959 for (int i = 0; i < iCount; ++i) { 2960 Span& iSpan = fTs[i]; 2961 double oT = iSpan.fOtherT; 2962 Segment* other = iSpan.fOther; 2963 int oCount = other->fTs.count(); 2964 for (int o = 0; o < oCount; ++o) { 2965 Span& oSpan = other->fTs[o]; 2966 if (oT == oSpan.fT && this == oSpan.fOther) { 2967 iSpan.fOtherIndex = o; 2968 break; 2969 } 2970 } 2971 } 2972 } 2973 2974 void init(const SkPoint pts[], SkPath::Verb verb, bool operand, bool evenOdd) { 2975 fDoneSpans = 0; 2976 fOperand = operand; 2977 fXor = evenOdd; 2978 fPts = pts; 2979 fVerb = verb; 2980 } 2981 2982 void initWinding(int start, int end) { 2983 int local = spanSign(start, end); 2984 int oppLocal = oppSign(start, end); 2985 (void) markAndChaseWinding(start, end, local, oppLocal); 2986 // OPTIMIZATION: the reverse mark and chase could skip the first marking 2987 (void) markAndChaseWinding(end, start, local, oppLocal); 2988 } 2989 2990 void initWinding(int start, int end, int winding, int oppWinding) { 2991 int local = spanSign(start, end); 2992 if (local * winding >= 0) { 2993 winding += local; 2994 } 2995 int oppLocal = oppSign(start, end); 2996 if (oppLocal * oppWinding >= 0) { 2997 oppWinding += oppLocal; 2998 } 2999 (void) markAndChaseWinding(start, end, winding, oppWinding); 3000 } 3001 3002/* 3003when we start with a vertical intersect, we try to use the dx to determine if the edge is to 3004the left or the right of vertical. This determines if we need to add the span's 3005sign or not. However, this isn't enough. 3006If the supplied sign (winding) is zero, then we didn't hit another vertical span, so dx is needed. 3007If there was a winding, then it may or may not need adjusting. If the span the winding was borrowed 3008from has the same x direction as this span, the winding should change. If the dx is opposite, then 3009the same winding is shared by both. 3010*/ 3011 void initWinding(int start, int end, double tHit, int winding, SkScalar hitDx, int oppWind, 3012 SkScalar hitOppDx) { 3013 SkASSERT(hitDx || !winding); 3014 SkScalar dx = (*SegmentDXAtT[fVerb])(fPts, tHit); 3015 SkASSERT(dx); 3016 int windVal = windValue(SkMin32(start, end)); 3017 #if DEBUG_WINDING_AT_T 3018 SkDebugf("%s oldWinding=%d hitDx=%c dx=%c windVal=%d", __FUNCTION__, winding, 3019 hitDx ? hitDx > 0 ? '+' : '-' : '0', dx > 0 ? '+' : '-', windVal); 3020 #endif 3021 if (!winding) { 3022 winding = dx < 0 ? windVal : -windVal; 3023 } else if (winding * dx < 0) { 3024 int sideWind = winding + (dx < 0 ? windVal : -windVal); 3025 if (abs(winding) < abs(sideWind)) { 3026 winding = sideWind; 3027 } 3028 } 3029 #if DEBUG_WINDING_AT_T 3030 SkDebugf(" winding=%d\n", winding); 3031 #endif 3032 int oppLocal = oppSign(start, end); 3033 SkASSERT(hitOppDx || !oppWind || !oppLocal); 3034 int oppWindVal = oppValue(SkMin32(start, end)); 3035 if (!oppWind) { 3036 oppWind = dx < 0 ? oppWindVal : -oppWindVal; 3037 } else if (hitOppDx * dx >= 0) { 3038 int oppSideWind = oppWind + (dx < 0 ? oppWindVal : -oppWindVal); 3039 if (abs(oppWind) < abs(oppSideWind)) { 3040 oppWind = oppSideWind; 3041 } 3042 } 3043 (void) markAndChaseWinding(start, end, winding, oppWind); 3044 } 3045 3046 bool intersected() const { 3047 return fTs.count() > 0; 3048 } 3049 3050 bool isCanceled(int tIndex) const { 3051 return fTs[tIndex].fWindValue == 0 && fTs[tIndex].fOppValue == 0; 3052 } 3053 3054 bool isConnected(int startIndex, int endIndex) const { 3055 return fTs[startIndex].fWindSum != SK_MinS32 3056 || fTs[endIndex].fWindSum != SK_MinS32; 3057 } 3058 3059 bool isHorizontal() const { 3060 return fBounds.fTop == fBounds.fBottom; 3061 } 3062 3063 bool isLinear(int start, int end) const { 3064 if (fVerb == SkPath::kLine_Verb) { 3065 return true; 3066 } 3067 if (fVerb == SkPath::kQuad_Verb) { 3068 SkPoint qPart[3]; 3069 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart); 3070 return QuadIsLinear(qPart); 3071 } else { 3072 SkASSERT(fVerb == SkPath::kCubic_Verb); 3073 SkPoint cPart[4]; 3074 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart); 3075 return CubicIsLinear(cPart); 3076 } 3077 } 3078 3079 // OPTIMIZE: successive calls could start were the last leaves off 3080 // or calls could specialize to walk forwards or backwards 3081 bool isMissing(double startT) const { 3082 size_t tCount = fTs.count(); 3083 for (size_t index = 0; index < tCount; ++index) { 3084 if (approximately_zero(startT - fTs[index].fT)) { 3085 return false; 3086 } 3087 } 3088 return true; 3089 } 3090 3091 bool isSimple(int end) const { 3092 int count = fTs.count(); 3093 if (count == 2) { 3094 return true; 3095 } 3096 double t = fTs[end].fT; 3097 if (approximately_less_than_zero(t)) { 3098 return !approximately_less_than_zero(fTs[1].fT); 3099 } 3100 if (approximately_greater_than_one(t)) { 3101 return !approximately_greater_than_one(fTs[count - 2].fT); 3102 } 3103 return false; 3104 } 3105 3106 bool isVertical() const { 3107 return fBounds.fLeft == fBounds.fRight; 3108 } 3109 3110 bool isVertical(int start, int end) const { 3111 return (*SegmentVertical[fVerb])(fPts, start, end); 3112 } 3113 3114 SkScalar leftMost(int start, int end) const { 3115 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT); 3116 } 3117 3118 // this span is excluded by the winding rule -- chase the ends 3119 // as long as they are unambiguous to mark connections as done 3120 // and give them the same winding value 3121 Span* markAndChaseDone(const Angle* angle, int winding) { 3122 int index = angle->start(); 3123 int endIndex = angle->end(); 3124 return markAndChaseDone(index, endIndex, winding); 3125 } 3126 3127 Span* markAndChaseDone(int index, int endIndex, int winding) { 3128 int step = SkSign32(endIndex - index); 3129 int min = SkMin32(index, endIndex); 3130 markDone(min, winding); 3131 Span* last; 3132 Segment* other = this; 3133 while ((other = other->nextChase(index, step, min, last))) { 3134 other->markDone(min, winding); 3135 } 3136 return last; 3137 } 3138 3139 Span* markAndChaseDoneBinary(const Angle* angle, int winding, int oppWinding) { 3140 int index = angle->start(); 3141 int endIndex = angle->end(); 3142 int step = SkSign32(endIndex - index); 3143 int min = SkMin32(index, endIndex); 3144 markDoneBinary(min, winding, oppWinding); 3145 Span* last; 3146 Segment* other = this; 3147 while ((other = other->nextChase(index, step, min, last))) { 3148 other->markDoneBinary(min, winding, oppWinding); 3149 } 3150 return last; 3151 } 3152 3153 Span* markAndChaseDoneBinary(int index, int endIndex) { 3154 int step = SkSign32(endIndex - index); 3155 int min = SkMin32(index, endIndex); 3156 markDoneBinary(min); 3157 Span* last; 3158 Segment* other = this; 3159 while ((other = other->nextChase(index, step, min, last))) { 3160 if (other->done()) { 3161 return NULL; 3162 } 3163 other->markDoneBinary(min); 3164 } 3165 return last; 3166 } 3167 3168 Span* markAndChaseDoneUnary(int index, int endIndex) { 3169 int step = SkSign32(endIndex - index); 3170 int min = SkMin32(index, endIndex); 3171 markDoneUnary(min); 3172 Span* last; 3173 Segment* other = this; 3174 while ((other = other->nextChase(index, step, min, last))) { 3175 if (other->done()) { 3176 return NULL; 3177 } 3178 other->markDoneUnary(min); 3179 } 3180 return last; 3181 } 3182 3183 Span* markAndChaseDoneUnary(const Angle* angle, int winding) { 3184 int index = angle->start(); 3185 int endIndex = angle->end(); 3186 return markAndChaseDone(index, endIndex, winding); 3187 } 3188 3189 Span* markAndChaseWinding(const Angle* angle, const int winding) { 3190 int index = angle->start(); 3191 int endIndex = angle->end(); 3192 int step = SkSign32(endIndex - index); 3193 int min = SkMin32(index, endIndex); 3194 markWinding(min, winding); 3195 Span* last; 3196 Segment* other = this; 3197 while ((other = other->nextChase(index, step, min, last))) { 3198 if (other->fTs[min].fWindSum != SK_MinS32) { 3199 SkASSERT(other->fTs[min].fWindSum == winding); 3200 return NULL; 3201 } 3202 other->markWinding(min, winding); 3203 } 3204 return last; 3205 } 3206 3207 Span* markAndChaseWinding(int index, int endIndex, int winding, int oppWinding) { 3208 int min = SkMin32(index, endIndex); 3209 int step = SkSign32(endIndex - index); 3210 markWinding(min, winding, oppWinding); 3211 Span* last; 3212 Segment* other = this; 3213 while ((other = other->nextChase(index, step, min, last))) { 3214 if (other->fTs[min].fWindSum != SK_MinS32) { 3215 SkASSERT(other->fTs[min].fWindSum == winding || other->fTs[min].fLoop); 3216 return NULL; 3217 } 3218 other->markWinding(min, winding, oppWinding); 3219 } 3220 return last; 3221 } 3222 3223 Span* markAndChaseWinding(const Angle* angle, int winding, int oppWinding) { 3224 int start = angle->start(); 3225 int end = angle->end(); 3226 return markAndChaseWinding(start, end, winding, oppWinding); 3227 } 3228 3229 Span* markAngle(int maxWinding, int sumWinding, bool activeAngle, const Angle* angle) { 3230 SkASSERT(angle->segment() == this); 3231 if (useInnerWinding(maxWinding, sumWinding)) { 3232 maxWinding = sumWinding; 3233 } 3234 Span* last; 3235 if (activeAngle) { 3236 last = markAndChaseWinding(angle, maxWinding); 3237 } else { 3238 last = markAndChaseDoneUnary(angle, maxWinding); 3239 } 3240 return last; 3241 } 3242 3243 Span* markAngle(int maxWinding, int sumWinding, int oppMaxWinding, int oppSumWinding, 3244 bool activeAngle, const Angle* angle) { 3245 SkASSERT(angle->segment() == this); 3246 if (useInnerWinding(maxWinding, sumWinding)) { 3247 maxWinding = sumWinding; 3248 } 3249 if (oppMaxWinding != oppSumWinding && useInnerWinding(oppMaxWinding, oppSumWinding)) { 3250 oppMaxWinding = oppSumWinding; 3251 } 3252 Span* last; 3253 if (activeAngle) { 3254 last = markAndChaseWinding(angle, maxWinding, oppMaxWinding); 3255 } else { 3256 last = markAndChaseDoneBinary(angle, maxWinding, oppMaxWinding); 3257 } 3258 return last; 3259 } 3260 3261 // FIXME: this should also mark spans with equal (x,y) 3262 // This may be called when the segment is already marked done. While this 3263 // wastes time, it shouldn't do any more than spin through the T spans. 3264 // OPTIMIZATION: abort on first done found (assuming that this code is 3265 // always called to mark segments done). 3266 void markDone(int index, int winding) { 3267 // SkASSERT(!done()); 3268 SkASSERT(winding); 3269 double referenceT = fTs[index].fT; 3270 int lesser = index; 3271 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 3272 markOneDone(__FUNCTION__, lesser, winding); 3273 } 3274 do { 3275 markOneDone(__FUNCTION__, index, winding); 3276 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT)); 3277 } 3278 3279 void markDoneBinary(int index, int winding, int oppWinding) { 3280 // SkASSERT(!done()); 3281 SkASSERT(winding || oppWinding); 3282 double referenceT = fTs[index].fT; 3283 int lesser = index; 3284 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 3285 markOneDoneBinary(__FUNCTION__, lesser, winding, oppWinding); 3286 } 3287 do { 3288 markOneDoneBinary(__FUNCTION__, index, winding, oppWinding); 3289 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT)); 3290 } 3291 3292 void markDoneBinary(int index) { 3293 double referenceT = fTs[index].fT; 3294 int lesser = index; 3295 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 3296 markOneDoneBinary(__FUNCTION__, lesser); 3297 } 3298 do { 3299 markOneDoneBinary(__FUNCTION__, index); 3300 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT)); 3301 } 3302 3303 void markDoneUnary(int index, int winding) { 3304 // SkASSERT(!done()); 3305 SkASSERT(winding); 3306 double referenceT = fTs[index].fT; 3307 int lesser = index; 3308 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 3309 markOneDoneUnary(__FUNCTION__, lesser, winding); 3310 } 3311 do { 3312 markOneDoneUnary(__FUNCTION__, index, winding); 3313 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT)); 3314 } 3315 3316 void markDoneUnary(int index) { 3317 double referenceT = fTs[index].fT; 3318 int lesser = index; 3319 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 3320 markOneDoneUnary(__FUNCTION__, lesser); 3321 } 3322 do { 3323 markOneDoneUnary(__FUNCTION__, index); 3324 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT)); 3325 } 3326 3327 void markOneDone(const char* funName, int tIndex, int winding) { 3328 Span* span = markOneWinding(funName, tIndex, winding); 3329 if (!span) { 3330 return; 3331 } 3332 span->fDone = true; 3333 fDoneSpans++; 3334 } 3335 3336 void markOneDoneBinary(const char* funName, int tIndex) { 3337 Span* span = verifyOneWinding(funName, tIndex); 3338 if (!span) { 3339 return; 3340 } 3341 span->fDone = true; 3342 fDoneSpans++; 3343 } 3344 3345 void markOneDoneBinary(const char* funName, int tIndex, int winding, int oppWinding) { 3346 Span* span = markOneWinding(funName, tIndex, winding, oppWinding); 3347 if (!span) { 3348 return; 3349 } 3350 span->fDone = true; 3351 fDoneSpans++; 3352 } 3353 3354 void markOneDoneUnary(const char* funName, int tIndex) { 3355 Span* span = verifyOneWindingU(funName, tIndex); 3356 if (!span) { 3357 return; 3358 } 3359 span->fDone = true; 3360 fDoneSpans++; 3361 } 3362 3363 void markOneDoneUnary(const char* funName, int tIndex, int winding) { 3364 Span* span = markOneWinding(funName, tIndex, winding); 3365 if (!span) { 3366 return; 3367 } 3368 span->fDone = true; 3369 fDoneSpans++; 3370 } 3371 3372 Span* markOneWinding(const char* funName, int tIndex, int winding) { 3373 Span& span = fTs[tIndex]; 3374 if (span.fDone) { 3375 return NULL; 3376 } 3377 #if DEBUG_MARK_DONE 3378 debugShowNewWinding(funName, span, winding); 3379 #endif 3380 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); 3381 #ifdef SK_DEBUG 3382 SkASSERT(abs(winding) <= gDebugMaxWindSum); 3383 #endif 3384 span.fWindSum = winding; 3385 return &span; 3386 } 3387 3388 Span* markOneWinding(const char* funName, int tIndex, int winding, int oppWinding) { 3389 Span& span = fTs[tIndex]; 3390 if (span.fDone) { 3391 return NULL; 3392 } 3393 #if DEBUG_MARK_DONE 3394 debugShowNewWinding(funName, span, winding, oppWinding); 3395 #endif 3396 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); 3397 #ifdef SK_DEBUG 3398 SkASSERT(abs(winding) <= gDebugMaxWindSum); 3399 #endif 3400 span.fWindSum = winding; 3401 SkASSERT(span.fOppSum == SK_MinS32 || span.fOppSum == oppWinding); 3402 #ifdef SK_DEBUG 3403 SkASSERT(abs(oppWinding) <= gDebugMaxWindSum); 3404 #endif 3405 span.fOppSum = oppWinding; 3406 return &span; 3407 } 3408 3409 bool bumpsUp(int tStart, int tEnd) const { 3410 SkPoint edge[4]; 3411 subDivide(tStart, tEnd, edge); 3412 switch (fVerb) { 3413 case SkPath::kLine_Verb: 3414 SkASSERT(0); // shouldn't call in for lines 3415 return true; 3416 case SkPath::kQuad_Verb: 3417 return approximately_greater(edge[0].fY, edge[1].fY) 3418 && approximately_lesser(edge[1].fY, edge[2].fY); 3419 case SkPath::kCubic_Verb: 3420 return (approximately_greater(edge[0].fY, edge[1].fY) 3421 && approximately_lesser(edge[1].fY, edge[3].fY)) 3422 || (approximately_greater(edge[0].fY, edge[2].fY) 3423 && approximately_lesser(edge[2].fY, edge[3].fY)); 3424 default: 3425 SkASSERT(0); 3426 return false; 3427 } 3428 } 3429 3430 Span* verifyOneWinding(const char* funName, int tIndex) { 3431 Span& span = fTs[tIndex]; 3432 if (span.fDone) { 3433 return NULL; 3434 } 3435 #if DEBUG_MARK_DONE 3436 debugShowNewWinding(funName, span, span.fWindSum, span.fOppSum); 3437 #endif 3438 SkASSERT(span.fWindSum != SK_MinS32); 3439 SkASSERT(span.fOppSum != SK_MinS32); 3440 return &span; 3441 } 3442 3443 Span* verifyOneWindingU(const char* funName, int tIndex) { 3444 Span& span = fTs[tIndex]; 3445 if (span.fDone) { 3446 return NULL; 3447 } 3448 #if DEBUG_MARK_DONE 3449 debugShowNewWinding(funName, span, span.fWindSum); 3450 #endif 3451 SkASSERT(span.fWindSum != SK_MinS32); 3452 return &span; 3453 } 3454 3455 // note that just because a span has one end that is unsortable, that's 3456 // not enough to mark it done. The other end may be sortable, allowing the 3457 // span to be added. 3458 // FIXME: if abs(start - end) > 1, mark intermediates as unsortable on both ends 3459 void markUnsortable(int start, int end) { 3460 Span* span = &fTs[start]; 3461 if (start < end) { 3462#if DEBUG_UNSORTABLE 3463 SkDebugf("%s start id=%d [%d] (%1.9g,%1.9g)\n", __FUNCTION__, fID, start, 3464 xAtT(start), yAtT(start)); 3465#endif 3466 span->fUnsortableStart = true; 3467 } else { 3468 --span; 3469#if DEBUG_UNSORTABLE 3470 SkDebugf("%s end id=%d [%d] (%1.9g,%1.9g) next:(%1.9g,%1.9g)\n", __FUNCTION__, fID, 3471 start - 1, xAtT(start - 1), yAtT(start - 1), xAtT(start), yAtT(start)); 3472#endif 3473 span->fUnsortableEnd = true; 3474 } 3475 if (!span->fUnsortableStart || !span->fUnsortableEnd || span->fDone) { 3476 return; 3477 } 3478 span->fDone = true; 3479 fDoneSpans++; 3480 } 3481 3482 void markWinding(int index, int winding) { 3483 // SkASSERT(!done()); 3484 SkASSERT(winding); 3485 double referenceT = fTs[index].fT; 3486 int lesser = index; 3487 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 3488 markOneWinding(__FUNCTION__, lesser, winding); 3489 } 3490 do { 3491 markOneWinding(__FUNCTION__, index, winding); 3492 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT)); 3493 } 3494 3495 void markWinding(int index, int winding, int oppWinding) { 3496 // SkASSERT(!done()); 3497 SkASSERT(winding || oppWinding); 3498 double referenceT = fTs[index].fT; 3499 int lesser = index; 3500 while (--lesser >= 0 && precisely_negative(referenceT - fTs[lesser].fT)) { 3501 markOneWinding(__FUNCTION__, lesser, winding, oppWinding); 3502 } 3503 do { 3504 markOneWinding(__FUNCTION__, index, winding, oppWinding); 3505 } while (++index < fTs.count() && precisely_negative(fTs[index].fT - referenceT)); 3506 } 3507 3508 void matchWindingValue(int tIndex, double t, bool borrowWind) { 3509 int nextDoorWind = SK_MaxS32; 3510 int nextOppWind = SK_MaxS32; 3511 if (tIndex > 0) { 3512 const Span& below = fTs[tIndex - 1]; 3513 if (approximately_negative(t - below.fT)) { 3514 nextDoorWind = below.fWindValue; 3515 nextOppWind = below.fOppValue; 3516 } 3517 } 3518 if (nextDoorWind == SK_MaxS32 && tIndex + 1 < fTs.count()) { 3519 const Span& above = fTs[tIndex + 1]; 3520 if (approximately_negative(above.fT - t)) { 3521 nextDoorWind = above.fWindValue; 3522 nextOppWind = above.fOppValue; 3523 } 3524 } 3525 if (nextDoorWind == SK_MaxS32 && borrowWind && tIndex > 0 && t < 1) { 3526 const Span& below = fTs[tIndex - 1]; 3527 nextDoorWind = below.fWindValue; 3528 nextOppWind = below.fOppValue; 3529 } 3530 if (nextDoorWind != SK_MaxS32) { 3531 Span& newSpan = fTs[tIndex]; 3532 newSpan.fWindValue = nextDoorWind; 3533 newSpan.fOppValue = nextOppWind; 3534 if (!nextDoorWind && !nextOppWind && !newSpan.fDone) { 3535 newSpan.fDone = true; 3536 ++fDoneSpans; 3537 } 3538 } 3539 } 3540 3541 bool moreHorizontal(int index, int endIndex, bool& unsortable) const { 3542 // find bounds 3543 Bounds bounds; 3544 bounds.setPoint(xyAtT(index)); 3545 bounds.add(xyAtT(endIndex)); 3546 SkScalar width = bounds.width(); 3547 SkScalar height = bounds.height(); 3548 if (width > height) { 3549 if (approximately_negative(width)) { 3550 unsortable = true; // edge is too small to resolve meaningfully 3551 } 3552 return false; 3553 } else { 3554 if (approximately_negative(height)) { 3555 unsortable = true; // edge is too small to resolve meaningfully 3556 } 3557 return true; 3558 } 3559 } 3560 3561 // return span if when chasing, two or more radiating spans are not done 3562 // OPTIMIZATION: ? multiple spans is detected when there is only one valid 3563 // candidate and the remaining spans have windValue == 0 (canceled by 3564 // coincidence). The coincident edges could either be removed altogether, 3565 // or this code could be more complicated in detecting this case. Worth it? 3566 bool multipleSpans(int end) const { 3567 return end > 0 && end < fTs.count() - 1; 3568 } 3569 3570 bool nextCandidate(int& start, int& end) const { 3571 while (fTs[end].fDone) { 3572 if (fTs[end].fT == 1) { 3573 return false; 3574 } 3575 ++end; 3576 } 3577 start = end; 3578 end = nextExactSpan(start, 1); 3579 return true; 3580 } 3581 3582 Segment* nextChase(int& index, const int step, int& min, Span*& last) const { 3583 int end = nextExactSpan(index, step); 3584 SkASSERT(end >= 0); 3585 if (multipleSpans(end)) { 3586 last = &fTs[end]; 3587 return NULL; 3588 } 3589 const Span& endSpan = fTs[end]; 3590 Segment* other = endSpan.fOther; 3591 index = endSpan.fOtherIndex; 3592 SkASSERT(index >= 0); 3593 int otherEnd = other->nextExactSpan(index, step); 3594 SkASSERT(otherEnd >= 0); 3595 min = SkMin32(index, otherEnd); 3596 return other; 3597 } 3598 3599 // This has callers for two different situations: one establishes the end 3600 // of the current span, and one establishes the beginning of the next span 3601 // (thus the name). When this is looking for the end of the current span, 3602 // coincidence is found when the beginning Ts contain -step and the end 3603 // contains step. When it is looking for the beginning of the next, the 3604 // first Ts found can be ignored and the last Ts should contain -step. 3605 // OPTIMIZATION: probably should split into two functions 3606 int nextSpan(int from, int step) const { 3607 const Span& fromSpan = fTs[from]; 3608 int count = fTs.count(); 3609 int to = from; 3610 while (step > 0 ? ++to < count : --to >= 0) { 3611 const Span& span = fTs[to]; 3612 if (approximately_zero(span.fT - fromSpan.fT)) { 3613 continue; 3614 } 3615 return to; 3616 } 3617 return -1; 3618 } 3619 3620 // FIXME 3621 // this returns at any difference in T, vs. a preset minimum. It may be 3622 // that all callers to nextSpan should use this instead. 3623 // OPTIMIZATION splitting this into separate loops for up/down steps 3624 // would allow using precisely_negative instead of precisely_zero 3625 int nextExactSpan(int from, int step) const { 3626 const Span& fromSpan = fTs[from]; 3627 int count = fTs.count(); 3628 int to = from; 3629 while (step > 0 ? ++to < count : --to >= 0) { 3630 const Span& span = fTs[to]; 3631 if (precisely_zero(span.fT - fromSpan.fT)) { 3632 continue; 3633 } 3634 return to; 3635 } 3636 return -1; 3637 } 3638 3639 bool operand() const { 3640 return fOperand; 3641 } 3642 3643 int oppSign(const Angle* angle) const { 3644 SkASSERT(angle->segment() == this); 3645 return oppSign(angle->start(), angle->end()); 3646 } 3647 3648 int oppSign(int startIndex, int endIndex) const { 3649 int result = startIndex < endIndex ? -fTs[startIndex].fOppValue 3650 : fTs[endIndex].fOppValue; 3651#if DEBUG_WIND_BUMP 3652 SkDebugf("%s oppSign=%d\n", __FUNCTION__, result); 3653#endif 3654 return result; 3655 } 3656 3657 int oppSum(int tIndex) const { 3658 return fTs[tIndex].fOppSum; 3659 } 3660 3661 int oppSum(const Angle* angle) const { 3662 int lesser = SkMin32(angle->start(), angle->end()); 3663 return fTs[lesser].fOppSum; 3664 } 3665 3666 int oppValue(int tIndex) const { 3667 return fTs[tIndex].fOppValue; 3668 } 3669 3670 int oppValue(const Angle* angle) const { 3671 int lesser = SkMin32(angle->start(), angle->end()); 3672 return fTs[lesser].fOppValue; 3673 } 3674 3675 const SkPoint* pts() const { 3676 return fPts; 3677 } 3678 3679 void reset() { 3680 init(NULL, (SkPath::Verb) -1, false, false); 3681 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax); 3682 fTs.reset(); 3683 } 3684 3685 void setOppXor(bool isOppXor) { 3686 fOppXor = isOppXor; 3687 } 3688 3689 void setSpanT(int index, double t) { 3690 Span& span = fTs[index]; 3691 span.fT = t; 3692 span.fOther->fTs[span.fOtherIndex].fOtherT = t; 3693 } 3694 3695 void setUpWinding(int index, int endIndex, int& maxWinding, int& sumWinding) { 3696 int deltaSum = spanSign(index, endIndex); 3697 maxWinding = sumWinding; 3698 sumWinding = sumWinding -= deltaSum; 3699 } 3700 3701 void setUpWindings(int index, int endIndex, int& sumMiWinding, int& sumSuWinding, 3702 int& maxWinding, int& sumWinding, int& oppMaxWinding, int& oppSumWinding) { 3703 int deltaSum = spanSign(index, endIndex); 3704 int oppDeltaSum = oppSign(index, endIndex); 3705 if (operand()) { 3706 maxWinding = sumSuWinding; 3707 sumWinding = sumSuWinding -= deltaSum; 3708 oppMaxWinding = sumMiWinding; 3709 oppSumWinding = sumMiWinding -= oppDeltaSum; 3710 } else { 3711 maxWinding = sumMiWinding; 3712 sumWinding = sumMiWinding -= deltaSum; 3713 oppMaxWinding = sumSuWinding; 3714 oppSumWinding = sumSuWinding -= oppDeltaSum; 3715 } 3716 } 3717 3718 // This marks all spans unsortable so that this info is available for early 3719 // exclusion in find top and others. This could be optimized to only mark 3720 // adjacent spans that unsortable. However, this makes it difficult to later 3721 // determine starting points for edge detection in find top and the like. 3722 static bool SortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) { 3723 bool sortable = true; 3724 int angleCount = angles.count(); 3725 int angleIndex; 3726 angleList.setReserve(angleCount); 3727 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { 3728 Angle& angle = angles[angleIndex]; 3729 *angleList.append() = ∠ 3730 sortable &= !angle.unsortable(); 3731 } 3732 if (sortable) { 3733 QSort<Angle>(angleList.begin(), angleList.end() - 1); 3734 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { 3735 if (angles[angleIndex].unsortable()) { 3736 sortable = false; 3737 break; 3738 } 3739 } 3740 } 3741 if (!sortable) { 3742 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { 3743 Angle& angle = angles[angleIndex]; 3744 angle.segment()->markUnsortable(angle.start(), angle.end()); 3745 } 3746 } 3747 return sortable; 3748 } 3749 3750 // OPTIMIZATION: mark as debugging only if used solely by tests 3751 const Span& span(int tIndex) const { 3752 return fTs[tIndex]; 3753 } 3754 3755 int spanSign(const Angle* angle) const { 3756 SkASSERT(angle->segment() == this); 3757 return spanSign(angle->start(), angle->end()); 3758 } 3759 3760 int spanSign(int startIndex, int endIndex) const { 3761 int result = startIndex < endIndex ? -fTs[startIndex].fWindValue 3762 : fTs[endIndex].fWindValue; 3763#if DEBUG_WIND_BUMP 3764 SkDebugf("%s spanSign=%d\n", __FUNCTION__, result); 3765#endif 3766 return result; 3767 } 3768 3769 void subDivide(int start, int end, SkPoint edge[4]) const { 3770 edge[0] = fTs[start].fPt; 3771 edge[fVerb] = fTs[end].fPt; 3772 if (fVerb == SkPath::kQuad_Verb || fVerb == SkPath::kCubic_Verb) { 3773 _Point sub[2] = {{ edge[0].fX, edge[0].fY}, {edge[fVerb].fX, edge[fVerb].fY }}; 3774 if (fVerb == SkPath::kQuad_Verb) { 3775 MAKE_CONST_QUAD(aQuad, fPts); 3776 edge[1] = sub_divide(aQuad, sub[0], sub[1], fTs[start].fT, fTs[end].fT).asSkPoint(); 3777 } else { 3778 MAKE_CONST_CUBIC(aCubic, fPts); 3779 sub_divide(aCubic, sub[0], sub[1], fTs[start].fT, fTs[end].fT, sub); 3780 edge[1] = sub[0].asSkPoint(); 3781 edge[2] = sub[1].asSkPoint(); 3782 } 3783 } 3784 } 3785 3786 // OPTIMIZATION: mark as debugging only if used solely by tests 3787 double t(int tIndex) const { 3788 return fTs[tIndex].fT; 3789 } 3790 3791 double tAtMid(int start, int end, double mid) const { 3792 return fTs[start].fT * (1 - mid) + fTs[end].fT * mid; 3793 } 3794 3795 bool tiny(const Angle* angle) const { 3796 int start = angle->start(); 3797 int end = angle->end(); 3798 const Span& mSpan = fTs[SkMin32(start, end)]; 3799 return mSpan.fTiny; 3800 } 3801 3802 static void TrackOutside(SkTDArray<double>& outsideTs, double end, 3803 double start) { 3804 int outCount = outsideTs.count(); 3805 if (outCount == 0 || !approximately_negative(end - outsideTs[outCount - 2])) { 3806 *outsideTs.append() = end; 3807 *outsideTs.append() = start; 3808 } 3809 } 3810 3811 void undoneSpan(int& start, int& end) { 3812 size_t tCount = fTs.count(); 3813 size_t index; 3814 for (index = 0; index < tCount; ++index) { 3815 if (!fTs[index].fDone) { 3816 break; 3817 } 3818 } 3819 SkASSERT(index < tCount - 1); 3820 start = index; 3821 double startT = fTs[index].fT; 3822 while (approximately_negative(fTs[++index].fT - startT)) 3823 SkASSERT(index < tCount); 3824 SkASSERT(index < tCount); 3825 end = index; 3826 } 3827 3828 bool unsortable(int index) const { 3829 return fTs[index].fUnsortableStart || fTs[index].fUnsortableEnd; 3830 } 3831 3832 void updatePts(const SkPoint pts[]) { 3833 fPts = pts; 3834 } 3835 3836 int updateOppWinding(int index, int endIndex) const { 3837 int lesser = SkMin32(index, endIndex); 3838 int oppWinding = oppSum(lesser); 3839 int oppSpanWinding = oppSign(index, endIndex); 3840 if (oppSpanWinding && useInnerWinding(oppWinding - oppSpanWinding, oppWinding) 3841 && oppWinding != SK_MaxS32) { 3842 oppWinding -= oppSpanWinding; 3843 } 3844 return oppWinding; 3845 } 3846 3847 int updateOppWinding(const Angle* angle) const { 3848 int startIndex = angle->start(); 3849 int endIndex = angle->end(); 3850 return updateOppWinding(endIndex, startIndex); 3851 } 3852 3853 int updateOppWindingReverse(const Angle* angle) const { 3854 int startIndex = angle->start(); 3855 int endIndex = angle->end(); 3856 return updateOppWinding(startIndex, endIndex); 3857 } 3858 3859 int updateWinding(int index, int endIndex) const { 3860 int lesser = SkMin32(index, endIndex); 3861 int winding = windSum(lesser); 3862 int spanWinding = spanSign(index, endIndex); 3863 if (winding && useInnerWinding(winding - spanWinding, winding) && winding != SK_MaxS32) { 3864 winding -= spanWinding; 3865 } 3866 return winding; 3867 } 3868 3869 int updateWinding(const Angle* angle) const { 3870 int startIndex = angle->start(); 3871 int endIndex = angle->end(); 3872 return updateWinding(endIndex, startIndex); 3873 } 3874 3875 int updateWindingReverse(const Angle* angle) const { 3876 int startIndex = angle->start(); 3877 int endIndex = angle->end(); 3878 return updateWinding(startIndex, endIndex); 3879 } 3880 3881 SkPath::Verb verb() const { 3882 return fVerb; 3883 } 3884 3885 int windingAtT(double tHit, int tIndex, bool crossOpp, SkScalar& dx) const { 3886 if (approximately_zero(tHit - t(tIndex))) { // if we hit the end of a span, disregard 3887 return SK_MinS32; 3888 } 3889 int winding = crossOpp ? oppSum(tIndex) : windSum(tIndex); 3890 SkASSERT(winding != SK_MinS32); 3891 int windVal = crossOpp ? oppValue(tIndex) : windValue(tIndex); 3892 #if DEBUG_WINDING_AT_T 3893 SkDebugf("%s oldWinding=%d windValue=%d", __FUNCTION__, winding, windVal); 3894 #endif 3895 // see if a + change in T results in a +/- change in X (compute x'(T)) 3896 dx = (*SegmentDXAtT[fVerb])(fPts, tHit); 3897 if (fVerb > SkPath::kLine_Verb && approximately_zero(dx)) { 3898 dx = fPts[2].fX - fPts[1].fX - dx; 3899 } 3900 if (dx == 0) { 3901 #if DEBUG_WINDING_AT_T 3902 SkDebugf(" dx=0 winding=SK_MinS32\n"); 3903 #endif 3904 return SK_MinS32; 3905 } 3906 if (winding * dx > 0) { // if same signs, result is negative 3907 winding += dx > 0 ? -windVal : windVal; 3908 } 3909 #if DEBUG_WINDING_AT_T 3910 SkDebugf(" dx=%c winding=%d\n", dx > 0 ? '+' : '-', winding); 3911 #endif 3912 return winding; 3913 } 3914 3915 int windSum(int tIndex) const { 3916 return fTs[tIndex].fWindSum; 3917 } 3918 3919 int windSum(const Angle* angle) const { 3920 int start = angle->start(); 3921 int end = angle->end(); 3922 int index = SkMin32(start, end); 3923 return windSum(index); 3924 } 3925 3926 int windValue(int tIndex) const { 3927 return fTs[tIndex].fWindValue; 3928 } 3929 3930 int windValue(const Angle* angle) const { 3931 int start = angle->start(); 3932 int end = angle->end(); 3933 int index = SkMin32(start, end); 3934 return windValue(index); 3935 } 3936 3937 int windValueAt(double t) const { 3938 int count = fTs.count(); 3939 for (int index = 0; index < count; ++index) { 3940 if (fTs[index].fT == t) { 3941 return fTs[index].fWindValue; 3942 } 3943 } 3944 SkASSERT(0); 3945 return 0; 3946 } 3947 3948 SkScalar xAtT(int index) const { 3949 return xAtT(&fTs[index]); 3950 } 3951 3952 SkScalar xAtT(const Span* span) const { 3953 return xyAtT(span).fX; 3954 } 3955 3956 const SkPoint& xyAtT(int index) const { 3957 return xyAtT(&fTs[index]); 3958 } 3959 3960 const SkPoint& xyAtT(const Span* span) const { 3961 if (SkScalarIsNaN(span->fPt.fX)) { 3962 SkASSERT(0); // make sure this path is never used 3963 if (span->fT == 0) { 3964 span->fPt = fPts[0]; 3965 } else if (span->fT == 1) { 3966 span->fPt = fPts[fVerb]; 3967 } else { 3968 (*SegmentXYAtT[fVerb])(fPts, span->fT, &span->fPt); 3969 } 3970 } 3971 return span->fPt; 3972 } 3973 3974 // used only by right angle winding finding 3975 void xyAtT(double mid, SkPoint& pt) const { 3976 (*SegmentXYAtT[fVerb])(fPts, mid, &pt); 3977 } 3978 3979 SkScalar yAtT(int index) const { 3980 return yAtT(&fTs[index]); 3981 } 3982 3983 SkScalar yAtT(const Span* span) const { 3984 return xyAtT(span).fY; 3985 } 3986 3987 void zeroCoincidentOpp(Span* oTest, int index) { 3988 Span* const test = &fTs[index]; 3989 Span* end = test; 3990 do { 3991 end->fOppValue = 0; 3992 end = &fTs[++index]; 3993 } while (approximately_negative(end->fT - test->fT)); 3994 } 3995 3996 void zeroCoincidentOther(Span* test, const double tRatio, const double oEndT, int oIndex) { 3997 Span* const oTest = &fTs[oIndex]; 3998 Span* oEnd = oTest; 3999 const double startT = test->fT; 4000 const double oStartT = oTest->fT; 4001 double otherTMatch = (test->fT - startT) * tRatio + oStartT; 4002 while (!approximately_negative(oEndT - oEnd->fT) 4003 && approximately_negative(oEnd->fT - otherTMatch)) { 4004 oEnd->fOppValue = 0; 4005 oEnd = &fTs[++oIndex]; 4006 } 4007 } 4008 4009 void zeroSpan(Span* span) { 4010 SkASSERT(span->fWindValue > 0 || span->fOppValue > 0); 4011 span->fWindValue = 0; 4012 span->fOppValue = 0; 4013 SkASSERT(!span->fDone); 4014 span->fDone = true; 4015 ++fDoneSpans; 4016 } 4017 4018#if DEBUG_DUMP 4019 void dump() const { 4020 const char className[] = "Segment"; 4021 const int tab = 4; 4022 for (int i = 0; i < fTs.count(); ++i) { 4023 SkPoint out; 4024 (*SegmentXYAtT[fVerb])(fPts, t(i), &out); 4025 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d" 4026 " otherT=%1.9g windSum=%d\n", 4027 tab + sizeof(className), className, fID, 4028 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY, 4029 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum); 4030 } 4031 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)", 4032 tab + sizeof(className), className, fID, 4033 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom); 4034 } 4035#endif 4036 4037#if DEBUG_CONCIDENT 4038 // SkASSERT if pair has not already been added 4039 void debugAddTPair(double t, const Segment& other, double otherT) const { 4040 for (int i = 0; i < fTs.count(); ++i) { 4041 if (fTs[i].fT == t && fTs[i].fOther == &other && fTs[i].fOtherT == otherT) { 4042 return; 4043 } 4044 } 4045 SkASSERT(0); 4046 } 4047#endif 4048 4049#if DEBUG_DUMP 4050 int debugID() const { 4051 return fID; 4052 } 4053#endif 4054 4055#if DEBUG_WINDING 4056 void debugShowSums() const { 4057 SkDebugf("%s id=%d (%1.9g,%1.9g %1.9g,%1.9g)", __FUNCTION__, fID, 4058 fPts[0].fX, fPts[0].fY, fPts[fVerb].fX, fPts[fVerb].fY); 4059 for (int i = 0; i < fTs.count(); ++i) { 4060 const Span& span = fTs[i]; 4061 SkDebugf(" [t=%1.3g %1.9g,%1.9g w=", span.fT, xAtT(&span), yAtT(&span)); 4062 if (span.fWindSum == SK_MinS32) { 4063 SkDebugf("?"); 4064 } else { 4065 SkDebugf("%d", span.fWindSum); 4066 } 4067 SkDebugf("]"); 4068 } 4069 SkDebugf("\n"); 4070 } 4071#endif 4072 4073#if DEBUG_CONCIDENT 4074 void debugShowTs() const { 4075 SkDebugf("%s id=%d", __FUNCTION__, fID); 4076 int lastWind = -1; 4077 int lastOpp = -1; 4078 double lastT = -1; 4079 int i; 4080 for (i = 0; i < fTs.count(); ++i) { 4081 bool change = lastT != fTs[i].fT || lastWind != fTs[i].fWindValue 4082 || lastOpp != fTs[i].fOppValue; 4083 if (change && lastWind >= 0) { 4084 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]", 4085 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp); 4086 } 4087 if (change) { 4088 SkDebugf(" [o=%d", fTs[i].fOther->fID); 4089 lastWind = fTs[i].fWindValue; 4090 lastOpp = fTs[i].fOppValue; 4091 lastT = fTs[i].fT; 4092 } else { 4093 SkDebugf(",%d", fTs[i].fOther->fID); 4094 } 4095 } 4096 if (i <= 0) { 4097 return; 4098 } 4099 SkDebugf(" t=%1.3g %1.9g,%1.9g w=%d o=%d]", 4100 lastT, xyAtT(i - 1).fX, xyAtT(i - 1).fY, lastWind, lastOpp); 4101 if (fOperand) { 4102 SkDebugf(" operand"); 4103 } 4104 if (done()) { 4105 SkDebugf(" done"); 4106 } 4107 SkDebugf("\n"); 4108 } 4109#endif 4110 4111#if DEBUG_ACTIVE_SPANS 4112 void debugShowActiveSpans() const { 4113 if (done()) { 4114 return; 4115 } 4116#if DEBUG_ACTIVE_SPANS_SHORT_FORM 4117 int lastId = -1; 4118 double lastT = -1; 4119#endif 4120 for (int i = 0; i < fTs.count(); ++i) { 4121 SkASSERT(&fTs[i] == &fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOther-> 4122 fTs[fTs[i].fOther->fTs[fTs[i].fOtherIndex].fOtherIndex]); 4123 if (fTs[i].fDone) { 4124 continue; 4125 } 4126#if DEBUG_ACTIVE_SPANS_SHORT_FORM 4127 if (lastId == fID && lastT == fTs[i].fT) { 4128 continue; 4129 } 4130 lastId = fID; 4131 lastT = fTs[i].fT; 4132#endif 4133 SkDebugf("%s id=%d", __FUNCTION__, fID); 4134 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); 4135 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) { 4136 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); 4137 } 4138 const Span* span = &fTs[i]; 4139 SkDebugf(") t=%1.9g (%1.9g,%1.9g)", fTs[i].fT, 4140 xAtT(span), yAtT(span)); 4141 int iEnd = i + 1; 4142 while (fTs[iEnd].fT < 1 && approximately_equal(fTs[i].fT, fTs[iEnd].fT)) { 4143 ++iEnd; 4144 } 4145 SkDebugf(" tEnd=%1.9g", fTs[iEnd].fT); 4146 const Segment* other = fTs[i].fOther; 4147 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d windSum=", 4148 other->fID, fTs[i].fOtherT, fTs[i].fOtherIndex); 4149 if (fTs[i].fWindSum == SK_MinS32) { 4150 SkDebugf("?"); 4151 } else { 4152 SkDebugf("%d", fTs[i].fWindSum); 4153 } 4154 SkDebugf(" windValue=%d oppValue=%d\n", fTs[i].fWindValue, fTs[i].fOppValue); 4155 } 4156 } 4157 4158 // This isn't useful yet -- but leaving it in for now in case i think of something 4159 // to use it for 4160 void validateActiveSpans() const { 4161 if (done()) { 4162 return; 4163 } 4164 int tCount = fTs.count(); 4165 for (int index = 0; index < tCount; ++index) { 4166 if (fTs[index].fDone) { 4167 continue; 4168 } 4169 // count number of connections which are not done 4170 int first = index; 4171 double baseT = fTs[index].fT; 4172 while (first > 0 && approximately_equal(fTs[first - 1].fT, baseT)) { 4173 --first; 4174 } 4175 int last = index; 4176 while (last < tCount - 1 && approximately_equal(fTs[last + 1].fT, baseT)) { 4177 ++last; 4178 } 4179 int connections = 0; 4180 connections += first > 0 && !fTs[first - 1].fDone; 4181 for (int test = first; test <= last; ++test) { 4182 connections += !fTs[test].fDone; 4183 const Segment* other = fTs[test].fOther; 4184 int oIndex = fTs[test].fOtherIndex; 4185 connections += !other->fTs[oIndex].fDone; 4186 connections += oIndex > 0 && !other->fTs[oIndex - 1].fDone; 4187 } 4188 // SkASSERT(!(connections & 1)); 4189 } 4190 } 4191#endif 4192 4193#if DEBUG_MARK_DONE 4194 void debugShowNewWinding(const char* fun, const Span& span, int winding) { 4195 const SkPoint& pt = xyAtT(&span); 4196 SkDebugf("%s id=%d", fun, fID); 4197 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); 4198 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) { 4199 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); 4200 } 4201 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther-> 4202 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]); 4203 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d windSum=", 4204 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, winding); 4205 if (span.fWindSum == SK_MinS32) { 4206 SkDebugf("?"); 4207 } else { 4208 SkDebugf("%d", span.fWindSum); 4209 } 4210 SkDebugf(" windValue=%d\n", span.fWindValue); 4211 } 4212 4213 void debugShowNewWinding(const char* fun, const Span& span, int winding, int oppWinding) { 4214 const SkPoint& pt = xyAtT(&span); 4215 SkDebugf("%s id=%d", fun, fID); 4216 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); 4217 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) { 4218 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); 4219 } 4220 SkASSERT(&span == &span.fOther->fTs[span.fOtherIndex].fOther-> 4221 fTs[span.fOther->fTs[span.fOtherIndex].fOtherIndex]); 4222 SkDebugf(") t=%1.9g [%d] (%1.9g,%1.9g) newWindSum=%d newOppSum=%d oppSum=", 4223 span.fT, span.fOther->fTs[span.fOtherIndex].fOtherIndex, pt.fX, pt.fY, 4224 winding, oppWinding); 4225 if (span.fOppSum == SK_MinS32) { 4226 SkDebugf("?"); 4227 } else { 4228 SkDebugf("%d", span.fOppSum); 4229 } 4230 SkDebugf(" windSum="); 4231 if (span.fWindSum == SK_MinS32) { 4232 SkDebugf("?"); 4233 } else { 4234 SkDebugf("%d", span.fWindSum); 4235 } 4236 SkDebugf(" windValue=%d\n", span.fWindValue); 4237 } 4238#endif 4239 4240#if DEBUG_SORT 4241 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first, 4242 const int contourWinding, const int oppContourWinding) const { 4243 if (--gDebugSortCount < 0) { 4244 return; 4245 } 4246 SkASSERT(angles[first]->segment() == this); 4247 SkASSERT(angles.count() > 1); 4248 int lastSum = contourWinding; 4249 int oppLastSum = oppContourWinding; 4250 const Angle* firstAngle = angles[first]; 4251 int windSum = lastSum - spanSign(firstAngle); 4252 int oppoSign = oppSign(firstAngle); 4253 int oppWindSum = oppLastSum - oppoSign; 4254 #define WIND_AS_STRING(x) char x##Str[12]; if (!valid_wind(x)) strcpy(x##Str, "?"); \ 4255 else snprintf(x##Str, sizeof(x##Str), "%d", x) 4256 WIND_AS_STRING(contourWinding); 4257 WIND_AS_STRING(oppContourWinding); 4258 SkDebugf("%s %s contourWinding=%s oppContourWinding=%s sign=%d\n", fun, __FUNCTION__, 4259 contourWindingStr, oppContourWindingStr, spanSign(angles[first])); 4260 int index = first; 4261 bool firstTime = true; 4262 do { 4263 const Angle& angle = *angles[index]; 4264 const Segment& segment = *angle.segment(); 4265 int start = angle.start(); 4266 int end = angle.end(); 4267 const Span& sSpan = segment.fTs[start]; 4268 const Span& eSpan = segment.fTs[end]; 4269 const Span& mSpan = segment.fTs[SkMin32(start, end)]; 4270 bool opp = segment.fOperand ^ fOperand; 4271 if (!firstTime) { 4272 oppoSign = segment.oppSign(&angle); 4273 if (opp) { 4274 oppLastSum = oppWindSum; 4275 oppWindSum -= segment.spanSign(&angle); 4276 if (oppoSign) { 4277 lastSum = windSum; 4278 windSum -= oppoSign; 4279 } 4280 } else { 4281 lastSum = windSum; 4282 windSum -= segment.spanSign(&angle); 4283 if (oppoSign) { 4284 oppLastSum = oppWindSum; 4285 oppWindSum -= oppoSign; 4286 } 4287 } 4288 } 4289 SkDebugf("%s [%d] %sid=%d %s start=%d (%1.9g,%,1.9g) end=%d (%1.9g,%,1.9g)" 4290 " sign=%d windValue=%d windSum=", 4291 __FUNCTION__, index, angle.unsortable() ? "*** UNSORTABLE *** " : "", 4292 segment.fID, kLVerbStr[segment.fVerb], 4293 start, segment.xAtT(&sSpan), segment.yAtT(&sSpan), end, 4294 segment.xAtT(&eSpan), segment.yAtT(&eSpan), angle.sign(), 4295 mSpan.fWindValue); 4296 winding_printf(mSpan.fWindSum); 4297 int last, wind; 4298 if (opp) { 4299 last = oppLastSum; 4300 wind = oppWindSum; 4301 } else { 4302 last = lastSum; 4303 wind = windSum; 4304 } 4305 bool useInner = valid_wind(last) && valid_wind(wind) && useInnerWinding(last, wind); 4306 WIND_AS_STRING(last); 4307 WIND_AS_STRING(wind); 4308 WIND_AS_STRING(lastSum); 4309 WIND_AS_STRING(oppLastSum); 4310 WIND_AS_STRING(windSum); 4311 WIND_AS_STRING(oppWindSum); 4312 #undef WIND_AS_STRING 4313 if (!oppoSign) { 4314 SkDebugf(" %s->%s (max=%s)", lastStr, windStr, useInner ? windStr : lastStr); 4315 } else { 4316 SkDebugf(" %s->%s (%s->%s)", lastStr, windStr, opp ? lastSumStr : oppLastSumStr, 4317 opp ? windSumStr : oppWindSumStr); 4318 } 4319 SkDebugf(" done=%d tiny=%d opp=%d\n", mSpan.fDone, mSpan.fTiny, opp); 4320#if false && DEBUG_ANGLE 4321 angle.debugShow(segment.xyAtT(&sSpan)); 4322#endif 4323 ++index; 4324 if (index == angles.count()) { 4325 index = 0; 4326 } 4327 if (firstTime) { 4328 firstTime = false; 4329 } 4330 } while (index != first); 4331 } 4332 4333 void debugShowSort(const char* fun, const SkTDArray<Angle*>& angles, int first) { 4334 const Angle* firstAngle = angles[first]; 4335 const Segment* segment = firstAngle->segment(); 4336 int winding = segment->updateWinding(firstAngle); 4337 int oppWinding = segment->updateOppWinding(firstAngle); 4338 debugShowSort(fun, angles, first, winding, oppWinding); 4339 } 4340 4341#endif 4342 4343#if DEBUG_WINDING 4344 static char as_digit(int value) { 4345 return value < 0 ? '?' : value <= 9 ? '0' + value : '+'; 4346 } 4347#endif 4348 4349#if DEBUG_SHOW_WINDING 4350 int debugShowWindingValues(int slotCount, int ofInterest) const { 4351 if (!(1 << fID & ofInterest)) { 4352 return 0; 4353 } 4354 int sum = 0; 4355 SkTDArray<char> slots; 4356 slots.setCount(slotCount * 2); 4357 memset(slots.begin(), ' ', slotCount * 2); 4358 for (int i = 0; i < fTs.count(); ++i) { 4359 // if (!(1 << fTs[i].fOther->fID & ofInterest)) { 4360 // continue; 4361 // } 4362 sum += fTs[i].fWindValue; 4363 slots[fTs[i].fOther->fID - 1] = as_digit(fTs[i].fWindValue); 4364 sum += fTs[i].fOppValue; 4365 slots[slotCount + fTs[i].fOther->fID - 1] = as_digit(fTs[i].fOppValue); 4366 } 4367 SkDebugf("%s id=%2d %.*s | %.*s\n", __FUNCTION__, fID, slotCount, slots.begin(), slotCount, 4368 slots.begin() + slotCount); 4369 return sum; 4370 } 4371#endif 4372 4373private: 4374 const SkPoint* fPts; 4375 Bounds fBounds; 4376 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1) 4377 // OPTIMIZATION: could pack donespans, verb, operand, xor into 1 int-sized value 4378 int fDoneSpans; // quick check that segment is finished 4379 // OPTIMIZATION: force the following to be byte-sized 4380 SkPath::Verb fVerb; 4381 bool fOperand; 4382 bool fXor; // set if original contour had even-odd fill 4383 bool fOppXor; // set if opposite operand had even-odd fill 4384#if DEBUG_DUMP 4385 int fID; 4386#endif 4387}; 4388 4389class Contour; 4390 4391struct Coincidence { 4392 Contour* fContours[2]; 4393 int fSegments[2]; 4394 double fTs[2][2]; 4395 SkPoint fPts[2]; 4396}; 4397 4398class Contour { 4399public: 4400 Contour() { 4401 reset(); 4402#if DEBUG_DUMP 4403 fID = ++gContourID; 4404#endif 4405 } 4406 4407 bool operator<(const Contour& rh) const { 4408 return fBounds.fTop == rh.fBounds.fTop 4409 ? fBounds.fLeft < rh.fBounds.fLeft 4410 : fBounds.fTop < rh.fBounds.fTop; 4411 } 4412 4413 void addCoincident(int index, Contour* other, int otherIndex, 4414 const Intersections& ts, bool swap) { 4415 Coincidence& coincidence = *fCoincidences.append(); 4416 coincidence.fContours[0] = this; // FIXME: no need to store 4417 coincidence.fContours[1] = other; 4418 coincidence.fSegments[0] = index; 4419 coincidence.fSegments[1] = otherIndex; 4420 coincidence.fTs[swap][0] = ts.fT[0][0]; 4421 coincidence.fTs[swap][1] = ts.fT[0][1]; 4422 coincidence.fTs[!swap][0] = ts.fT[1][0]; 4423 coincidence.fTs[!swap][1] = ts.fT[1][1]; 4424 coincidence.fPts[0] = ts.fPt[0].asSkPoint(); 4425 coincidence.fPts[1] = ts.fPt[1].asSkPoint(); 4426 } 4427 4428 void addCross(const Contour* crosser) { 4429#ifdef DEBUG_CROSS 4430 for (int index = 0; index < fCrosses.count(); ++index) { 4431 SkASSERT(fCrosses[index] != crosser); 4432 } 4433#endif 4434 *fCrosses.append() = crosser; 4435 } 4436 4437 void addCubic(const SkPoint pts[4]) { 4438 fSegments.push_back().addCubic(pts, fOperand, fXor); 4439 fContainsCurves = fContainsCubics = true; 4440 } 4441 4442 int addLine(const SkPoint pts[2]) { 4443 fSegments.push_back().addLine(pts, fOperand, fXor); 4444 return fSegments.count(); 4445 } 4446 4447 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) { 4448 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex); 4449 } 4450 4451 int addQuad(const SkPoint pts[3]) { 4452 fSegments.push_back().addQuad(pts, fOperand, fXor); 4453 fContainsCurves = true; 4454 return fSegments.count(); 4455 } 4456 4457 int addT(int segIndex, Contour* other, int otherIndex, const SkPoint& pt, double& newT) { 4458 setContainsIntercepts(); 4459 return fSegments[segIndex].addT(&other->fSegments[otherIndex], pt, newT); 4460 } 4461 4462 int addSelfT(int segIndex, Contour* other, int otherIndex, const SkPoint& pt, double& newT) { 4463 setContainsIntercepts(); 4464 return fSegments[segIndex].addSelfT(&other->fSegments[otherIndex], pt, newT); 4465 } 4466 4467 int addUnsortableT(int segIndex, Contour* other, int otherIndex, bool start, 4468 const SkPoint& pt, double& newT) { 4469 return fSegments[segIndex].addUnsortableT(&other->fSegments[otherIndex], start, pt, newT); 4470 } 4471 4472 const Bounds& bounds() const { 4473 return fBounds; 4474 } 4475 4476 void complete() { 4477 setBounds(); 4478 fContainsIntercepts = false; 4479 } 4480 4481 bool containsCubics() const { 4482 return fContainsCubics; 4483 } 4484 4485 bool crosses(const Contour* crosser) const { 4486 for (int index = 0; index < fCrosses.count(); ++index) { 4487 if (fCrosses[index] == crosser) { 4488 return true; 4489 } 4490 } 4491 return false; 4492 } 4493 4494 bool done() const { 4495 return fDone; 4496 } 4497 4498 const SkPoint& end() const { 4499 const Segment& segment = fSegments.back(); 4500 return segment.pts()[segment.verb()]; 4501 } 4502 4503 void findTooCloseToCall() { 4504 int segmentCount = fSegments.count(); 4505 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { 4506 fSegments[sIndex].findTooCloseToCall(); 4507 } 4508 } 4509 4510 void fixOtherTIndex() { 4511 int segmentCount = fSegments.count(); 4512 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { 4513 fSegments[sIndex].fixOtherTIndex(); 4514 } 4515 } 4516 4517 Segment* nonVerticalSegment(int& start, int& end) { 4518 int segmentCount = fSortedSegments.count(); 4519 SkASSERT(segmentCount > 0); 4520 for (int sortedIndex = fFirstSorted; sortedIndex < segmentCount; ++sortedIndex) { 4521 Segment* testSegment = fSortedSegments[sortedIndex]; 4522 if (testSegment->done()) { 4523 continue; 4524 } 4525 start = end = 0; 4526 while (testSegment->nextCandidate(start, end)) { 4527 if (!testSegment->isVertical(start, end)) { 4528 return testSegment; 4529 } 4530 } 4531 } 4532 return NULL; 4533 } 4534 4535 bool operand() const { 4536 return fOperand; 4537 } 4538 4539 void reset() { 4540 fSegments.reset(); 4541 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax); 4542 fContainsCurves = fContainsCubics = fContainsIntercepts = fDone = false; 4543 } 4544 4545 void resolveCoincidence(SkTDArray<Contour*>& contourList) { 4546 int count = fCoincidences.count(); 4547 for (int index = 0; index < count; ++index) { 4548 Coincidence& coincidence = fCoincidences[index]; 4549 SkASSERT(coincidence.fContours[0] == this); 4550 int thisIndex = coincidence.fSegments[0]; 4551 Segment& thisOne = fSegments[thisIndex]; 4552 Contour* otherContour = coincidence.fContours[1]; 4553 int otherIndex = coincidence.fSegments[1]; 4554 Segment& other = otherContour->fSegments[otherIndex]; 4555 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) { 4556 continue; 4557 } 4558 #if DEBUG_CONCIDENT 4559 thisOne.debugShowTs(); 4560 other.debugShowTs(); 4561 #endif 4562 double startT = coincidence.fTs[0][0]; 4563 double endT = coincidence.fTs[0][1]; 4564 bool cancelers = false; 4565 if (startT > endT) { 4566 SkTSwap<double>(startT, endT); 4567 cancelers ^= true; // FIXME: just assign true 4568 } 4569 SkASSERT(!approximately_negative(endT - startT)); 4570 double oStartT = coincidence.fTs[1][0]; 4571 double oEndT = coincidence.fTs[1][1]; 4572 if (oStartT > oEndT) { 4573 SkTSwap<double>(oStartT, oEndT); 4574 cancelers ^= true; 4575 } 4576 SkASSERT(!approximately_negative(oEndT - oStartT)); 4577 bool opp = fOperand ^ otherContour->fOperand; 4578 if (cancelers && !opp) { 4579 // make sure startT and endT have t entries 4580 if (startT > 0 || oEndT < 1 4581 || thisOne.isMissing(startT) || other.isMissing(oEndT)) { 4582 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]); 4583 } 4584 if (oStartT > 0 || endT < 1 4585 || thisOne.isMissing(endT) || other.isMissing(oStartT)) { 4586 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]); 4587 } 4588 if (!thisOne.done() && !other.done()) { 4589 thisOne.addTCancel(startT, endT, other, oStartT, oEndT); 4590 } 4591 } else { 4592 if (startT > 0 || oStartT > 0 4593 || thisOne.isMissing(startT) || other.isMissing(oStartT)) { 4594 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]); 4595 } 4596 if (endT < 1 || oEndT < 1 4597 || thisOne.isMissing(endT) || other.isMissing(oEndT)) { 4598 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]); 4599 } 4600 if (!thisOne.done() && !other.done()) { 4601 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT); 4602 } 4603 } 4604 #if DEBUG_CONCIDENT 4605 thisOne.debugShowTs(); 4606 other.debugShowTs(); 4607 #endif 4608 #if DEBUG_SHOW_WINDING 4609 debugShowWindingValues(contourList); 4610 #endif 4611 } 4612 } 4613 4614 // first pass, add missing T values 4615 // second pass, determine winding values of overlaps 4616 void addCoincidentPoints() { 4617 int count = fCoincidences.count(); 4618 for (int index = 0; index < count; ++index) { 4619 Coincidence& coincidence = fCoincidences[index]; 4620 SkASSERT(coincidence.fContours[0] == this); 4621 int thisIndex = coincidence.fSegments[0]; 4622 Segment& thisOne = fSegments[thisIndex]; 4623 Contour* otherContour = coincidence.fContours[1]; 4624 int otherIndex = coincidence.fSegments[1]; 4625 Segment& other = otherContour->fSegments[otherIndex]; 4626 if ((thisOne.done() || other.done()) && thisOne.complete() && other.complete()) { 4627 // OPTIMIZATION: remove from array 4628 continue; 4629 } 4630 #if DEBUG_CONCIDENT 4631 thisOne.debugShowTs(); 4632 other.debugShowTs(); 4633 #endif 4634 double startT = coincidence.fTs[0][0]; 4635 double endT = coincidence.fTs[0][1]; 4636 bool cancelers; 4637 if ((cancelers = startT > endT)) { 4638 SkTSwap(startT, endT); 4639 SkTSwap(coincidence.fPts[0], coincidence.fPts[1]); 4640 } 4641 SkASSERT(!approximately_negative(endT - startT)); 4642 double oStartT = coincidence.fTs[1][0]; 4643 double oEndT = coincidence.fTs[1][1]; 4644 if (oStartT > oEndT) { 4645 SkTSwap<double>(oStartT, oEndT); 4646 cancelers ^= true; 4647 } 4648 SkASSERT(!approximately_negative(oEndT - oStartT)); 4649 bool opp = fOperand ^ otherContour->fOperand; 4650 if (cancelers && !opp) { 4651 // make sure startT and endT have t entries 4652 if (startT > 0 || oEndT < 1 4653 || thisOne.isMissing(startT) || other.isMissing(oEndT)) { 4654 thisOne.addTPair(startT, other, oEndT, true, coincidence.fPts[0]); 4655 } 4656 if (oStartT > 0 || endT < 1 4657 || thisOne.isMissing(endT) || other.isMissing(oStartT)) { 4658 other.addTPair(oStartT, thisOne, endT, true, coincidence.fPts[1]); 4659 } 4660 } else { 4661 if (startT > 0 || oStartT > 0 4662 || thisOne.isMissing(startT) || other.isMissing(oStartT)) { 4663 thisOne.addTPair(startT, other, oStartT, true, coincidence.fPts[0]); 4664 } 4665 if (endT < 1 || oEndT < 1 4666 || thisOne.isMissing(endT) || other.isMissing(oEndT)) { 4667 other.addTPair(oEndT, thisOne, endT, true, coincidence.fPts[1]); 4668 } 4669 } 4670 #if DEBUG_CONCIDENT 4671 thisOne.debugShowTs(); 4672 other.debugShowTs(); 4673 #endif 4674 } 4675 } 4676 4677 void calcCoincidentWinding() { 4678 int count = fCoincidences.count(); 4679 for (int index = 0; index < count; ++index) { 4680 Coincidence& coincidence = fCoincidences[index]; 4681 SkASSERT(coincidence.fContours[0] == this); 4682 int thisIndex = coincidence.fSegments[0]; 4683 Segment& thisOne = fSegments[thisIndex]; 4684 if (thisOne.done()) { 4685 continue; 4686 } 4687 Contour* otherContour = coincidence.fContours[1]; 4688 int otherIndex = coincidence.fSegments[1]; 4689 Segment& other = otherContour->fSegments[otherIndex]; 4690 if (other.done()) { 4691 continue; 4692 } 4693 double startT = coincidence.fTs[0][0]; 4694 double endT = coincidence.fTs[0][1]; 4695 bool cancelers; 4696 if ((cancelers = startT > endT)) { 4697 SkTSwap<double>(startT, endT); 4698 } 4699 SkASSERT(!approximately_negative(endT - startT)); 4700 double oStartT = coincidence.fTs[1][0]; 4701 double oEndT = coincidence.fTs[1][1]; 4702 if (oStartT > oEndT) { 4703 SkTSwap<double>(oStartT, oEndT); 4704 cancelers ^= true; 4705 } 4706 SkASSERT(!approximately_negative(oEndT - oStartT)); 4707 bool opp = fOperand ^ otherContour->fOperand; 4708 if (cancelers && !opp) { 4709 // make sure startT and endT have t entries 4710 if (!thisOne.done() && !other.done()) { 4711 thisOne.addTCancel(startT, endT, other, oStartT, oEndT); 4712 } 4713 } else { 4714 if (!thisOne.done() && !other.done()) { 4715 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT); 4716 } 4717 } 4718 #if DEBUG_CONCIDENT 4719 thisOne.debugShowTs(); 4720 other.debugShowTs(); 4721 #endif 4722 } 4723 } 4724 4725 SkTArray<Segment>& segments() { 4726 return fSegments; 4727 } 4728 4729 void setContainsIntercepts() { 4730 fContainsIntercepts = true; 4731 } 4732 4733 void setOperand(bool isOp) { 4734 fOperand = isOp; 4735 } 4736 4737 void setOppXor(bool isOppXor) { 4738 fOppXor = isOppXor; 4739 int segmentCount = fSegments.count(); 4740 for (int test = 0; test < segmentCount; ++test) { 4741 fSegments[test].setOppXor(isOppXor); 4742 } 4743 } 4744 4745 void setXor(bool isXor) { 4746 fXor = isXor; 4747 } 4748 4749 void sortSegments() { 4750 int segmentCount = fSegments.count(); 4751 fSortedSegments.setReserve(segmentCount); 4752 for (int test = 0; test < segmentCount; ++test) { 4753 *fSortedSegments.append() = &fSegments[test]; 4754 } 4755 QSort<Segment>(fSortedSegments.begin(), fSortedSegments.end() - 1); 4756 fFirstSorted = 0; 4757 } 4758 4759 const SkPoint& start() const { 4760 return fSegments.front().pts()[0]; 4761 } 4762 4763 void toPath(PathWrapper& path) const { 4764 int segmentCount = fSegments.count(); 4765 const SkPoint& pt = fSegments.front().pts()[0]; 4766 path.deferredMove(pt); 4767 for (int test = 0; test < segmentCount; ++test) { 4768 fSegments[test].addCurveTo(0, 1, path, true); 4769 } 4770 path.close(); 4771 } 4772 4773 void toPartialBackward(PathWrapper& path) const { 4774 int segmentCount = fSegments.count(); 4775 for (int test = segmentCount - 1; test >= 0; --test) { 4776 fSegments[test].addCurveTo(1, 0, path, true); 4777 } 4778 } 4779 4780 void toPartialForward(PathWrapper& path) const { 4781 int segmentCount = fSegments.count(); 4782 for (int test = 0; test < segmentCount; ++test) { 4783 fSegments[test].addCurveTo(0, 1, path, true); 4784 } 4785 } 4786 4787 void topSortableSegment(const SkPoint& topLeft, SkPoint& bestXY, Segment*& topStart) { 4788 int segmentCount = fSortedSegments.count(); 4789 SkASSERT(segmentCount > 0); 4790 int sortedIndex = fFirstSorted; 4791 fDone = true; // may be cleared below 4792 for ( ; sortedIndex < segmentCount; ++sortedIndex) { 4793 Segment* testSegment = fSortedSegments[sortedIndex]; 4794 if (testSegment->done()) { 4795 if (sortedIndex == fFirstSorted) { 4796 ++fFirstSorted; 4797 } 4798 continue; 4799 } 4800 fDone = false; 4801 SkPoint testXY = testSegment->activeLeftTop(true, NULL); 4802 if (topStart) { 4803 if (testXY.fY < topLeft.fY) { 4804 continue; 4805 } 4806 if (testXY.fY == topLeft.fY && testXY.fX < topLeft.fX) { 4807 continue; 4808 } 4809 if (bestXY.fY < testXY.fY) { 4810 continue; 4811 } 4812 if (bestXY.fY == testXY.fY && bestXY.fX < testXY.fX) { 4813 continue; 4814 } 4815 } 4816 topStart = testSegment; 4817 bestXY = testXY; 4818 } 4819 } 4820 4821 Segment* undoneSegment(int& start, int& end) { 4822 int segmentCount = fSegments.count(); 4823 for (int test = 0; test < segmentCount; ++test) { 4824 Segment* testSegment = &fSegments[test]; 4825 if (testSegment->done()) { 4826 continue; 4827 } 4828 testSegment->undoneSpan(start, end); 4829 return testSegment; 4830 } 4831 return NULL; 4832 } 4833 4834 int updateSegment(int index, const SkPoint* pts) { 4835 Segment& segment = fSegments[index]; 4836 segment.updatePts(pts); 4837 return segment.verb() + 1; 4838 } 4839 4840#if DEBUG_TEST 4841 SkTArray<Segment>& debugSegments() { 4842 return fSegments; 4843 } 4844#endif 4845 4846#if DEBUG_DUMP 4847 void dump() { 4848 int i; 4849 const char className[] = "Contour"; 4850 const int tab = 4; 4851 SkDebugf("%s %p (contour=%d)\n", className, this, fID); 4852 for (i = 0; i < fSegments.count(); ++i) { 4853 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className), 4854 className, i); 4855 fSegments[i].dump(); 4856 } 4857 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n", 4858 tab + sizeof(className), className, 4859 fBounds.fLeft, fBounds.fTop, 4860 fBounds.fRight, fBounds.fBottom); 4861 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className), 4862 className, fContainsIntercepts); 4863 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className), 4864 className, fContainsCurves); 4865 } 4866#endif 4867 4868#if DEBUG_ACTIVE_SPANS 4869 void debugShowActiveSpans() { 4870 for (int index = 0; index < fSegments.count(); ++index) { 4871 fSegments[index].debugShowActiveSpans(); 4872 } 4873 } 4874 4875 void validateActiveSpans() { 4876 for (int index = 0; index < fSegments.count(); ++index) { 4877 fSegments[index].validateActiveSpans(); 4878 } 4879 } 4880#endif 4881 4882#if DEBUG_SHOW_WINDING 4883 int debugShowWindingValues(int totalSegments, int ofInterest) { 4884 int count = fSegments.count(); 4885 int sum = 0; 4886 for (int index = 0; index < count; ++index) { 4887 sum += fSegments[index].debugShowWindingValues(totalSegments, ofInterest); 4888 } 4889 // SkDebugf("%s sum=%d\n", __FUNCTION__, sum); 4890 return sum; 4891 } 4892 4893 static void debugShowWindingValues(SkTDArray<Contour*>& contourList) { 4894 // int ofInterest = 1 << 1 | 1 << 5 | 1 << 9 | 1 << 13; 4895 // int ofInterest = 1 << 4 | 1 << 8 | 1 << 12 | 1 << 16; 4896 int ofInterest = 1 << 5 | 1 << 8; 4897 int total = 0; 4898 int index; 4899 for (index = 0; index < contourList.count(); ++index) { 4900 total += contourList[index]->segments().count(); 4901 } 4902 int sum = 0; 4903 for (index = 0; index < contourList.count(); ++index) { 4904 sum += contourList[index]->debugShowWindingValues(total, ofInterest); 4905 } 4906 // SkDebugf("%s total=%d\n", __FUNCTION__, sum); 4907 } 4908#endif 4909 4910protected: 4911 void setBounds() { 4912 int count = fSegments.count(); 4913 if (count == 0) { 4914 SkDebugf("%s empty contour\n", __FUNCTION__); 4915 SkASSERT(0); 4916 // FIXME: delete empty contour? 4917 return; 4918 } 4919 fBounds = fSegments.front().bounds(); 4920 for (int index = 1; index < count; ++index) { 4921 fBounds.add(fSegments[index].bounds()); 4922 } 4923 } 4924 4925private: 4926 SkTArray<Segment> fSegments; 4927 SkTDArray<Segment*> fSortedSegments; 4928 int fFirstSorted; 4929 SkTDArray<Coincidence> fCoincidences; 4930 SkTDArray<const Contour*> fCrosses; 4931 Bounds fBounds; 4932 bool fContainsIntercepts; // FIXME: is this used by anybody? 4933 bool fContainsCubics; 4934 bool fContainsCurves; 4935 bool fDone; 4936 bool fOperand; // true for the second argument to a binary operator 4937 bool fXor; 4938 bool fOppXor; 4939#if DEBUG_DUMP 4940 int fID; 4941#endif 4942}; 4943 4944class EdgeBuilder { 4945public: 4946 4947EdgeBuilder(const PathWrapper& path, SkTArray<Contour>& contours) 4948 : fPath(path.nativePath()) 4949 , fContours(contours) 4950{ 4951 init(); 4952} 4953 4954EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours) 4955 : fPath(&path) 4956 , fContours(contours) 4957{ 4958 init(); 4959} 4960 4961void init() { 4962 fCurrentContour = NULL; 4963 fOperand = false; 4964 fXorMask[0] = fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask; 4965#if DEBUG_DUMP 4966 gContourID = 0; 4967 gSegmentID = 0; 4968#endif 4969 fSecondHalf = preFetch(); 4970} 4971 4972void addOperand(const SkPath& path) { 4973 SkASSERT(fPathVerbs.count() > 0 && fPathVerbs.end()[-1] == SkPath::kDone_Verb); 4974 fPathVerbs.pop(); 4975 fPath = &path; 4976 fXorMask[1] = (fPath->getFillType() & 1) ? kEvenOdd_Mask : kWinding_Mask; 4977 preFetch(); 4978} 4979 4980void finish() { 4981 walk(); 4982 complete(); 4983 if (fCurrentContour && !fCurrentContour->segments().count()) { 4984 fContours.pop_back(); 4985 } 4986 // correct pointers in contours since fReducePts may have moved as it grew 4987 int cIndex = 0; 4988 int extraCount = fExtra.count(); 4989 SkASSERT(extraCount == 0 || fExtra[0] == -1); 4990 int eIndex = 0; 4991 int rIndex = 0; 4992 while (++eIndex < extraCount) { 4993 int offset = fExtra[eIndex]; 4994 if (offset < 0) { 4995 ++cIndex; 4996 continue; 4997 } 4998 fCurrentContour = &fContours[cIndex]; 4999 rIndex += fCurrentContour->updateSegment(offset - 1, 5000 &fReducePts[rIndex]); 5001 } 5002 fExtra.reset(); // we're done with this 5003} 5004 5005ShapeOpMask xorMask() const { 5006 return fXorMask[fOperand]; 5007} 5008 5009protected: 5010 5011void complete() { 5012 if (fCurrentContour && fCurrentContour->segments().count()) { 5013 fCurrentContour->complete(); 5014 fCurrentContour = NULL; 5015 } 5016} 5017 5018// FIXME:remove once we can access path pts directly 5019int preFetch() { 5020 SkPath::RawIter iter(*fPath); // FIXME: access path directly when allowed 5021 SkPoint pts[4]; 5022 SkPath::Verb verb; 5023 do { 5024 verb = iter.next(pts); 5025 *fPathVerbs.append() = verb; 5026 if (verb == SkPath::kMove_Verb) { 5027 *fPathPts.append() = pts[0]; 5028 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) { 5029 fPathPts.append(verb, &pts[1]); 5030 } 5031 } while (verb != SkPath::kDone_Verb); 5032 return fPathVerbs.count() - 1; 5033} 5034 5035void walk() { 5036 SkPath::Verb reducedVerb; 5037 uint8_t* verbPtr = fPathVerbs.begin(); 5038 uint8_t* endOfFirstHalf = &verbPtr[fSecondHalf]; 5039 const SkPoint* pointsPtr = fPathPts.begin(); 5040 const SkPoint* finalCurveStart = NULL; 5041 const SkPoint* finalCurveEnd = NULL; 5042 SkPath::Verb verb; 5043 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) { 5044 switch (verb) { 5045 case SkPath::kMove_Verb: 5046 complete(); 5047 if (!fCurrentContour) { 5048 fCurrentContour = fContours.push_back_n(1); 5049 fCurrentContour->setOperand(fOperand); 5050 fCurrentContour->setXor(fXorMask[fOperand] == kEvenOdd_Mask); 5051 *fExtra.append() = -1; // start new contour 5052 } 5053 finalCurveEnd = pointsPtr++; 5054 goto nextVerb; 5055 case SkPath::kLine_Verb: 5056 // skip degenerate points 5057 if (pointsPtr[-1].fX != pointsPtr[0].fX 5058 || pointsPtr[-1].fY != pointsPtr[0].fY) { 5059 fCurrentContour->addLine(&pointsPtr[-1]); 5060 } 5061 break; 5062 case SkPath::kQuad_Verb: 5063 5064 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts); 5065 if (reducedVerb == 0) { 5066 break; // skip degenerate points 5067 } 5068 if (reducedVerb == 1) { 5069 *fExtra.append() = 5070 fCurrentContour->addLine(fReducePts.end() - 2); 5071 break; 5072 } 5073 fCurrentContour->addQuad(&pointsPtr[-1]); 5074 break; 5075 case SkPath::kCubic_Verb: 5076 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts); 5077 if (reducedVerb == 0) { 5078 break; // skip degenerate points 5079 } 5080 if (reducedVerb == 1) { 5081 *fExtra.append() = 5082 fCurrentContour->addLine(fReducePts.end() - 2); 5083 break; 5084 } 5085 if (reducedVerb == 2) { 5086 *fExtra.append() = 5087 fCurrentContour->addQuad(fReducePts.end() - 3); 5088 break; 5089 } 5090 fCurrentContour->addCubic(&pointsPtr[-1]); 5091 break; 5092 case SkPath::kClose_Verb: 5093 SkASSERT(fCurrentContour); 5094 if (finalCurveStart && finalCurveEnd 5095 && *finalCurveStart != *finalCurveEnd) { 5096 *fReducePts.append() = *finalCurveStart; 5097 *fReducePts.append() = *finalCurveEnd; 5098 *fExtra.append() = 5099 fCurrentContour->addLine(fReducePts.end() - 2); 5100 } 5101 complete(); 5102 goto nextVerb; 5103 default: 5104 SkDEBUGFAIL("bad verb"); 5105 return; 5106 } 5107 finalCurveStart = &pointsPtr[verb - 1]; 5108 pointsPtr += verb; 5109 SkASSERT(fCurrentContour); 5110 nextVerb: 5111 if (verbPtr == endOfFirstHalf) { 5112 fOperand = true; 5113 } 5114 } 5115} 5116 5117private: 5118 const SkPath* fPath; 5119 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead 5120 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove 5121 Contour* fCurrentContour; 5122 SkTArray<Contour>& fContours; 5123 SkTDArray<SkPoint> fReducePts; // segments created on the fly 5124 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour 5125 ShapeOpMask fXorMask[2]; 5126 int fSecondHalf; 5127 bool fOperand; 5128}; 5129 5130class Work { 5131public: 5132 enum SegmentType { 5133 kHorizontalLine_Segment = -1, 5134 kVerticalLine_Segment = 0, 5135 kLine_Segment = SkPath::kLine_Verb, 5136 kQuad_Segment = SkPath::kQuad_Verb, 5137 kCubic_Segment = SkPath::kCubic_Verb, 5138 }; 5139 5140 void addCoincident(Work& other, const Intersections& ts, bool swap) { 5141 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap); 5142 } 5143 5144 // FIXME: does it make sense to write otherIndex now if we're going to 5145 // fix it up later? 5146 void addOtherT(int index, double otherT, int otherIndex) { 5147 fContour->addOtherT(fIndex, index, otherT, otherIndex); 5148 } 5149 5150 // Avoid collapsing t values that are close to the same since 5151 // we walk ts to describe consecutive intersections. Since a pair of ts can 5152 // be nearly equal, any problems caused by this should be taken care 5153 // of later. 5154 // On the edge or out of range values are negative; add 2 to get end 5155 int addT(const Work& other, const SkPoint& pt, double& newT) { 5156 return fContour->addT(fIndex, other.fContour, other.fIndex, pt, newT); 5157 } 5158 5159 int addSelfT(const Work& other, const SkPoint& pt, double& newT) { 5160 return fContour->addSelfT(fIndex, other.fContour, other.fIndex, pt, newT); 5161 } 5162 5163 int addUnsortableT(const Work& other, bool start, const SkPoint& pt, double& newT) { 5164 return fContour->addUnsortableT(fIndex, other.fContour, other.fIndex, start, pt, newT); 5165 } 5166 5167 bool advance() { 5168 return ++fIndex < fLast; 5169 } 5170 5171 SkScalar bottom() const { 5172 return bounds().fBottom; 5173 } 5174 5175 const Bounds& bounds() const { 5176 return fContour->segments()[fIndex].bounds(); 5177 } 5178 5179#if !APPROXIMATE_CUBICS 5180 const SkPoint* cubic() const { 5181 return fCubic; 5182 } 5183#endif 5184 5185 void init(Contour* contour) { 5186 fContour = contour; 5187 fIndex = 0; 5188 fLast = contour->segments().count(); 5189 } 5190 5191 bool isAdjacent(const Work& next) { 5192 return fContour == next.fContour && fIndex + 1 == next.fIndex; 5193 } 5194 5195 bool isFirstLast(const Work& next) { 5196 return fContour == next.fContour && fIndex == 0 5197 && next.fIndex == fLast - 1; 5198 } 5199 5200 SkScalar left() const { 5201 return bounds().fLeft; 5202 } 5203 5204#if !APPROXIMATE_CUBICS 5205 void promoteToCubic() { 5206 fCubic[0] = pts()[0]; 5207 fCubic[2] = pts()[1]; 5208 fCubic[3] = pts()[2]; 5209 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3; 5210 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3; 5211 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3; 5212 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3; 5213 } 5214#endif 5215 5216 const SkPoint* pts() const { 5217 return fContour->segments()[fIndex].pts(); 5218 } 5219 5220 SkScalar right() const { 5221 return bounds().fRight; 5222 } 5223 5224 ptrdiff_t segmentIndex() const { 5225 return fIndex; 5226 } 5227 5228 SegmentType segmentType() const { 5229 const Segment& segment = fContour->segments()[fIndex]; 5230 SegmentType type = (SegmentType) segment.verb(); 5231 if (type != kLine_Segment) { 5232 return type; 5233 } 5234 if (segment.isHorizontal()) { 5235 return kHorizontalLine_Segment; 5236 } 5237 if (segment.isVertical()) { 5238 return kVerticalLine_Segment; 5239 } 5240 return kLine_Segment; 5241 } 5242 5243 bool startAfter(const Work& after) { 5244 fIndex = after.fIndex; 5245 return advance(); 5246 } 5247 5248 SkScalar top() const { 5249 return bounds().fTop; 5250 } 5251 5252 SkPath::Verb verb() const { 5253 return fContour->segments()[fIndex].verb(); 5254 } 5255 5256 SkScalar x() const { 5257 return bounds().fLeft; 5258 } 5259 5260 bool xFlipped() const { 5261 return x() != pts()[0].fX; 5262 } 5263 5264 SkScalar y() const { 5265 return bounds().fTop; 5266 } 5267 5268 bool yFlipped() const { 5269 return y() != pts()[0].fY; 5270 } 5271 5272protected: 5273 Contour* fContour; 5274#if !APPROXIMATE_CUBICS 5275 SkPoint fCubic[4]; 5276#endif 5277 int fIndex; 5278 int fLast; 5279}; 5280 5281#if DEBUG_ADD_INTERSECTING_TS 5282 5283#if DEBUG_AS_C_CODE 5284#define CUBIC_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}}" 5285#define QUAD_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}, {%1.17g,%1.17g}}" 5286#define LINE_DEBUG_STR "{{%1.17g,%1.17g}, {%1.17g,%1.17g}}" 5287#define PT_DEBUG_STR "{{%1.17g,%1.17g}}" 5288#else 5289#define CUBIC_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)" 5290#define QUAD_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g %1.9g,%1.9g)" 5291#define LINE_DEBUG_STR "(%1.9g,%1.9g %1.9g,%1.9g)" 5292#define PT_DEBUG_STR "(%1.9g,%1.9g)" 5293#endif 5294#define T_DEBUG_STR(t, n) #t "[" #n "]=%1.9g" 5295#define TX_DEBUG_STR(t) #t "[%d]=%1.9g" 5296#define CUBIC_DEBUG_DATA(c) c[0].fX, c[0].fY, c[1].fX, c[1].fY, c[2].fX, c[2].fY, c[3].fX, c[3].fY 5297#define QUAD_DEBUG_DATA(q) q[0].fX, q[0].fY, q[1].fX, q[1].fY, q[2].fX, q[2].fY 5298#define LINE_DEBUG_DATA(l) l[0].fX, l[0].fY, l[1].fX, l[1].fY 5299#define PT_DEBUG_DATA(i, n) i.fPt[n].x, i.fPt[n].y 5300 5301static void debugShowLineIntersection(int pts, const Work& wt, const Work& wn, 5302 const Intersections& i) { 5303 SkASSERT(i.used() == pts); 5304 if (!pts) { 5305 SkDebugf("%s no intersect " LINE_DEBUG_STR " " LINE_DEBUG_STR "\n", 5306 __FUNCTION__, LINE_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts())); 5307 return; 5308 } 5309 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " LINE_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, 5310 i.fT[0][0], LINE_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); 5311 if (pts == 2) { 5312 SkDebugf(" " T_DEBUG_STR(wtTs, 1) " " PT_DEBUG_STR, i.fT[0][1], PT_DEBUG_DATA(i, 1)); 5313 } 5314 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts())); 5315 if (pts == 2) { 5316 SkDebugf(" " T_DEBUG_STR(wnTs, 1), i.fT[1][1]); 5317 } 5318 SkDebugf("\n"); 5319} 5320 5321static void debugShowQuadLineIntersection(int pts, const Work& wt, 5322 const Work& wn, const Intersections& i) { 5323 SkASSERT(i.used() == pts); 5324 if (!pts) { 5325 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " LINE_DEBUG_STR "\n", 5326 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts())); 5327 return; 5328 } 5329 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, 5330 i.fT[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); 5331 for (int n = 1; n < pts; ++n) { 5332 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n)); 5333 } 5334 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts())); 5335 for (int n = 1; n < pts; ++n) { 5336 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]); 5337 } 5338 SkDebugf("\n"); 5339} 5340 5341static void debugShowQuadIntersection(int pts, const Work& wt, 5342 const Work& wn, const Intersections& i) { 5343 SkASSERT(i.used() == pts); 5344 if (!pts) { 5345 SkDebugf("%s no intersect " QUAD_DEBUG_STR " " QUAD_DEBUG_STR "\n", 5346 __FUNCTION__, QUAD_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts())); 5347 return; 5348 } 5349 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " QUAD_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, 5350 i.fT[0][0], QUAD_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); 5351 for (int n = 1; n < pts; ++n) { 5352 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n)); 5353 } 5354 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i.fT[1][0], QUAD_DEBUG_DATA(wn.pts())); 5355 for (int n = 1; n < pts; ++n) { 5356 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]); 5357 } 5358 SkDebugf("\n"); 5359} 5360 5361static void debugShowCubicLineIntersection(int pts, const Work& wt, 5362 const Work& wn, const Intersections& i) { 5363 SkASSERT(i.used() == pts); 5364 if (!pts) { 5365 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " LINE_DEBUG_STR "\n", 5366 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), LINE_DEBUG_DATA(wn.pts())); 5367 return; 5368 } 5369 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, 5370 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); 5371 for (int n = 1; n < pts; ++n) { 5372 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n)); 5373 } 5374 SkDebugf(" wnTs[0]=%g " LINE_DEBUG_STR, i.fT[1][0], LINE_DEBUG_DATA(wn.pts())); 5375 for (int n = 1; n < pts; ++n) { 5376 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]); 5377 } 5378 SkDebugf("\n"); 5379} 5380 5381static void debugShowCubicQuadIntersection(int pts, const Work& wt, 5382 const Work& wn, const Intersections& i) { 5383 SkASSERT(i.used() == pts); 5384 if (!pts) { 5385 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " QUAD_DEBUG_STR "\n", 5386 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), QUAD_DEBUG_DATA(wn.pts())); 5387 return; 5388 } 5389 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, 5390 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); 5391 for (int n = 1; n < pts; ++n) { 5392 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n)); 5393 } 5394 SkDebugf(" wnTs[0]=%g " QUAD_DEBUG_STR, i.fT[1][0], QUAD_DEBUG_DATA(wn.pts())); 5395 for (int n = 1; n < pts; ++n) { 5396 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]); 5397 } 5398 SkDebugf("\n"); 5399} 5400 5401static void debugShowCubicIntersection(int pts, const Work& wt, 5402 const Work& wn, const Intersections& i) { 5403 SkASSERT(i.used() == pts); 5404 if (!pts) { 5405 SkDebugf("%s no intersect " CUBIC_DEBUG_STR " " CUBIC_DEBUG_STR "\n", 5406 __FUNCTION__, CUBIC_DEBUG_DATA(wt.pts()), CUBIC_DEBUG_DATA(wn.pts())); 5407 return; 5408 } 5409 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, 5410 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); 5411 for (int n = 1; n < pts; ++n) { 5412 SkDebugf(" " TX_DEBUG_STR(wtTs) " " PT_DEBUG_STR, n, i.fT[0][n], PT_DEBUG_DATA(i, n)); 5413 } 5414 SkDebugf(" wnTs[0]=%g " CUBIC_DEBUG_STR, i.fT[1][0], CUBIC_DEBUG_DATA(wn.pts())); 5415 for (int n = 1; n < pts; ++n) { 5416 SkDebugf(" " TX_DEBUG_STR(wnTs), n, i.fT[1][n]); 5417 } 5418 SkDebugf("\n"); 5419} 5420 5421static void debugShowCubicIntersection(int pts, const Work& wt, const Intersections& i) { 5422 SkASSERT(i.used() == pts); 5423 if (!pts) { 5424 SkDebugf("%s no self intersect " CUBIC_DEBUG_STR "\n", __FUNCTION__, 5425 CUBIC_DEBUG_DATA(wt.pts())); 5426 return; 5427 } 5428 SkDebugf("%s " T_DEBUG_STR(wtTs, 0) " " CUBIC_DEBUG_STR " " PT_DEBUG_STR, __FUNCTION__, 5429 i.fT[0][0], CUBIC_DEBUG_DATA(wt.pts()), PT_DEBUG_DATA(i, 0)); 5430 SkDebugf(" " T_DEBUG_STR(wtTs, 1), i.fT[1][0]); 5431 SkDebugf("\n"); 5432} 5433 5434#undef CUBIC_DEBUG_STR 5435#undef QUAD_DEBUG_STR 5436#undef LINE_DEBUG_STR 5437#undef PT_DEBUG_STR 5438#undef T_DEBUG_STR 5439#undef CUBIC_DEBUG_DATA 5440#undef QUAD_DEBUG_DATA 5441#undef LINE_DEBUG_DATA 5442#undef PT_DEBUG_DATA 5443 5444#else 5445static void debugShowLineIntersection(int , const Work& , const Work& , const Intersections& ) { 5446} 5447 5448static void debugShowQuadLineIntersection(int , const Work& , const Work& , const Intersections& ) { 5449} 5450 5451static void debugShowQuadIntersection(int , const Work& , const Work& , const Intersections& ) { 5452} 5453 5454static void debugShowCubicLineIntersection(int , const Work& , const Work& , 5455 const Intersections& ) { 5456} 5457 5458static void debugShowCubicQuadIntersection(int , const Work& , const Work& , 5459 const Intersections& ) { 5460} 5461 5462static void debugShowCubicIntersection(int , const Work& , const Work& , const Intersections& ) { 5463} 5464 5465static void debugShowCubicIntersection(int , const Work& , const Intersections& ) { 5466} 5467#endif 5468 5469static bool addIntersectTs(Contour* test, Contour* next) { 5470 5471 if (test != next) { 5472 if (test->bounds().fBottom < next->bounds().fTop) { 5473 return false; 5474 } 5475 if (!Bounds::Intersects(test->bounds(), next->bounds())) { 5476 return true; 5477 } 5478 } 5479 Work wt; 5480 wt.init(test); 5481 bool foundCommonContour = test == next; 5482 do { 5483 Work wn; 5484 wn.init(next); 5485 if (test == next && !wn.startAfter(wt)) { 5486 continue; 5487 } 5488 do { 5489 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) { 5490 continue; 5491 } 5492 int pts; 5493 Intersections ts; 5494 bool swap = false; 5495 switch (wt.segmentType()) { 5496 case Work::kHorizontalLine_Segment: 5497 swap = true; 5498 switch (wn.segmentType()) { 5499 case Work::kHorizontalLine_Segment: 5500 case Work::kVerticalLine_Segment: 5501 case Work::kLine_Segment: { 5502 pts = HLineIntersect(wn.pts(), wt.left(), 5503 wt.right(), wt.y(), wt.xFlipped(), ts); 5504 debugShowLineIntersection(pts, wt, wn, ts); 5505 break; 5506 } 5507 case Work::kQuad_Segment: { 5508 pts = HQuadIntersect(wn.pts(), wt.left(), 5509 wt.right(), wt.y(), wt.xFlipped(), ts); 5510 break; 5511 } 5512 case Work::kCubic_Segment: { 5513 pts = HCubicIntersect(wn.pts(), wt.left(), 5514 wt.right(), wt.y(), wt.xFlipped(), ts); 5515 debugShowCubicLineIntersection(pts, wn, wt, ts); 5516 break; 5517 } 5518 default: 5519 SkASSERT(0); 5520 } 5521 break; 5522 case Work::kVerticalLine_Segment: 5523 swap = true; 5524 switch (wn.segmentType()) { 5525 case Work::kHorizontalLine_Segment: 5526 case Work::kVerticalLine_Segment: 5527 case Work::kLine_Segment: { 5528 pts = VLineIntersect(wn.pts(), wt.top(), 5529 wt.bottom(), wt.x(), wt.yFlipped(), ts); 5530 debugShowLineIntersection(pts, wt, wn, ts); 5531 break; 5532 } 5533 case Work::kQuad_Segment: { 5534 pts = VQuadIntersect(wn.pts(), wt.top(), 5535 wt.bottom(), wt.x(), wt.yFlipped(), ts); 5536 break; 5537 } 5538 case Work::kCubic_Segment: { 5539 pts = VCubicIntersect(wn.pts(), wt.top(), 5540 wt.bottom(), wt.x(), wt.yFlipped(), ts); 5541 debugShowCubicLineIntersection(pts, wn, wt, ts); 5542 break; 5543 } 5544 default: 5545 SkASSERT(0); 5546 } 5547 break; 5548 case Work::kLine_Segment: 5549 switch (wn.segmentType()) { 5550 case Work::kHorizontalLine_Segment: 5551 pts = HLineIntersect(wt.pts(), wn.left(), 5552 wn.right(), wn.y(), wn.xFlipped(), ts); 5553 debugShowLineIntersection(pts, wt, wn, ts); 5554 break; 5555 case Work::kVerticalLine_Segment: 5556 pts = VLineIntersect(wt.pts(), wn.top(), 5557 wn.bottom(), wn.x(), wn.yFlipped(), ts); 5558 debugShowLineIntersection(pts, wt, wn, ts); 5559 break; 5560 case Work::kLine_Segment: { 5561 pts = LineIntersect(wt.pts(), wn.pts(), ts); 5562 debugShowLineIntersection(pts, wt, wn, ts); 5563 break; 5564 } 5565 case Work::kQuad_Segment: { 5566 swap = true; 5567 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts); 5568 debugShowQuadLineIntersection(pts, wn, wt, ts); 5569 break; 5570 } 5571 case Work::kCubic_Segment: { 5572 swap = true; 5573 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts); 5574 debugShowCubicLineIntersection(pts, wn, wt, ts); 5575 break; 5576 } 5577 default: 5578 SkASSERT(0); 5579 } 5580 break; 5581 case Work::kQuad_Segment: 5582 switch (wn.segmentType()) { 5583 case Work::kHorizontalLine_Segment: 5584 pts = HQuadIntersect(wt.pts(), wn.left(), 5585 wn.right(), wn.y(), wn.xFlipped(), ts); 5586 break; 5587 case Work::kVerticalLine_Segment: 5588 pts = VQuadIntersect(wt.pts(), wn.top(), 5589 wn.bottom(), wn.x(), wn.yFlipped(), ts); 5590 break; 5591 case Work::kLine_Segment: { 5592 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts); 5593 debugShowQuadLineIntersection(pts, wt, wn, ts); 5594 break; 5595 } 5596 case Work::kQuad_Segment: { 5597 pts = QuadIntersect(wt.pts(), wn.pts(), ts); 5598 debugShowQuadIntersection(pts, wt, wn, ts); 5599 break; 5600 } 5601 case Work::kCubic_Segment: { 5602 #if APPROXIMATE_CUBICS 5603 swap = true; 5604 pts = CubicQuadIntersect(wn.pts(), wt.pts(), ts); 5605 debugShowCubicQuadIntersection(pts, wn, wt, ts); 5606 #else 5607 wt.promoteToCubic(); 5608 pts = CubicIntersect(wt.cubic(), wn.pts(), ts); 5609 debugShowCubicIntersection(pts, wt, wn, ts); 5610 #endif 5611 break; 5612 } 5613 default: 5614 SkASSERT(0); 5615 } 5616 break; 5617 case Work::kCubic_Segment: 5618 switch (wn.segmentType()) { 5619 case Work::kHorizontalLine_Segment: 5620 pts = HCubicIntersect(wt.pts(), wn.left(), 5621 wn.right(), wn.y(), wn.xFlipped(), ts); 5622 debugShowCubicLineIntersection(pts, wt, wn, ts); 5623 break; 5624 case Work::kVerticalLine_Segment: 5625 pts = VCubicIntersect(wt.pts(), wn.top(), 5626 wn.bottom(), wn.x(), wn.yFlipped(), ts); 5627 debugShowCubicLineIntersection(pts, wt, wn, ts); 5628 break; 5629 case Work::kLine_Segment: { 5630 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts); 5631 debugShowCubicLineIntersection(pts, wt, wn, ts); 5632 break; 5633 } 5634 case Work::kQuad_Segment: { 5635 #if APPROXIMATE_CUBICS 5636 pts = CubicQuadIntersect(wt.pts(), wn.pts(), ts); 5637 debugShowCubicQuadIntersection(pts, wt, wn, ts); 5638 #else 5639 wn.promoteToCubic(); 5640 pts = CubicIntersect(wt.pts(), wn.cubic(), ts); 5641 debugShowCubicIntersection(pts, wt, wn, ts); 5642 #endif 5643 break; 5644 } 5645 case Work::kCubic_Segment: { 5646 pts = CubicIntersect(wt.pts(), wn.pts(), ts); 5647 debugShowCubicIntersection(pts, wt, wn, ts); 5648 break; 5649 } 5650 default: 5651 SkASSERT(0); 5652 } 5653 break; 5654 default: 5655 SkASSERT(0); 5656 } 5657 if (!foundCommonContour && pts > 0) { 5658 test->addCross(next); 5659 next->addCross(test); 5660 foundCommonContour = true; 5661 } 5662 // in addition to recording T values, record matching segment 5663 if (ts.unsortable()) { 5664 bool start = true; 5665 for (int pt = 0; pt < ts.used(); ++pt) { 5666 // FIXME: if unsortable, the other points to the original. This logic is 5667 // untested downstream. 5668 SkPoint point = ts.fPt[pt].asSkPoint(); 5669 int testTAt = wt.addUnsortableT(wt, start, point, ts.fT[swap][pt]); 5670 wt.addOtherT(testTAt, ts.fT[swap][pt], testTAt); 5671 testTAt = wn.addUnsortableT(wn, start ^ ts.fFlip, point, ts.fT[!swap][pt]); 5672 wn.addOtherT(testTAt, ts.fT[!swap][pt], testTAt); 5673 start ^= true; 5674 } 5675 continue; 5676 } 5677 if (pts == 2) { 5678 if (wn.segmentType() <= Work::kLine_Segment 5679 && wt.segmentType() <= Work::kLine_Segment) { 5680 wt.addCoincident(wn, ts, swap); 5681 continue; 5682 } 5683 if (wn.segmentType() >= Work::kQuad_Segment 5684 && wt.segmentType() >= Work::kQuad_Segment 5685 && ts.fIsCoincident[0]) { 5686 SkASSERT(ts.coincidentUsed() == 2); 5687 wt.addCoincident(wn, ts, swap); 5688 continue; 5689 } 5690 5691 } 5692 for (int pt = 0; pt < pts; ++pt) { 5693 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1); 5694 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1); 5695 SkPoint point = ts.fPt[pt].asSkPoint(); 5696 int testTAt = wt.addT(wn, point, ts.fT[swap][pt]); 5697 int nextTAt = wn.addT(wt, point, ts.fT[!swap][pt]); 5698 wt.addOtherT(testTAt, ts.fT[!swap][pt ^ ts.fFlip], nextTAt); 5699 wn.addOtherT(nextTAt, ts.fT[swap][pt ^ ts.fFlip], testTAt); 5700 } 5701 } while (wn.advance()); 5702 } while (wt.advance()); 5703 return true; 5704} 5705 5706static void addSelfIntersectTs(Contour* test) { 5707 Work wt; 5708 wt.init(test); 5709 do { 5710 if (wt.segmentType() != Work::kCubic_Segment) { 5711 continue; 5712 } 5713 Intersections ts; 5714 int pts = CubicIntersect(wt.pts(), ts); 5715 debugShowCubicIntersection(pts, wt, ts); 5716 if (!pts) { 5717 continue; 5718 } 5719 SkASSERT(pts == 1); 5720 SkASSERT(ts.fT[0][0] >= 0 && ts.fT[0][0] <= 1); 5721 SkASSERT(ts.fT[1][0] >= 0 && ts.fT[1][0] <= 1); 5722 SkPoint point = ts.fPt[0].asSkPoint(); 5723 int testTAt = wt.addSelfT(wt, point, ts.fT[0][0]); 5724 int nextTAt = wt.addT(wt, point, ts.fT[1][0]); 5725 wt.addOtherT(testTAt, ts.fT[1][0], nextTAt); 5726 wt.addOtherT(nextTAt, ts.fT[0][0], testTAt); 5727 } while (wt.advance()); 5728} 5729 5730// resolve any coincident pairs found while intersecting, and 5731// see if coincidence is formed by clipping non-concident segments 5732static void coincidenceCheck(SkTDArray<Contour*>& contourList, int total) { 5733 int contourCount = contourList.count(); 5734#if ONE_PASS_COINCIDENCE_CHECK 5735 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 5736 Contour* contour = contourList[cIndex]; 5737 contour->resolveCoincidence(contourList); 5738 } 5739#else 5740 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 5741 Contour* contour = contourList[cIndex]; 5742 contour->addCoincidentPoints(); 5743 } 5744 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 5745 Contour* contour = contourList[cIndex]; 5746 contour->calcCoincidentWinding(); 5747 } 5748#endif 5749 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 5750 Contour* contour = contourList[cIndex]; 5751 contour->findTooCloseToCall(); 5752 } 5753} 5754 5755static int contourRangeCheckY(SkTDArray<Contour*>& contourList, Segment*& current, int& index, 5756 int& endIndex, double& bestHit, SkScalar& bestDx, bool& tryAgain, double& mid, bool opp) { 5757 SkPoint basePt; 5758 double tAtMid = current->tAtMid(index, endIndex, mid); 5759 current->xyAtT(tAtMid, basePt); 5760 int contourCount = contourList.count(); 5761 SkScalar bestY = SK_ScalarMin; 5762 Segment* bestSeg = NULL; 5763 int bestTIndex; 5764 bool bestOpp; 5765 bool hitSomething = false; 5766 for (int cTest = 0; cTest < contourCount; ++cTest) { 5767 Contour* contour = contourList[cTest]; 5768 bool testOpp = contour->operand() ^ current->operand() ^ opp; 5769 if (basePt.fY < contour->bounds().fTop) { 5770 continue; 5771 } 5772 if (bestY > contour->bounds().fBottom) { 5773 continue; 5774 } 5775 int segmentCount = contour->segments().count(); 5776 for (int test = 0; test < segmentCount; ++test) { 5777 Segment* testSeg = &contour->segments()[test]; 5778 SkScalar testY = bestY; 5779 double testHit; 5780 int testTIndex = testSeg->crossedSpanY(basePt, testY, testHit, hitSomething, tAtMid, 5781 testOpp, testSeg == current); 5782 if (testTIndex < 0) { 5783 if (testTIndex == SK_MinS32) { 5784 hitSomething = true; 5785 bestSeg = NULL; 5786 goto abortContours; // vertical encountered, return and try different point 5787 } 5788 continue; 5789 } 5790 if (testSeg == current && current->betweenTs(index, testHit, endIndex)) { 5791 double baseT = current->t(index); 5792 double endT = current->t(endIndex); 5793 double newMid = (testHit - baseT) / (endT - baseT); 5794#if DEBUG_WINDING 5795 SkPoint midXY, newXY; 5796 double midT = current->tAtMid(index, endIndex, mid); 5797 current->xyAtT(midT, midXY); 5798 double newMidT = current->tAtMid(index, endIndex, newMid); 5799 current->xyAtT(newMidT, newXY); 5800 SkDebugf("%s [%d] mid=%1.9g->%1.9g s=%1.9g (%1.9g,%1.9g) m=%1.9g (%1.9g,%1.9g)" 5801 " n=%1.9g (%1.9g,%1.9g) e=%1.9g (%1.9g,%1.9g)\n", __FUNCTION__, 5802 current->debugID(), mid, newMid, 5803 baseT, current->xAtT(index), current->yAtT(index), 5804 baseT + mid * (endT - baseT), midXY.fX, midXY.fY, 5805 baseT + newMid * (endT - baseT), newXY.fX, newXY.fY, 5806 endT, current->xAtT(endIndex), current->yAtT(endIndex)); 5807#endif 5808 mid = newMid * 2; // calling loop with divide by 2 before continuing 5809 return SK_MinS32; 5810 } 5811 bestSeg = testSeg; 5812 bestHit = testHit; 5813 bestOpp = testOpp; 5814 bestTIndex = testTIndex; 5815 bestY = testY; 5816 } 5817 } 5818abortContours: 5819 int result; 5820 if (!bestSeg) { 5821 result = hitSomething ? SK_MinS32 : 0; 5822 } else { 5823 if (bestSeg->windSum(bestTIndex) == SK_MinS32) { 5824 current = bestSeg; 5825 index = bestTIndex; 5826 endIndex = bestSeg->nextSpan(bestTIndex, 1); 5827 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0); 5828 tryAgain = true; 5829 return 0; 5830 } 5831 result = bestSeg->windingAtT(bestHit, bestTIndex, bestOpp, bestDx); 5832 SkASSERT(bestDx); 5833 } 5834 double baseT = current->t(index); 5835 double endT = current->t(endIndex); 5836 bestHit = baseT + mid * (endT - baseT); 5837 return result; 5838} 5839 5840static Segment* findUndone(SkTDArray<Contour*>& contourList, int& start, int& end) { 5841 int contourCount = contourList.count(); 5842 Segment* result; 5843 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 5844 Contour* contour = contourList[cIndex]; 5845 result = contour->undoneSegment(start, end); 5846 if (result) { 5847 return result; 5848 } 5849 } 5850 return NULL; 5851} 5852 5853#define OLD_FIND_CHASE 1 5854 5855static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) { 5856 while (chase.count()) { 5857 Span* span; 5858 chase.pop(&span); 5859 const Span& backPtr = span->fOther->span(span->fOtherIndex); 5860 Segment* segment = backPtr.fOther; 5861 tIndex = backPtr.fOtherIndex; 5862 SkTDArray<Angle> angles; 5863 int done = 0; 5864 if (segment->activeAngle(tIndex, done, angles)) { 5865 Angle* last = angles.end() - 1; 5866 tIndex = last->start(); 5867 endIndex = last->end(); 5868 #if TRY_ROTATE 5869 *chase.insert(0) = span; 5870 #else 5871 *chase.append() = span; 5872 #endif 5873 return last->segment(); 5874 } 5875 if (done == angles.count()) { 5876 continue; 5877 } 5878 SkTDArray<Angle*> sorted; 5879 bool sortable = Segment::SortAngles(angles, sorted); 5880 int angleCount = sorted.count(); 5881#if DEBUG_SORT 5882 sorted[0]->segment()->debugShowSort(__FUNCTION__, sorted, 0, 0, 0); 5883#endif 5884 if (!sortable) { 5885 continue; 5886 } 5887 // find first angle, initialize winding to computed fWindSum 5888 int firstIndex = -1; 5889 const Angle* angle; 5890#if OLD_FIND_CHASE 5891 int winding; 5892 do { 5893 angle = sorted[++firstIndex]; 5894 segment = angle->segment(); 5895 winding = segment->windSum(angle); 5896 } while (winding == SK_MinS32); 5897 int spanWinding = segment->spanSign(angle->start(), angle->end()); 5898 #if DEBUG_WINDING 5899 SkDebugf("%s winding=%d spanWinding=%d\n", 5900 __FUNCTION__, winding, spanWinding); 5901 #endif 5902 // turn span winding into contour winding 5903 if (spanWinding * winding < 0) { 5904 winding += spanWinding; 5905 } 5906 #if DEBUG_SORT 5907 segment->debugShowSort(__FUNCTION__, sorted, firstIndex, winding, 0); 5908 #endif 5909 // we care about first sign and whether wind sum indicates this 5910 // edge is inside or outside. Maybe need to pass span winding 5911 // or first winding or something into this function? 5912 // advance to first undone angle, then return it and winding 5913 // (to set whether edges are active or not) 5914 int nextIndex = firstIndex + 1; 5915 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; 5916 angle = sorted[firstIndex]; 5917 winding -= angle->segment()->spanSign(angle); 5918#else 5919 do { 5920 angle = sorted[++firstIndex]; 5921 segment = angle->segment(); 5922 } while (segment->windSum(angle) == SK_MinS32); 5923 #if DEBUG_SORT 5924 segment->debugShowSort(__FUNCTION__, sorted, firstIndex); 5925 #endif 5926 int sumWinding = segment->updateWindingReverse(angle); 5927 int nextIndex = firstIndex + 1; 5928 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; 5929 Segment* first = NULL; 5930#endif 5931 do { 5932 SkASSERT(nextIndex != firstIndex); 5933 if (nextIndex == angleCount) { 5934 nextIndex = 0; 5935 } 5936 angle = sorted[nextIndex]; 5937 segment = angle->segment(); 5938#if OLD_FIND_CHASE 5939 int maxWinding = winding; 5940 winding -= segment->spanSign(angle); 5941 #if DEBUG_SORT 5942 SkDebugf("%s id=%d maxWinding=%d winding=%d sign=%d\n", __FUNCTION__, 5943 segment->debugID(), maxWinding, winding, angle->sign()); 5944 #endif 5945 tIndex = angle->start(); 5946 endIndex = angle->end(); 5947 int lesser = SkMin32(tIndex, endIndex); 5948 const Span& nextSpan = segment->span(lesser); 5949 if (!nextSpan.fDone) { 5950#if 1 5951 // FIXME: this be wrong? assign startWinding if edge is in 5952 // same direction. If the direction is opposite, winding to 5953 // assign is flipped sign or +/- 1? 5954 if (useInnerWinding(maxWinding, winding)) { 5955 maxWinding = winding; 5956 } 5957 segment->markAndChaseWinding(angle, maxWinding, 0); 5958#endif 5959 break; 5960 } 5961#else 5962 int start = angle->start(); 5963 int end = angle->end(); 5964 int maxWinding; 5965 segment->setUpWinding(start, end, maxWinding, sumWinding); 5966 if (!segment->done(angle)) { 5967 if (!first) { 5968 first = segment; 5969 tIndex = start; 5970 endIndex = end; 5971 } 5972 (void) segment->markAngle(maxWinding, sumWinding, true, angle); 5973 } 5974#endif 5975 } while (++nextIndex != lastIndex); 5976 #if TRY_ROTATE 5977 *chase.insert(0) = span; 5978 #else 5979 *chase.append() = span; 5980 #endif 5981 return segment; 5982 } 5983 return NULL; 5984} 5985 5986#if DEBUG_ACTIVE_SPANS 5987static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) { 5988 int index; 5989 for (index = 0; index < contourList.count(); ++ index) { 5990 contourList[index]->debugShowActiveSpans(); 5991 } 5992 for (index = 0; index < contourList.count(); ++ index) { 5993 contourList[index]->validateActiveSpans(); 5994 } 5995} 5996#endif 5997 5998static Segment* findSortableTop(SkTDArray<Contour*>& contourList, int& index, 5999 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool onlySortable) { 6000 Segment* result; 6001 do { 6002 SkPoint bestXY = {SK_ScalarMax, SK_ScalarMax}; 6003 int contourCount = contourList.count(); 6004 Segment* topStart = NULL; 6005 done = true; 6006 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 6007 Contour* contour = contourList[cIndex]; 6008 if (contour->done()) { 6009 continue; 6010 } 6011 const Bounds& bounds = contour->bounds(); 6012 if (bounds.fBottom < topLeft.fY) { 6013 done = false; 6014 continue; 6015 } 6016 if (bounds.fBottom == topLeft.fY && bounds.fRight < topLeft.fX) { 6017 done = false; 6018 continue; 6019 } 6020 contour->topSortableSegment(topLeft, bestXY, topStart); 6021 if (!contour->done()) { 6022 done = false; 6023 } 6024 } 6025 if (!topStart) { 6026 return NULL; 6027 } 6028 topLeft = bestXY; 6029 result = topStart->findTop(index, endIndex, unsortable, onlySortable); 6030 } while (!result); 6031 return result; 6032} 6033 6034static int rightAngleWinding(SkTDArray<Contour*>& contourList, 6035 Segment*& current, int& index, int& endIndex, double& tHit, SkScalar& hitDx, bool& tryAgain, 6036 bool opp) { 6037 double test = 0.9; 6038 int contourWinding; 6039 do { 6040 contourWinding = contourRangeCheckY(contourList, current, index, endIndex, tHit, hitDx, 6041 tryAgain, test, opp); 6042 if (contourWinding != SK_MinS32 || tryAgain) { 6043 return contourWinding; 6044 } 6045 test /= 2; 6046 } while (!approximately_negative(test)); 6047 SkASSERT(0); // should be OK to comment out, but interested when this hits 6048 return contourWinding; 6049} 6050 6051static void skipVertical(SkTDArray<Contour*>& contourList, 6052 Segment*& current, int& index, int& endIndex) { 6053 if (!current->isVertical(index, endIndex)) { 6054 return; 6055 } 6056 int contourCount = contourList.count(); 6057 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 6058 Contour* contour = contourList[cIndex]; 6059 if (contour->done()) { 6060 continue; 6061 } 6062 current = contour->nonVerticalSegment(index, endIndex); 6063 if (current) { 6064 return; 6065 } 6066 } 6067} 6068 6069static Segment* findSortableTop(SkTDArray<Contour*>& contourList, bool& firstContour, int& index, 6070 int& endIndex, SkPoint& topLeft, bool& unsortable, bool& done, bool binary) { 6071 Segment* current = findSortableTop(contourList, index, endIndex, topLeft, unsortable, done, 6072 true); 6073 if (!current) { 6074 return NULL; 6075 } 6076 if (firstContour) { 6077 current->initWinding(index, endIndex); 6078 firstContour = false; 6079 return current; 6080 } 6081 int minIndex = SkMin32(index, endIndex); 6082 int sumWinding = current->windSum(minIndex); 6083 if (sumWinding != SK_MinS32) { 6084 return current; 6085 } 6086 sumWinding = current->computeSum(index, endIndex, binary); 6087 if (sumWinding != SK_MinS32) { 6088 return current; 6089 } 6090 int contourWinding; 6091 int oppContourWinding = 0; 6092 // the simple upward projection of the unresolved points hit unsortable angles 6093 // shoot rays at right angles to the segment to find its winding, ignoring angle cases 6094 bool tryAgain; 6095 double tHit; 6096 SkScalar hitDx = 0; 6097 SkScalar hitOppDx = 0; 6098 do { 6099 // if current is vertical, find another candidate which is not 6100 // if only remaining candidates are vertical, then they can be marked done 6101 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0); 6102 skipVertical(contourList, current, index, endIndex); 6103 SkASSERT(index != endIndex && index >= 0 && endIndex >= 0); 6104 tryAgain = false; 6105 contourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitDx, 6106 tryAgain, false); 6107 if (tryAgain) { 6108 continue; 6109 } 6110 if (!binary) { 6111 break; 6112 } 6113 oppContourWinding = rightAngleWinding(contourList, current, index, endIndex, tHit, hitOppDx, 6114 tryAgain, true); 6115 } while (tryAgain); 6116 6117 current->initWinding(index, endIndex, tHit, contourWinding, hitDx, oppContourWinding, hitOppDx); 6118 return current; 6119} 6120 6121// rewrite that abandons keeping local track of winding 6122static bool bridgeWinding(SkTDArray<Contour*>& contourList, PathWrapper& simple) { 6123 bool firstContour = true; 6124 bool unsortable = false; 6125 bool topUnsortable = false; 6126 SkPoint topLeft = {SK_ScalarMin, SK_ScalarMin}; 6127 do { 6128 int index, endIndex; 6129 bool topDone; 6130 Segment* current = findSortableTop(contourList, firstContour, index, endIndex, topLeft, 6131 topUnsortable, topDone, false); 6132 if (!current) { 6133 if (topUnsortable || !topDone) { 6134 topUnsortable = false; 6135 SkASSERT(topLeft.fX != SK_ScalarMin && topLeft.fY != SK_ScalarMin); 6136 topLeft.fX = topLeft.fY = SK_ScalarMin; 6137 continue; 6138 } 6139 break; 6140 } 6141 SkTDArray<Span*> chaseArray; 6142 do { 6143 if (current->activeWinding(index, endIndex)) { 6144 do { 6145 #if DEBUG_ACTIVE_SPANS 6146 if (!unsortable && current->done()) { 6147 debugShowActiveSpans(contourList); 6148 } 6149 #endif 6150 SkASSERT(unsortable || !current->done()); 6151 int nextStart = index; 6152 int nextEnd = endIndex; 6153 Segment* next = current->findNextWinding(chaseArray, nextStart, nextEnd, 6154 unsortable); 6155 if (!next) { 6156 if (!unsortable && simple.hasMove() 6157 && current->verb() != SkPath::kLine_Verb 6158 && !simple.isClosed()) { 6159 current->addCurveTo(index, endIndex, simple, true); 6160 SkASSERT(simple.isClosed()); 6161 } 6162 break; 6163 } 6164 #if DEBUG_FLOW 6165 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__, 6166 current->debugID(), current->xyAtT(index).fX, current->xyAtT(index).fY, 6167 current->xyAtT(endIndex).fX, current->xyAtT(endIndex).fY); 6168 #endif 6169 current->addCurveTo(index, endIndex, simple, true); 6170 current = next; 6171 index = nextStart; 6172 endIndex = nextEnd; 6173 } while (!simple.isClosed() && (!unsortable 6174 || !current->done(SkMin32(index, endIndex)))); 6175 if (current->activeWinding(index, endIndex) && !simple.isClosed()) { 6176 SkASSERT(unsortable); 6177 int min = SkMin32(index, endIndex); 6178 if (!current->done(min)) { 6179 current->addCurveTo(index, endIndex, simple, true); 6180 current->markDoneUnary(min); 6181 } 6182 } 6183 simple.close(); 6184 } else { 6185 Span* last = current->markAndChaseDoneUnary(index, endIndex); 6186 if (last && !last->fLoop) { 6187 *chaseArray.append() = last; 6188 } 6189 } 6190 current = findChase(chaseArray, index, endIndex); 6191 #if DEBUG_ACTIVE_SPANS 6192 debugShowActiveSpans(contourList); 6193 #endif 6194 if (!current) { 6195 break; 6196 } 6197 } while (true); 6198 } while (true); 6199 return simple.someAssemblyRequired(); 6200} 6201 6202// returns true if all edges were processed 6203static bool bridgeXor(SkTDArray<Contour*>& contourList, PathWrapper& simple) { 6204 Segment* current; 6205 int start, end; 6206 bool unsortable = false; 6207 bool closable = true; 6208 while ((current = findUndone(contourList, start, end))) { 6209 do { 6210 #if DEBUG_ACTIVE_SPANS 6211 if (!unsortable && current->done()) { 6212 debugShowActiveSpans(contourList); 6213 } 6214 #endif 6215 SkASSERT(unsortable || !current->done()); 6216 int nextStart = start; 6217 int nextEnd = end; 6218 Segment* next = current->findNextXor(nextStart, nextEnd, unsortable); 6219 if (!next) { 6220 if (!unsortable && simple.hasMove() 6221 && current->verb() != SkPath::kLine_Verb 6222 && !simple.isClosed()) { 6223 current->addCurveTo(start, end, simple, true); 6224 SkASSERT(simple.isClosed()); 6225 } 6226 break; 6227 } 6228 #if DEBUG_FLOW 6229 SkDebugf("%s current id=%d from=(%1.9g,%1.9g) to=(%1.9g,%1.9g)\n", __FUNCTION__, 6230 current->debugID(), current->xyAtT(start).fX, current->xyAtT(start).fY, 6231 current->xyAtT(end).fX, current->xyAtT(end).fY); 6232 #endif 6233 current->addCurveTo(start, end, simple, true); 6234 current = next; 6235 start = nextStart; 6236 end = nextEnd; 6237 } while (!simple.isClosed() && (!unsortable || !current->done(SkMin32(start, end)))); 6238 if (!simple.isClosed()) { 6239 SkASSERT(unsortable); 6240 int min = SkMin32(start, end); 6241 if (!current->done(min)) { 6242 current->addCurveTo(start, end, simple, true); 6243 current->markDone(min, 1); 6244 } 6245 closable = false; 6246 } 6247 simple.close(); 6248 #if DEBUG_ACTIVE_SPANS 6249 debugShowActiveSpans(contourList); 6250 #endif 6251 } 6252 return closable; 6253} 6254 6255static void fixOtherTIndex(SkTDArray<Contour*>& contourList) { 6256 int contourCount = contourList.count(); 6257 for (int cTest = 0; cTest < contourCount; ++cTest) { 6258 Contour* contour = contourList[cTest]; 6259 contour->fixOtherTIndex(); 6260 } 6261} 6262 6263static void sortSegments(SkTDArray<Contour*>& contourList) { 6264 int contourCount = contourList.count(); 6265 for (int cTest = 0; cTest < contourCount; ++cTest) { 6266 Contour* contour = contourList[cTest]; 6267 contour->sortSegments(); 6268 } 6269} 6270 6271static void makeContourList(SkTArray<Contour>& contours, SkTDArray<Contour*>& list, 6272 bool evenOdd, bool oppEvenOdd) { 6273 int count = contours.count(); 6274 if (count == 0) { 6275 return; 6276 } 6277 for (int index = 0; index < count; ++index) { 6278 Contour& contour = contours[index]; 6279 contour.setOppXor(contour.operand() ? evenOdd : oppEvenOdd); 6280 *list.append() = &contour; 6281 } 6282 QSort<Contour>(list.begin(), list.end() - 1); 6283} 6284 6285static bool approximatelyEqual(const SkPoint& a, const SkPoint& b) { 6286 return AlmostEqualUlps(a.fX, b.fX) && AlmostEqualUlps(a.fY, b.fY); 6287} 6288 6289static bool lessThan(SkTDArray<double>& distances, const int one, const int two) { 6290 return distances[one] < distances[two]; 6291} 6292 /* 6293 check start and end of each contour 6294 if not the same, record them 6295 match them up 6296 connect closest 6297 reassemble contour pieces into new path 6298 */ 6299static void assemble(const PathWrapper& path, PathWrapper& simple) { 6300#if DEBUG_PATH_CONSTRUCTION 6301 SkDebugf("%s\n", __FUNCTION__); 6302#endif 6303 SkTArray<Contour> contours; 6304 EdgeBuilder builder(path, contours); 6305 builder.finish(); 6306 int count = contours.count(); 6307 int outer; 6308 SkTDArray<int> runs; // indices of partial contours 6309 for (outer = 0; outer < count; ++outer) { 6310 const Contour& eContour = contours[outer]; 6311 const SkPoint& eStart = eContour.start(); 6312 const SkPoint& eEnd = eContour.end(); 6313#if DEBUG_ASSEMBLE 6314 SkDebugf("%s contour", __FUNCTION__); 6315 if (!approximatelyEqual(eStart, eEnd)) { 6316 SkDebugf("[%d]", runs.count()); 6317 } else { 6318 SkDebugf(" "); 6319 } 6320 SkDebugf(" start=(%1.9g,%1.9g) end=(%1.9g,%1.9g)\n", 6321 eStart.fX, eStart.fY, eEnd.fX, eEnd.fY); 6322#endif 6323 if (approximatelyEqual(eStart, eEnd)) { 6324 eContour.toPath(simple); 6325 continue; 6326 } 6327 *runs.append() = outer; 6328 } 6329 count = runs.count(); 6330 if (count == 0) { 6331 return; 6332 } 6333 SkTDArray<int> sLink, eLink; 6334 sLink.setCount(count); 6335 eLink.setCount(count); 6336 int rIndex, iIndex; 6337 for (rIndex = 0; rIndex < count; ++rIndex) { 6338 sLink[rIndex] = eLink[rIndex] = SK_MaxS32; 6339 } 6340 SkTDArray<double> distances; 6341 const int ends = count * 2; // all starts and ends 6342 const int entries = (ends - 1) * count; // folded triangle : n * (n - 1) / 2 6343 distances.setCount(entries); 6344 for (rIndex = 0; rIndex < ends - 1; ++rIndex) { 6345 outer = runs[rIndex >> 1]; 6346 const Contour& oContour = contours[outer]; 6347 const SkPoint& oPt = rIndex & 1 ? oContour.end() : oContour.start(); 6348 const int row = rIndex < count - 1 ? rIndex * ends : (ends - rIndex - 2) 6349 * ends - rIndex - 1; 6350 for (iIndex = rIndex + 1; iIndex < ends; ++iIndex) { 6351 int inner = runs[iIndex >> 1]; 6352 const Contour& iContour = contours[inner]; 6353 const SkPoint& iPt = iIndex & 1 ? iContour.end() : iContour.start(); 6354 double dx = iPt.fX - oPt.fX; 6355 double dy = iPt.fY - oPt.fY; 6356 double dist = dx * dx + dy * dy; 6357 distances[row + iIndex] = dist; // oStart distance from iStart 6358 } 6359 } 6360 SkTDArray<int> sortedDist; 6361 sortedDist.setCount(entries); 6362 for (rIndex = 0; rIndex < entries; ++rIndex) { 6363 sortedDist[rIndex] = rIndex; 6364 } 6365 QSort<SkTDArray<double>, int>(distances, sortedDist.begin(), sortedDist.end() - 1, lessThan); 6366 int remaining = count; // number of start/end pairs 6367 for (rIndex = 0; rIndex < entries; ++rIndex) { 6368 int pair = sortedDist[rIndex]; 6369 int row = pair / ends; 6370 int col = pair - row * ends; 6371 int thingOne = row < col ? row : ends - row - 2; 6372 int ndxOne = thingOne >> 1; 6373 bool endOne = thingOne & 1; 6374 int* linkOne = endOne ? eLink.begin() : sLink.begin(); 6375 if (linkOne[ndxOne] != SK_MaxS32) { 6376 continue; 6377 } 6378 int thingTwo = row < col ? col : ends - row + col - 1; 6379 int ndxTwo = thingTwo >> 1; 6380 bool endTwo = thingTwo & 1; 6381 int* linkTwo = endTwo ? eLink.begin() : sLink.begin(); 6382 if (linkTwo[ndxTwo] != SK_MaxS32) { 6383 continue; 6384 } 6385 SkASSERT(&linkOne[ndxOne] != &linkTwo[ndxTwo]); 6386 bool flip = endOne == endTwo; 6387 linkOne[ndxOne] = flip ? ~ndxTwo : ndxTwo; 6388 linkTwo[ndxTwo] = flip ? ~ndxOne : ndxOne; 6389 if (!--remaining) { 6390 break; 6391 } 6392 } 6393 SkASSERT(!remaining); 6394#if DEBUG_ASSEMBLE 6395 for (rIndex = 0; rIndex < count; ++rIndex) { 6396 int s = sLink[rIndex]; 6397 int e = eLink[rIndex]; 6398 SkDebugf("%s %c%d <- s%d - e%d -> %c%d\n", __FUNCTION__, s < 0 ? 's' : 'e', 6399 s < 0 ? ~s : s, rIndex, rIndex, e < 0 ? 'e' : 's', e < 0 ? ~e : e); 6400 } 6401#endif 6402 rIndex = 0; 6403 do { 6404 bool forward = true; 6405 bool first = true; 6406 int sIndex = sLink[rIndex]; 6407 SkASSERT(sIndex != SK_MaxS32); 6408 sLink[rIndex] = SK_MaxS32; 6409 int eIndex; 6410 if (sIndex < 0) { 6411 eIndex = sLink[~sIndex]; 6412 sLink[~sIndex] = SK_MaxS32; 6413 } else { 6414 eIndex = eLink[sIndex]; 6415 eLink[sIndex] = SK_MaxS32; 6416 } 6417 SkASSERT(eIndex != SK_MaxS32); 6418#if DEBUG_ASSEMBLE 6419 SkDebugf("%s sIndex=%c%d eIndex=%c%d\n", __FUNCTION__, sIndex < 0 ? 's' : 'e', 6420 sIndex < 0 ? ~sIndex : sIndex, eIndex < 0 ? 's' : 'e', 6421 eIndex < 0 ? ~eIndex : eIndex); 6422#endif 6423 do { 6424 outer = runs[rIndex]; 6425 const Contour& contour = contours[outer]; 6426 if (first) { 6427 first = false; 6428 const SkPoint* startPtr = &contour.start(); 6429 simple.deferredMove(startPtr[0]); 6430 } 6431 if (forward) { 6432 contour.toPartialForward(simple); 6433 } else { 6434 contour.toPartialBackward(simple); 6435 } 6436#if DEBUG_ASSEMBLE 6437 SkDebugf("%s rIndex=%d eIndex=%s%d close=%d\n", __FUNCTION__, rIndex, 6438 eIndex < 0 ? "~" : "", eIndex < 0 ? ~eIndex : eIndex, 6439 sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)); 6440#endif 6441 if (sIndex == ((rIndex != eIndex) ^ forward ? eIndex : ~eIndex)) { 6442 simple.close(); 6443 break; 6444 } 6445 if (forward) { 6446 eIndex = eLink[rIndex]; 6447 SkASSERT(eIndex != SK_MaxS32); 6448 eLink[rIndex] = SK_MaxS32; 6449 if (eIndex >= 0) { 6450 SkASSERT(sLink[eIndex] == rIndex); 6451 sLink[eIndex] = SK_MaxS32; 6452 } else { 6453 SkASSERT(eLink[~eIndex] == ~rIndex); 6454 eLink[~eIndex] = SK_MaxS32; 6455 } 6456 } else { 6457 eIndex = sLink[rIndex]; 6458 SkASSERT(eIndex != SK_MaxS32); 6459 sLink[rIndex] = SK_MaxS32; 6460 if (eIndex >= 0) { 6461 SkASSERT(eLink[eIndex] == rIndex); 6462 eLink[eIndex] = SK_MaxS32; 6463 } else { 6464 SkASSERT(sLink[~eIndex] == ~rIndex); 6465 sLink[~eIndex] = SK_MaxS32; 6466 } 6467 } 6468 rIndex = eIndex; 6469 if (rIndex < 0) { 6470 forward ^= 1; 6471 rIndex = ~rIndex; 6472 } 6473 } while (true); 6474 for (rIndex = 0; rIndex < count; ++rIndex) { 6475 if (sLink[rIndex] != SK_MaxS32) { 6476 break; 6477 } 6478 } 6479 } while (rIndex < count); 6480#if DEBUG_ASSEMBLE 6481 for (rIndex = 0; rIndex < count; ++rIndex) { 6482 SkASSERT(sLink[rIndex] == SK_MaxS32); 6483 SkASSERT(eLink[rIndex] == SK_MaxS32); 6484 } 6485#endif 6486} 6487 6488void simplifyx(const SkPath& path, SkPath& result) { 6489#if DEBUG_SORT 6490 gDebugSortCount = gDebugSortCountDefault; 6491#endif 6492 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness 6493 result.reset(); 6494 result.setFillType(SkPath::kEvenOdd_FillType); 6495 PathWrapper simple(result); 6496 6497 // turn path into list of segments 6498 SkTArray<Contour> contours; 6499 EdgeBuilder builder(path, contours); 6500 builder.finish(); 6501 SkTDArray<Contour*> contourList; 6502 makeContourList(contours, contourList, false, false); 6503 Contour** currentPtr = contourList.begin(); 6504 if (!currentPtr) { 6505 return; 6506 } 6507 Contour** listEnd = contourList.end(); 6508 // find all intersections between segments 6509 do { 6510 Contour** nextPtr = currentPtr; 6511 Contour* current = *currentPtr++; 6512 if (current->containsCubics()) { 6513 addSelfIntersectTs(current); 6514 } 6515 Contour* next; 6516 do { 6517 next = *nextPtr++; 6518 } while (addIntersectTs(current, next) && nextPtr != listEnd); 6519 } while (currentPtr != listEnd); 6520 // eat through coincident edges 6521 coincidenceCheck(contourList, 0); 6522 fixOtherTIndex(contourList); 6523 sortSegments(contourList); 6524#if DEBUG_ACTIVE_SPANS 6525 debugShowActiveSpans(contourList); 6526#endif 6527 // construct closed contours 6528 if (builder.xorMask() == kWinding_Mask ? bridgeWinding(contourList, simple) 6529 : !bridgeXor(contourList, simple)) 6530 { // if some edges could not be resolved, assemble remaining fragments 6531 SkPath temp; 6532 temp.setFillType(SkPath::kEvenOdd_FillType); 6533 PathWrapper assembled(temp); 6534 assemble(simple, assembled); 6535 result = *assembled.nativePath(); 6536 } 6537} 6538