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