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