Simplify.cpp revision 9764cc6c109dba208592fe5f16447b8439375746
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 21// FIXME: remove once debugging is complete 22#if 0 // set to 1 for no debugging whatsoever 23 24//const bool gxRunTestsInOneThread = false; 25 26#define DEBUG_ADD_INTERSECTING_TS 0 27#define DEBUG_BRIDGE 0 28#define DEBUG_CROSS 0 29#define DEBUG_DUMP 0 30#define DEBUG_PATH_CONSTRUCTION 0 31#define DEBUG_ACTIVE_SPANS 0 32#define DEBUG_WINDING 0 33#define DEBUG_UNUSED 0 // set to expose unused functions 34#define DEBUG_MARK_DONE 0 35 36#else 37 38//const bool gRunTestsInOneThread = true; 39 40#define DEBUG_ADD_INTERSECTING_TS 0 41#define DEBUG_BRIDGE 1 42#define DEBUG_CROSS 1 43#define DEBUG_DUMP 1 44#define DEBUG_PATH_CONSTRUCTION 1 45#define DEBUG_ACTIVE_SPANS 0 46#define DEBUG_WINDING 0 47#define DEBUG_UNUSED 0 // set to expose unused functions 48#define DEBUG_MARK_DONE 0 49 50#endif 51 52#if DEBUG_ACTIVE_SPANS && !DEBUG_DUMP 53#undef DEBUG_DUMP 54#define DEBUG_DUMP 1 55#endif 56 57#if DEBUG_DUMP 58static const char* kLVerbStr[] = {"", "line", "quad", "cubic"}; 59// static const char* kUVerbStr[] = {"", "Line", "Quad", "Cubic"}; 60static int gContourID; 61static int gSegmentID; 62#endif 63 64#ifndef DEBUG_TEST 65#define DEBUG_TEST 0 66#endif 67 68static int LineIntersect(const SkPoint a[2], const SkPoint b[2], 69 Intersections& intersections) { 70 const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}}; 71 const _Line bLine = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}}; 72 return intersect(aLine, bLine, intersections.fT[0], intersections.fT[1]); 73} 74 75static int QuadLineIntersect(const SkPoint a[3], const SkPoint b[2], 76 Intersections& intersections) { 77 const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}}; 78 const _Line bLine = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}}; 79 intersect(aQuad, bLine, intersections); 80 return intersections.fUsed; 81} 82 83static int CubicLineIntersect(const SkPoint a[2], const SkPoint b[3], 84 Intersections& intersections) { 85 const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}, 86 {a[3].fX, a[3].fY}}; 87 const _Line bLine = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}}; 88 return intersect(aCubic, bLine, intersections.fT[0], intersections.fT[1]); 89} 90 91static int QuadIntersect(const SkPoint a[3], const SkPoint b[3], 92 Intersections& intersections) { 93 const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}}; 94 const Quadratic bQuad = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}, {b[2].fX, b[2].fY}}; 95 intersect(aQuad, bQuad, intersections); 96 return intersections.fUsed; 97} 98 99static int CubicIntersect(const SkPoint a[4], const SkPoint b[4], 100 Intersections& intersections) { 101 const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}, 102 {a[3].fX, a[3].fY}}; 103 const Cubic bCubic = {{b[0].fX, b[0].fY}, {b[1].fX, b[1].fY}, {b[2].fX, b[2].fY}, 104 {b[3].fX, b[3].fY}}; 105 intersect(aCubic, bCubic, intersections); 106 return intersections.fUsed; 107} 108 109static int HLineIntersect(const SkPoint a[2], SkScalar left, SkScalar right, 110 SkScalar y, bool flipped, Intersections& intersections) { 111 const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}}; 112 return horizontalIntersect(aLine, left, right, y, flipped, intersections); 113} 114 115static int HQuadIntersect(const SkPoint a[3], SkScalar left, SkScalar right, 116 SkScalar y, bool flipped, Intersections& intersections) { 117 const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}}; 118 return horizontalIntersect(aQuad, left, right, y, flipped, intersections); 119} 120 121static int HCubicIntersect(const SkPoint a[4], SkScalar left, SkScalar right, 122 SkScalar y, bool flipped, Intersections& intersections) { 123 const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}, 124 {a[3].fX, a[3].fY}}; 125 return horizontalIntersect(aCubic, left, right, y, flipped, intersections); 126} 127 128static int VLineIntersect(const SkPoint a[2], SkScalar top, SkScalar bottom, 129 SkScalar x, bool flipped, Intersections& intersections) { 130 const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}}; 131 return verticalIntersect(aLine, top, bottom, x, flipped, intersections); 132} 133 134static int VQuadIntersect(const SkPoint a[3], SkScalar top, SkScalar bottom, 135 SkScalar x, bool flipped, Intersections& intersections) { 136 const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}}; 137 return verticalIntersect(aQuad, top, bottom, x, flipped, intersections); 138} 139 140static int VCubicIntersect(const SkPoint a[4], SkScalar top, SkScalar bottom, 141 SkScalar x, bool flipped, Intersections& intersections) { 142 const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}, 143 {a[3].fX, a[3].fY}}; 144 return verticalIntersect(aCubic, top, bottom, x, flipped, intersections); 145} 146 147static int (* const VSegmentIntersect[])(const SkPoint [], SkScalar , 148 SkScalar , SkScalar , bool , Intersections& ) = { 149 NULL, 150 VLineIntersect, 151 VQuadIntersect, 152 VCubicIntersect 153}; 154 155static void LineXYAtT(const SkPoint a[2], double t, SkPoint* out) { 156 const _Line line = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}}; 157 double x, y; 158 xy_at_t(line, t, x, y); 159 out->fX = SkDoubleToScalar(x); 160 out->fY = SkDoubleToScalar(y); 161} 162 163static void QuadXYAtT(const SkPoint a[3], double t, SkPoint* out) { 164 const Quadratic quad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}}; 165 double x, y; 166 xy_at_t(quad, t, x, y); 167 out->fX = SkDoubleToScalar(x); 168 out->fY = SkDoubleToScalar(y); 169} 170 171static void CubicXYAtT(const SkPoint a[4], double t, SkPoint* out) { 172 const Cubic cubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}, 173 {a[3].fX, a[3].fY}}; 174 double x, y; 175 xy_at_t(cubic, t, x, y); 176 out->fX = SkDoubleToScalar(x); 177 out->fY = SkDoubleToScalar(y); 178} 179 180static void (* const SegmentXYAtT[])(const SkPoint [], double , SkPoint* ) = { 181 NULL, 182 LineXYAtT, 183 QuadXYAtT, 184 CubicXYAtT 185}; 186 187static SkScalar LineXAtT(const SkPoint a[2], double t) { 188 const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}}; 189 double x; 190 xy_at_t(aLine, t, x, *(double*) 0); 191 return SkDoubleToScalar(x); 192} 193 194static SkScalar QuadXAtT(const SkPoint a[3], double t) { 195 const Quadratic quad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}}; 196 double x; 197 xy_at_t(quad, t, x, *(double*) 0); 198 return SkDoubleToScalar(x); 199} 200 201static SkScalar CubicXAtT(const SkPoint a[4], double t) { 202 const Cubic cubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}, 203 {a[3].fX, a[3].fY}}; 204 double x; 205 xy_at_t(cubic, t, x, *(double*) 0); 206 return SkDoubleToScalar(x); 207} 208 209static SkScalar (* const SegmentXAtT[])(const SkPoint [], double ) = { 210 NULL, 211 LineXAtT, 212 QuadXAtT, 213 CubicXAtT 214}; 215 216static SkScalar LineYAtT(const SkPoint a[2], double t) { 217 const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}}; 218 double y; 219 xy_at_t(aLine, t, *(double*) 0, y); 220 return SkDoubleToScalar(y); 221} 222 223static SkScalar QuadYAtT(const SkPoint a[3], double t) { 224 const Quadratic quad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}}; 225 double y; 226 xy_at_t(quad, t, *(double*) 0, y); 227 return SkDoubleToScalar(y); 228} 229 230static SkScalar CubicYAtT(const SkPoint a[4], double t) { 231 const Cubic cubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}, 232 {a[3].fX, a[3].fY}}; 233 double y; 234 xy_at_t(cubic, t, *(double*) 0, y); 235 return SkDoubleToScalar(y); 236} 237 238static SkScalar (* const SegmentYAtT[])(const SkPoint [], double ) = { 239 NULL, 240 LineYAtT, 241 QuadYAtT, 242 CubicYAtT 243}; 244 245static SkScalar LineDXAtT(const SkPoint a[2], double ) { 246 return a[1].fX - a[0].fX; 247} 248 249static SkScalar QuadDXAtT(const SkPoint a[3], double t) { 250 const Quadratic quad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}}; 251 double x; 252 dxdy_at_t(quad, t, x, *(double*) 0); 253 return SkDoubleToScalar(x); 254} 255 256static SkScalar CubicDXAtT(const SkPoint a[4], double t) { 257 const Cubic cubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, {a[2].fX, a[2].fY}, 258 {a[3].fX, a[3].fY}}; 259 double x; 260 dxdy_at_t(cubic, t, x, *(double*) 0); 261 return SkDoubleToScalar(x); 262} 263 264static SkScalar (* const SegmentDXAtT[])(const SkPoint [], double ) = { 265 NULL, 266 LineDXAtT, 267 QuadDXAtT, 268 CubicDXAtT 269}; 270 271static void LineSubDivide(const SkPoint a[2], double startT, double endT, 272 SkPoint sub[2]) { 273 const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}}; 274 _Line dst; 275 sub_divide(aLine, startT, endT, dst); 276 sub[0].fX = SkDoubleToScalar(dst[0].x); 277 sub[0].fY = SkDoubleToScalar(dst[0].y); 278 sub[1].fX = SkDoubleToScalar(dst[1].x); 279 sub[1].fY = SkDoubleToScalar(dst[1].y); 280} 281 282static void QuadSubDivide(const SkPoint a[3], double startT, double endT, 283 SkPoint sub[3]) { 284 const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, 285 {a[2].fX, a[2].fY}}; 286 Quadratic dst; 287 sub_divide(aQuad, startT, endT, dst); 288 sub[0].fX = SkDoubleToScalar(dst[0].x); 289 sub[0].fY = SkDoubleToScalar(dst[0].y); 290 sub[1].fX = SkDoubleToScalar(dst[1].x); 291 sub[1].fY = SkDoubleToScalar(dst[1].y); 292 sub[2].fX = SkDoubleToScalar(dst[2].x); 293 sub[2].fY = SkDoubleToScalar(dst[2].y); 294} 295 296static void CubicSubDivide(const SkPoint a[4], double startT, double endT, 297 SkPoint sub[4]) { 298 const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, 299 {a[2].fX, a[2].fY}, {a[3].fX, a[3].fY}}; 300 Cubic dst; 301 sub_divide(aCubic, startT, endT, dst); 302 sub[0].fX = SkDoubleToScalar(dst[0].x); 303 sub[0].fY = SkDoubleToScalar(dst[0].y); 304 sub[1].fX = SkDoubleToScalar(dst[1].x); 305 sub[1].fY = SkDoubleToScalar(dst[1].y); 306 sub[2].fX = SkDoubleToScalar(dst[2].x); 307 sub[2].fY = SkDoubleToScalar(dst[2].y); 308 sub[3].fX = SkDoubleToScalar(dst[3].x); 309 sub[3].fY = SkDoubleToScalar(dst[3].y); 310} 311 312static void (* const SegmentSubDivide[])(const SkPoint [], double , double , 313 SkPoint []) = { 314 NULL, 315 LineSubDivide, 316 QuadSubDivide, 317 CubicSubDivide 318}; 319 320#if DEBUG_UNUSED 321static void QuadSubBounds(const SkPoint a[3], double startT, double endT, 322 SkRect& bounds) { 323 SkPoint dst[3]; 324 QuadSubDivide(a, startT, endT, dst); 325 bounds.fLeft = bounds.fRight = dst[0].fX; 326 bounds.fTop = bounds.fBottom = dst[0].fY; 327 for (int index = 1; index < 3; ++index) { 328 bounds.growToInclude(dst[index].fX, dst[index].fY); 329 } 330} 331 332static void CubicSubBounds(const SkPoint a[4], double startT, double endT, 333 SkRect& bounds) { 334 SkPoint dst[4]; 335 CubicSubDivide(a, startT, endT, dst); 336 bounds.fLeft = bounds.fRight = dst[0].fX; 337 bounds.fTop = bounds.fBottom = dst[0].fY; 338 for (int index = 1; index < 4; ++index) { 339 bounds.growToInclude(dst[index].fX, dst[index].fY); 340 } 341} 342#endif 343 344static SkPath::Verb QuadReduceOrder(const SkPoint a[3], 345 SkTDArray<SkPoint>& reducePts) { 346 const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, 347 {a[2].fX, a[2].fY}}; 348 Quadratic dst; 349 int order = reduceOrder(aQuad, dst); 350 if (order == 3) { 351 return SkPath::kQuad_Verb; 352 } 353 for (int index = 0; index < order; ++index) { 354 SkPoint* pt = reducePts.append(); 355 pt->fX = SkDoubleToScalar(dst[index].x); 356 pt->fY = SkDoubleToScalar(dst[index].y); 357 } 358 return (SkPath::Verb) (order - 1); 359} 360 361static SkPath::Verb CubicReduceOrder(const SkPoint a[4], 362 SkTDArray<SkPoint>& reducePts) { 363 const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, 364 {a[2].fX, a[2].fY}, {a[3].fX, a[3].fY}}; 365 Cubic dst; 366 int order = reduceOrder(aCubic, dst, kReduceOrder_QuadraticsAllowed); 367 if (order == 4) { 368 return SkPath::kCubic_Verb; 369 } 370 for (int index = 0; index < order; ++index) { 371 SkPoint* pt = reducePts.append(); 372 pt->fX = SkDoubleToScalar(dst[index].x); 373 pt->fY = SkDoubleToScalar(dst[index].y); 374 } 375 return (SkPath::Verb) (order - 1); 376} 377 378static bool QuadIsLinear(const SkPoint a[3]) { 379 const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, 380 {a[2].fX, a[2].fY}}; 381 return isLinear(aQuad, 0, 2); 382} 383 384static bool CubicIsLinear(const SkPoint a[4]) { 385 const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, 386 {a[2].fX, a[2].fY}, {a[3].fX, a[3].fY}}; 387 return isLinear(aCubic, 0, 3); 388} 389 390static SkScalar LineLeftMost(const SkPoint a[2], double startT, double endT) { 391 const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}}; 392 double x[2]; 393 xy_at_t(aLine, startT, x[0], *(double*) 0); 394 xy_at_t(aLine, endT, x[1], *(double*) 0); 395 return SkMinScalar((float) x[0], (float) x[1]); 396} 397 398static SkScalar QuadLeftMost(const SkPoint a[3], double startT, double endT) { 399 const Quadratic aQuad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, 400 {a[2].fX, a[2].fY}}; 401 return (float) leftMostT(aQuad, startT, endT); 402} 403 404static SkScalar CubicLeftMost(const SkPoint a[4], double startT, double endT) { 405 const Cubic aCubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, 406 {a[2].fX, a[2].fY}, {a[3].fX, a[3].fY}}; 407 return (float) leftMostT(aCubic, startT, endT); 408} 409 410static SkScalar (* const SegmentLeftMost[])(const SkPoint [], double , double) = { 411 NULL, 412 LineLeftMost, 413 QuadLeftMost, 414 CubicLeftMost 415}; 416 417#if DEBUG_UNUSED 418static bool IsCoincident(const SkPoint a[2], const SkPoint& above, 419 const SkPoint& below) { 420 const _Line aLine = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}}; 421 const _Line bLine = {{above.fX, above.fY}, {below.fX, below.fY}}; 422 return implicit_matches_ulps(aLine, bLine, 32); 423} 424#endif 425 426class Segment; 427 428// sorting angles 429// given angles of {dx dy ddx ddy dddx dddy} sort them 430class Angle { 431public: 432 // FIXME: this is bogus for quads and cubics 433 // if the quads and cubics' line from end pt to ctrl pt are coincident, 434 // there's no obvious way to determine the curve ordering from the 435 // derivatives alone. In particular, if one quadratic's coincident tangent 436 // is longer than the other curve, the final control point can place the 437 // longer curve on either side of the shorter one. 438 // Using Bezier curve focus http://cagd.cs.byu.edu/~tom/papers/bezclip.pdf 439 // may provide some help, but nothing has been figured out yet. 440 bool operator<(const Angle& rh) const { 441 if ((fDy < 0) ^ (rh.fDy < 0)) { 442 return fDy < 0; 443 } 444 if (fDy == 0 && rh.fDy == 0 && fDx != rh.fDx) { 445 return fDx < rh.fDx; 446 } 447 SkScalar cmp = fDx * rh.fDy - rh.fDx * fDy; 448 if (cmp) { 449 return cmp < 0; 450 } 451 if ((fDDy < 0) ^ (rh.fDDy < 0)) { 452 return fDDy < 0; 453 } 454 if (fDDy == 0 && rh.fDDy == 0 && fDDx != rh.fDDx) { 455 return fDDx < rh.fDDx; 456 } 457 cmp = fDDx * rh.fDDy - rh.fDDx * fDDy; 458 if (cmp) { 459 return cmp < 0; 460 } 461 if ((fDDDy < 0) ^ (rh.fDDDy < 0)) { 462 return fDDDy < 0; 463 } 464 if (fDDDy == 0 && rh.fDDDy == 0) { 465 return fDDDx < rh.fDDDx; 466 } 467 return fDDDx * rh.fDDDy < rh.fDDDx * fDDDy; 468 } 469 470 int end() const { 471 return fEnd; 472 } 473 474 bool isHorizontal() const { 475 return fDy == 0 && fDDy == 0 && fDDDy == 0; 476 } 477 478 // since all angles share a point, this needs to know which point 479 // is the common origin, i.e., whether the center is at pts[0] or pts[verb] 480 // practically, this should only be called by addAngle 481 void set(const SkPoint* pts, SkPath::Verb verb, const Segment* segment, 482 int start, int end) { 483 SkASSERT(start != end); 484 fSegment = segment; 485 fStart = start; 486 fEnd = end; 487 fDx = pts[1].fX - pts[0].fX; // b - a 488 fDy = pts[1].fY - pts[0].fY; 489 if (verb == SkPath::kLine_Verb) { 490 fDDx = fDDy = fDDDx = fDDDy = 0; 491 return; 492 } 493 fDDx = pts[2].fX - pts[1].fX - fDx; // a - 2b + c 494 fDDy = pts[2].fY - pts[1].fY - fDy; 495 if (verb == SkPath::kQuad_Verb) { 496 fDDDx = fDDDy = 0; 497 return; 498 } 499 fDDDx = pts[3].fX + 3 * (pts[1].fX - pts[2].fX) - pts[0].fX; 500 fDDDy = pts[3].fY + 3 * (pts[1].fY - pts[2].fY) - pts[0].fY; 501 } 502 503 // noncoincident quads/cubics may have the same initial angle 504 // as lines, so must sort by derivatives as well 505 // if flatness turns out to be a reasonable way to sort, use the below: 506 void setFlat(const SkPoint* pts, SkPath::Verb verb, Segment* segment, 507 int start, int end) { 508 fSegment = segment; 509 fStart = start; 510 fEnd = end; 511 fDx = pts[1].fX - pts[0].fX; // b - a 512 fDy = pts[1].fY - pts[0].fY; 513 if (verb == SkPath::kLine_Verb) { 514 fDDx = fDDy = fDDDx = fDDDy = 0; 515 return; 516 } 517 if (verb == SkPath::kQuad_Verb) { 518 int uplsX = FloatAsInt(pts[2].fX - pts[1].fY - fDx); 519 int uplsY = FloatAsInt(pts[2].fY - pts[1].fY - fDy); 520 int larger = std::max(abs(uplsX), abs(uplsY)); 521 int shift = 0; 522 double flatT; 523 SkPoint ddPt; // FIXME: get rid of copy (change fDD_ to point) 524 LineParameters implicitLine; 525 _Line tangent = {{pts[0].fX, pts[0].fY}, {pts[1].fX, pts[1].fY}}; 526 implicitLine.lineEndPoints(tangent); 527 implicitLine.normalize(); 528 while (larger > UlpsEpsilon * 1024) { 529 larger >>= 2; 530 ++shift; 531 flatT = 0.5 / (1 << shift); 532 QuadXYAtT(pts, flatT, &ddPt); 533 _Point _pt = {ddPt.fX, ddPt.fY}; 534 double distance = implicitLine.pointDistance(_pt); 535 if (approximately_zero(distance)) { 536 SkDebugf("%s ulps too small %1.9g\n", __FUNCTION__, distance); 537 break; 538 } 539 } 540 flatT = 0.5 / (1 << shift); 541 QuadXYAtT(pts, flatT, &ddPt); 542 fDDx = ddPt.fX - pts[0].fX; 543 fDDy = ddPt.fY - pts[0].fY; 544 SkASSERT(fDDx != 0 || fDDy != 0); 545 fDDDx = fDDDy = 0; 546 return; 547 } 548 SkASSERT(0); // FIXME: add cubic case 549 } 550 551 Segment* segment() const { 552 return const_cast<Segment*>(fSegment); 553 } 554 555 int sign() const { 556 return SkSign32(fStart - fEnd); 557 } 558 559 int start() const { 560 return fStart; 561 } 562 563private: 564 SkScalar fDx; 565 SkScalar fDy; 566 SkScalar fDDx; 567 SkScalar fDDy; 568 SkScalar fDDDx; 569 SkScalar fDDDy; 570 const Segment* fSegment; 571 int fStart; 572 int fEnd; 573}; 574 575static void sortAngles(SkTDArray<Angle>& angles, SkTDArray<Angle*>& angleList) { 576 int angleCount = angles.count(); 577 int angleIndex; 578 angleList.setReserve(angleCount); 579 for (angleIndex = 0; angleIndex < angleCount; ++angleIndex) { 580 *angleList.append() = &angles[angleIndex]; 581 } 582 QSort<Angle>(angleList.begin(), angleList.end() - 1); 583} 584 585// Bounds, unlike Rect, does not consider a line to be empty. 586struct Bounds : public SkRect { 587 static bool Intersects(const Bounds& a, const Bounds& b) { 588 return a.fLeft <= b.fRight && b.fLeft <= a.fRight && 589 a.fTop <= b.fBottom && b.fTop <= a.fBottom; 590 } 591 592 void add(SkScalar left, SkScalar top, SkScalar right, SkScalar bottom) { 593 if (left < fLeft) { 594 fLeft = left; 595 } 596 if (top < fTop) { 597 fTop = top; 598 } 599 if (right > fRight) { 600 fRight = right; 601 } 602 if (bottom > fBottom) { 603 fBottom = bottom; 604 } 605 } 606 607 void add(const Bounds& toAdd) { 608 add(toAdd.fLeft, toAdd.fTop, toAdd.fRight, toAdd.fBottom); 609 } 610 611 bool isEmpty() { 612 return fLeft > fRight || fTop > fBottom 613 || fLeft == fRight && fTop == fBottom 614 || isnan(fLeft) || isnan(fRight) 615 || isnan(fTop) || isnan(fBottom); 616 } 617 618 void setCubicBounds(const SkPoint a[4]) { 619 _Rect dRect; 620 Cubic cubic = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, 621 {a[2].fX, a[2].fY}, {a[3].fX, a[3].fY}}; 622 dRect.setBounds(cubic); 623 set((float) dRect.left, (float) dRect.top, (float) dRect.right, 624 (float) dRect.bottom); 625 } 626 627 void setQuadBounds(const SkPoint a[3]) { 628 const Quadratic quad = {{a[0].fX, a[0].fY}, {a[1].fX, a[1].fY}, 629 {a[2].fX, a[2].fY}}; 630 _Rect dRect; 631 dRect.setBounds(quad); 632 set((float) dRect.left, (float) dRect.top, (float) dRect.right, 633 (float) dRect.bottom); 634 } 635}; 636 637struct Span { 638 Segment* fOther; 639 mutable SkPoint const* fPt; // lazily computed as needed 640 double fT; 641 double fOtherT; // value at fOther[fOtherIndex].fT 642 int fOtherIndex; // can't be used during intersection 643 int fWindSum; // accumulated from contours surrounding this one 644 int fWindValue; // 0 == canceled; 1 == normal; >1 == coincident 645 bool fDone; // if set, this span to next higher T has been processed 646}; 647 648class Segment { 649public: 650 Segment() { 651#if DEBUG_DUMP 652 fID = ++gSegmentID; 653#endif 654 } 655 656 bool activeAngle(int index, int& done, SkTDArray<Angle>& angles) const { 657 if (activeAngleInner(index, done, angles)) { 658 return true; 659 } 660 double referenceT = fTs[index].fT; 661 int lesser = index; 662 while (--lesser >= 0 && referenceT - fTs[lesser].fT < FLT_EPSILON) { 663 if (activeAngleOther(lesser, done, angles)) { 664 return true; 665 } 666 } 667 do { 668 if (activeAngleOther(index, done, angles)) { 669 return true; 670 } 671 } while (++index < fTs.count() && fTs[index].fT - referenceT < FLT_EPSILON); 672 return false; 673 } 674 675 bool activeAngleOther(int index, int& done, SkTDArray<Angle>& angles) const { 676 Span* span = &fTs[index]; 677 Segment* other = span->fOther; 678 int oIndex = span->fOtherIndex; 679 return other->activeAngleInner(oIndex, done, angles); 680 } 681 682 bool activeAngleInner(int index, int& done, SkTDArray<Angle>& angles) const { 683 int next = nextSpan(index, 1); 684 if (next > 0) { 685 addAngle(angles, index, next); 686 const Span& upSpan = fTs[index]; 687 if (upSpan.fDone) { 688 done++; 689 } else if (upSpan.fWindSum != SK_MinS32) { 690 return true; 691 } 692 } 693 int prev = nextSpan(index, -1); 694 // edge leading into junction 695 if (prev >= 0) { 696 addAngle(angles, index, prev); 697 const Span& downSpan = fTs[prev]; 698 if (downSpan.fDone) { 699 done++; 700 } else if (downSpan.fWindSum != SK_MinS32) { 701 return true; 702 } 703 } 704 return false; 705 } 706 707 SkScalar activeTop() const { 708 SkASSERT(!done()); 709 int count = fTs.count(); 710 SkScalar result = SK_ScalarMax; 711 bool lastDone = true; 712 for (int index = 0; index < count; ++index) { 713 bool done = fTs[index].fDone; 714 if (!done || !lastDone) { 715 SkScalar y = yAtT(index); 716 if (result > y) { 717 result = y; 718 } 719 } 720 lastDone = done; 721 } 722 SkASSERT(result < SK_ScalarMax); 723 return result; 724 } 725 726 void addAngle(SkTDArray<Angle>& angles, int start, int end) const { 727 SkASSERT(start != end); 728 SkPoint edge[4]; 729 (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge); 730 Angle* angle = angles.append(); 731 angle->set(edge, fVerb, this, start, end); 732 } 733 734 void addCubic(const SkPoint pts[4]) { 735 init(pts, SkPath::kCubic_Verb); 736 fBounds.setCubicBounds(pts); 737 } 738 739 // FIXME: this needs to defer add for aligned consecutive line segments 740 SkPoint addCurveTo(int start, int end, SkPath& path, bool active) { 741 SkPoint edge[4]; 742 // OPTIMIZE? if not active, skip remainder and return xy_at_t(end) 743 (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge); 744 if (active) { 745 #if DEBUG_PATH_CONSTRUCTION 746 SkDebugf("%s %s (%1.9g,%1.9g)", __FUNCTION__, 747 kLVerbStr[fVerb], edge[1].fX, edge[1].fY); 748 if (fVerb > 1) { 749 SkDebugf(" (%1.9g,%1.9g)", edge[2].fX, edge[2].fY); 750 } 751 if (fVerb > 2) { 752 SkDebugf(" (%1.9g,%1.9g)", edge[3].fX, edge[3].fY); 753 } 754 SkDebugf("\n"); 755 #endif 756 switch (fVerb) { 757 case SkPath::kLine_Verb: 758 path.lineTo(edge[1].fX, edge[1].fY); 759 break; 760 case SkPath::kQuad_Verb: 761 path.quadTo(edge[1].fX, edge[1].fY, edge[2].fX, edge[2].fY); 762 break; 763 case SkPath::kCubic_Verb: 764 path.cubicTo(edge[1].fX, edge[1].fY, edge[2].fX, edge[2].fY, 765 edge[3].fX, edge[3].fY); 766 break; 767 } 768 } 769 return edge[fVerb]; 770 } 771 772 void addLine(const SkPoint pts[2]) { 773 init(pts, SkPath::kLine_Verb); 774 fBounds.set(pts, 2); 775 } 776 777 const SkPoint& addMoveTo(int tIndex, SkPath& path, bool active) { 778 const SkPoint& pt = xyAtT(tIndex); 779 if (active) { 780 #if DEBUG_PATH_CONSTRUCTION 781 SkDebugf("%s (%1.9g,%1.9g)\n", __FUNCTION__, pt.fX, pt.fY); 782 #endif 783 path.moveTo(pt.fX, pt.fY); 784 } 785 return pt; 786 } 787 788 // add 2 to edge or out of range values to get T extremes 789 void addOtherT(int index, double otherT, int otherIndex) { 790 Span& span = fTs[index]; 791 span.fOtherT = otherT; 792 span.fOtherIndex = otherIndex; 793 } 794 795 void addQuad(const SkPoint pts[3]) { 796 init(pts, SkPath::kQuad_Verb); 797 fBounds.setQuadBounds(pts); 798 } 799 800 // Defer all coincident edge processing until 801 // after normal intersections have been computed 802 803// no need to be tricky; insert in normal T order 804// resolve overlapping ts when considering coincidence later 805 806 // add non-coincident intersection. Resulting edges are sorted in T. 807 int addT(double newT, Segment* other) { 808 // FIXME: in the pathological case where there is a ton of intercepts, 809 // binary search? 810 int insertedAt = -1; 811 size_t tCount = fTs.count(); 812 for (size_t index = 0; index < tCount; ++index) { 813 // OPTIMIZATION: if there are three or more identical Ts, then 814 // the fourth and following could be further insertion-sorted so 815 // that all the edges are clockwise or counterclockwise. 816 // This could later limit segment tests to the two adjacent 817 // neighbors, although it doesn't help with determining which 818 // circular direction to go in. 819 if (newT < fTs[index].fT) { 820 insertedAt = index; 821 break; 822 } 823 } 824 Span* span; 825 if (insertedAt >= 0) { 826 span = fTs.insert(insertedAt); 827 } else { 828 insertedAt = tCount; 829 span = fTs.append(); 830 } 831 span->fT = newT; 832 span->fOther = other; 833 span->fPt = NULL; 834 span->fWindSum = SK_MinS32; 835 span->fWindValue = 1; 836 if ((span->fDone = newT == 1)) { 837 ++fDoneSpans; 838 } 839 return insertedAt; 840 } 841 842 // set spans from start to end to decrement by one 843 // note this walks other backwards 844 // FIMXE: there's probably an edge case that can be constructed where 845 // two span in one segment are separated by float epsilon on one span but 846 // not the other, if one segment is very small. For this 847 // case the counts asserted below may or may not be enough to separate the 848 // spans. Even if the counts work out, what if the spanw aren't correctly 849 // sorted? It feels better in such a case to match the span's other span 850 // pointer since both coincident segments must contain the same spans. 851 void addTCancel(double startT, double endT, Segment& other, 852 double oStartT, double oEndT) { 853 SkASSERT(endT - startT >= FLT_EPSILON); 854 SkASSERT(oEndT - oStartT >= FLT_EPSILON); 855 int index = 0; 856 while (startT - fTs[index].fT >= FLT_EPSILON) { 857 ++index; 858 } 859 int oIndex = other.fTs.count(); 860 while (other.fTs[--oIndex].fT - oEndT > -FLT_EPSILON) 861 ; 862 Span* test = &fTs[index]; 863 Span* oTest = &other.fTs[oIndex]; 864 do { 865 bool decrement = test->fWindValue && oTest->fWindValue; 866 Span* end = test; 867 do { 868 if (decrement) { 869 SkASSERT(end->fWindValue > 0); 870 if (--(end->fWindValue) == 0) { 871 end->fDone = true; 872 ++fDoneSpans; 873 } 874 } 875 end = &fTs[++index]; 876 } while (end->fT - test->fT < FLT_EPSILON); 877 Span* oTestStart = oTest; 878 do { 879 if (decrement) { 880 SkASSERT(oTestStart->fWindValue > 0); 881 if (--(oTestStart->fWindValue) == 0) { 882 oTestStart->fDone = true; 883 ++other.fDoneSpans; 884 } 885 } 886 if (!oIndex) { 887 break; 888 } 889 oTestStart = &other.fTs[--oIndex]; 890 } while (oTest->fT - oTestStart->fT < FLT_EPSILON); 891 test = end; 892 oTest = oTestStart; 893 } while (test->fT < endT - FLT_EPSILON); 894 SkASSERT(!oIndex || oTest->fT <= oStartT - FLT_EPSILON); 895 } 896 897 // set spans from start to end to increment the greater by one and decrement 898 // the lesser 899 void addTCoincident(double startT, double endT, Segment& other, 900 double oStartT, double oEndT) { 901 SkASSERT(endT - startT >= FLT_EPSILON); 902 SkASSERT(oEndT - oStartT >= FLT_EPSILON); 903 int index = 0; 904 while (startT - fTs[index].fT >= FLT_EPSILON) { 905 ++index; 906 } 907 int oIndex = 0; 908 while (oStartT - other.fTs[oIndex].fT >= FLT_EPSILON) { 909 ++oIndex; 910 } 911 Span* test = &fTs[index]; 912 Span* oTest = &other.fTs[oIndex]; 913 SkTDArray<double> outsideTs; 914 SkTDArray<double> oOutsideTs; 915 do { 916 bool transfer = test->fWindValue && oTest->fWindValue; 917 bool decrementOther = test->fWindValue >= oTest->fWindValue; 918 Span* end = test; 919 double startT = end->fT; 920 double oStartT = oTest->fT; 921 do { 922 if (transfer) { 923 if (decrementOther) { 924 ++(end->fWindValue); 925 } else { 926 SkASSERT(end->fWindValue > 0); 927 if (--(end->fWindValue) == 0) { 928 end->fDone = true; 929 ++fDoneSpans; 930 int outCount = outsideTs.count(); 931 if (outCount == 0 || end->fT - outsideTs[outCount - 2] 932 >= FLT_EPSILON) { 933 *outsideTs.append() = end->fT; 934 *outsideTs.append() = oStartT; 935 } 936 } 937 } 938 } 939 end = &fTs[++index]; 940 } while (end->fT - test->fT < FLT_EPSILON); 941 Span* oEnd = oTest; 942 do { 943 if (transfer) { 944 if (decrementOther) { 945 SkASSERT(oEnd->fWindValue > 0); 946 if (--(oEnd->fWindValue) == 0) { 947 oEnd->fDone = true; 948 ++other.fDoneSpans; 949 int oOutCount = oOutsideTs.count(); 950 if (oOutCount == 0 || oEnd->fT 951 - oOutsideTs[oOutCount - 2] >= FLT_EPSILON) { 952 *oOutsideTs.append() = oEnd->fT; 953 *oOutsideTs.append() = startT; 954 } 955 } 956 } else { 957 ++(oEnd->fWindValue); 958 } 959 } 960 oEnd = &other.fTs[++oIndex]; 961 } while (oEnd->fT - oTest->fT < FLT_EPSILON); 962 test = end; 963 oTest = oEnd; 964 } while (test->fT < endT - FLT_EPSILON); 965 SkASSERT(oTest->fT < oEndT + FLT_EPSILON); 966 SkASSERT(oTest->fT > oEndT - FLT_EPSILON); 967 if (!done() && outsideTs.count()) { 968 addTOutsides(outsideTs, other, oEndT); 969 } 970 if (!other.done() && oOutsideTs.count()) { 971 other.addTOutsides(oOutsideTs, *this, endT); 972 } 973 } 974 975 void addTOutsides(const SkTDArray<double>& outsideTs, Segment& other, 976 double otherEnd) { 977 int count = outsideTs.count(); 978 double endT = 0; 979 int endSpan = 0; 980 for (int index = 0; index < count; index += 2) { 981 double t = outsideTs[index]; 982 double otherT = outsideTs[index + 1]; 983 if (t > 1 - FLT_EPSILON) { 984 return; 985 } 986 if (t - endT > FLT_EPSILON) { 987 endSpan = addTDonePair(t, other, otherT); 988 } 989 do { 990 endT = fTs[++endSpan].fT; 991 } while (endT - t < FLT_EPSILON); 992 } 993 addTPair(endT, other, otherEnd); 994 } 995 996 // match the other.fWindValue to its mates 997 int addTDonePair(double t, Segment& other, double otherT) { 998 int insertedAt = addTPair(t, other, otherT); 999 Span& end = fTs[insertedAt]; 1000 SkASSERT(end.fWindValue == 1); 1001 end.fWindValue = 0; 1002 end.fDone = true; 1003 ++fDoneSpans; 1004 Span& otherEnd = other.fTs[end.fOtherIndex]; 1005 Span* match = NULL; 1006 if (end.fOtherIndex > 0) { 1007 match = &other.fTs[end.fOtherIndex - 1]; 1008 } 1009 if (!match || match->fT < otherT) { 1010 match = &other.fTs[end.fOtherIndex + 1]; 1011 } 1012 otherEnd.fWindValue = match->fWindValue; 1013 return insertedAt; 1014 } 1015 1016 int addTPair(double t, Segment& other, double otherT) { 1017 int insertedAt = addT(t, &other); 1018 int otherInsertedAt = other.addT(otherT, this); 1019 addOtherT(insertedAt, otherT, otherInsertedAt); 1020 other.addOtherT(otherInsertedAt, t, insertedAt); 1021 return insertedAt; 1022 } 1023 1024 void addTwoAngles(int start, int end, SkTDArray<Angle>& angles) const { 1025 // add edge leading into junction 1026 if (fTs[SkMin32(end, start)].fWindValue > 0) { 1027 addAngle(angles, end, start); 1028 } 1029 // add edge leading away from junction 1030 int step = SkSign32(end - start); 1031 int tIndex = nextSpan(end, step); 1032 if (tIndex >= 0 && fTs[SkMin32(end, tIndex)].fWindValue > 0) { 1033 addAngle(angles, end, tIndex); 1034 } 1035 } 1036 1037 const Bounds& bounds() const { 1038 return fBounds; 1039 } 1040 1041 void buildAngles(int index, SkTDArray<Angle>& angles) const { 1042 double referenceT = fTs[index].fT; 1043 int lesser = index; 1044 while (--lesser >= 0 && referenceT - fTs[lesser].fT < FLT_EPSILON) { 1045 buildAnglesInner(lesser, angles); 1046 } 1047 do { 1048 buildAnglesInner(index, angles); 1049 } while (++index < fTs.count() && fTs[index].fT - referenceT < FLT_EPSILON); 1050 } 1051 1052 void buildAnglesInner(int index, SkTDArray<Angle>& angles) const { 1053 Span* span = &fTs[index]; 1054 Segment* other = span->fOther; 1055 // if there is only one live crossing, and no coincidence, continue 1056 // in the same direction 1057 // if there is coincidence, the only choice may be to reverse direction 1058 // find edge on either side of intersection 1059 int oIndex = span->fOtherIndex; 1060 // if done == -1, prior span has already been processed 1061 int step = 1; 1062 int next = other->nextSpan(oIndex, step); 1063 if (next < 0) { 1064 step = -step; 1065 next = other->nextSpan(oIndex, step); 1066 } 1067 // add candidate into and away from junction 1068 other->addTwoAngles(next, oIndex, angles); 1069 } 1070 1071 bool cancels(const Segment& other) const { 1072 SkASSERT(fVerb == SkPath::kLine_Verb); 1073 SkASSERT(other.fVerb == SkPath::kLine_Verb); 1074 SkPoint dxy = fPts[0] - fPts[1]; 1075 SkPoint odxy = other.fPts[0] - other.fPts[1]; 1076 return dxy.fX * odxy.fX < 0 || dxy.fY * odxy.fY < 0; 1077 } 1078 1079 // figure out if the segment's ascending T goes clockwise or not 1080 // not enough context to write this as shown 1081 // instead, add all segments meeting at the top 1082 // sort them using buildAngleList 1083 // find the first in the sort 1084 // see if ascendingT goes to top 1085 bool clockwise(int /* tIndex */) const { 1086 SkASSERT(0); // incomplete 1087 return false; 1088 } 1089 1090 int crossedSpan(const SkPoint& basePt, SkScalar& bestY, double& hitT) const { 1091 int start = 0; 1092 int bestT = -1; 1093 SkScalar top = bounds().fTop; 1094 SkScalar bottom = bounds().fBottom; 1095 int end; 1096 do { 1097 end = nextSpan(start, 1); 1098 SkPoint edge[4]; 1099 // OPTIMIZE: wrap this so that if start==0 end==fTCount-1 we can 1100 // work with the original data directly 1101 (*SegmentSubDivide[fVerb])(fPts, fTs[start].fT, fTs[end].fT, edge); 1102 // intersect ray starting at basePt with edge 1103 Intersections intersections; 1104 int pts = (*VSegmentIntersect[fVerb])(edge, top, bottom, basePt.fX, 1105 false, intersections); 1106 if (pts == 0) { 1107 continue; 1108 } 1109 if (pts > 1 && fVerb == SkPath::kLine_Verb) { 1110 // if the intersection is edge on, wait for another one 1111 continue; 1112 } 1113 SkASSERT(pts == 1); // FIXME: more code required to disambiguate 1114 SkPoint pt; 1115 double foundT = intersections.fT[0][0]; 1116 (*SegmentXYAtT[fVerb])(fPts, foundT, &pt); 1117 if (bestY < pt.fY) { 1118 bestY = pt.fY; 1119 bestT = foundT < 1 ? start : end; 1120 hitT = foundT; 1121 } 1122 start = end; 1123 } while (fTs[end].fT != 1); 1124 return bestT; 1125 } 1126 1127 bool done() const { 1128 SkASSERT(fDoneSpans <= fTs.count()); 1129 return fDoneSpans == fTs.count(); 1130 } 1131 1132 // so the span needs to contain the pairing info found here 1133 // this should include the winding computed for the edge, and 1134 // what edge it connects to, and whether it is discarded 1135 // (maybe discarded == abs(winding) > 1) ? 1136 // only need derivatives for duration of sorting, add a new struct 1137 // for pairings, remove extra spans that have zero length and 1138 // reference an unused other 1139 // for coincident, the last span on the other may be marked done 1140 // (always?) 1141 1142 // if loop is exhausted, contour may be closed. 1143 // FIXME: pass in close point so we can check for closure 1144 1145 // given a segment, and a sense of where 'inside' is, return the next 1146 // segment. If this segment has an intersection, or ends in multiple 1147 // segments, find the mate that continues the outside. 1148 // note that if there are multiples, but no coincidence, we can limit 1149 // choices to connections in the correct direction 1150 1151 // mark found segments as done 1152 1153 // start is the index of the beginning T of this edge 1154 // it is guaranteed to have an end which describes a non-zero length (?) 1155 // winding -1 means ccw, 1 means cw 1156 // firstFind allows coincident edges to be treated differently 1157 Segment* findNext(SkTDArray<Span*>& chase, int winding, const int startIndex, 1158 const int endIndex, 1159 int& nextStart, int& nextEnd, int& flipped, bool firstFind) { 1160 SkASSERT(startIndex != endIndex); 1161 int count = fTs.count(); 1162 SkASSERT(startIndex < endIndex ? startIndex < count - 1 1163 : startIndex > 0); 1164 int step = SkSign32(endIndex - startIndex); 1165 int end = nextSpan(startIndex, step); 1166 SkASSERT(end >= 0); 1167 Span* endSpan = &fTs[end]; 1168 Segment* other; 1169 if (isSimple(end)) { 1170 // mark the smaller of startIndex, endIndex done, and all adjacent 1171 // spans with the same T value (but not 'other' spans) 1172 markDone(SkMin32(startIndex, endIndex), winding); 1173 other = endSpan->fOther; 1174 nextStart = endSpan->fOtherIndex; 1175 nextEnd = nextStart + step; 1176 SkASSERT(step < 0 ? nextEnd >= 0 : nextEnd < other->fTs.count()); 1177 return other; 1178 } 1179 // more than one viable candidate -- measure angles to find best 1180 SkTDArray<Angle> angles; 1181 SkASSERT(startIndex - endIndex != 0); 1182 SkASSERT((startIndex - endIndex < 0) ^ (step < 0)); 1183 addTwoAngles(startIndex, end, angles); 1184 buildAngles(end, angles); 1185 SkTDArray<Angle*> sorted; 1186 sortAngles(angles, sorted); 1187 int angleCount = angles.count(); 1188 int firstIndex = findStartingEdge(sorted, startIndex, end); 1189 1190 SkASSERT(firstIndex >= 0); 1191 int startWinding = winding; 1192 int nextIndex = firstIndex + 1; 1193 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; 1194 const Angle* foundAngle = NULL; 1195 // iterate through the angle, and compute everyone's winding 1196 bool firstEdge = true; 1197 do { 1198 if (nextIndex == angleCount) { 1199 nextIndex = 0; 1200 } 1201 const Angle* nextAngle = sorted[nextIndex]; 1202 int maxWinding = winding; 1203 Segment* nextSegment = nextAngle->segment(); 1204 int windValue = nextSegment->windValue(nextAngle); 1205 SkASSERT(windValue > 0); 1206 winding -= nextAngle->sign() * windValue; 1207 #if DEBUG_WINDING 1208 SkDebugf("%s maxWinding=%d winding=%d\n", __FUNCTION__, maxWinding, 1209 winding); 1210 #endif 1211 if (maxWinding * winding < 0) { 1212 flipped = -flipped; 1213 SkDebugf("flipped sign %d %d\n", maxWinding, winding); 1214 } 1215 firstEdge = false; 1216 if (!winding) { 1217 if (!foundAngle) { 1218 foundAngle = nextAngle; 1219 } 1220 continue; 1221 } 1222 if (nextSegment->done()) { 1223 continue; 1224 } 1225 // if the winding is non-zero, nextAngle does not connect to 1226 // current chain. If we haven't done so already, mark the angle 1227 // as done, record the winding value, and mark connected unambiguous 1228 // segments as well. 1229 if (nextSegment->windSum(nextAngle) == SK_MinS32) { 1230 if (abs(maxWinding) < abs(winding)) { 1231 maxWinding = winding; 1232 } 1233 Span* last; 1234 if (foundAngle) { 1235 last = nextSegment->markAndChaseWinding(nextAngle, maxWinding); 1236 } else { 1237 last = nextSegment->markAndChaseDone(nextAngle, maxWinding); 1238 } 1239 if (last) { 1240 *chase.append() = last; 1241 } 1242 } 1243 } while (++nextIndex != lastIndex); 1244 sorted[firstIndex]->segment()-> 1245 markDone(SkMin32(startIndex, endIndex), startWinding); 1246 if (!foundAngle) { 1247 return NULL; 1248 } 1249 nextStart = foundAngle->start(); 1250 nextEnd = foundAngle->end(); 1251 return foundAngle->segment(); 1252 } 1253 1254 int findStartingEdge(SkTDArray<Angle*>& sorted, int start, int end) { 1255 int angleCount = sorted.count(); 1256 int firstIndex = -1; 1257 for (int angleIndex = 0; angleIndex < angleCount; ++angleIndex) { 1258 const Angle* angle = sorted[angleIndex]; 1259 if (angle->segment() == this && angle->start() == end && 1260 angle->end() == start) { 1261 firstIndex = angleIndex; 1262 break; 1263 } 1264 } 1265 return firstIndex; 1266 } 1267 1268 // FIXME: this is tricky code; needs its own unit test 1269 void findTooCloseToCall(int /* winding */ ) { // FIXME: winding should be considered 1270 int count = fTs.count(); 1271 if (count < 3) { // require t=0, x, 1 at minimum 1272 return; 1273 } 1274 int matchIndex = 0; 1275 int moCount; 1276 Span* match; 1277 Segment* mOther; 1278 do { 1279 match = &fTs[matchIndex]; 1280 mOther = match->fOther; 1281 moCount = mOther->fTs.count(); 1282 if (moCount >= 3) { 1283 break; 1284 } 1285 if (++matchIndex >= count) { 1286 return; 1287 } 1288 } while (true); // require t=0, x, 1 at minimum 1289 // OPTIMIZATION: defer matchPt until qualifying toCount is found? 1290 const SkPoint* matchPt = &xyAtT(match); 1291 // look for a pair of nearby T values that map to the same (x,y) value 1292 // if found, see if the pair of other segments share a common point. If 1293 // so, the span from here to there is coincident. 1294 for (int index = matchIndex + 1; index < count; ++index) { 1295 Span* test = &fTs[index]; 1296 if (test->fDone) { 1297 continue; 1298 } 1299 Segment* tOther = test->fOther; 1300 int toCount = tOther->fTs.count(); 1301 if (toCount < 3) { // require t=0, x, 1 at minimum 1302 continue; 1303 } 1304 const SkPoint* testPt = &xyAtT(test); 1305 if (*matchPt != *testPt) { 1306 matchIndex = index; 1307 moCount = toCount; 1308 match = test; 1309 mOther = tOther; 1310 matchPt = testPt; 1311 continue; 1312 } 1313 int moStart = -1; 1314 int moEnd = -1; 1315 double moStartT, moEndT; 1316 for (int moIndex = 0; moIndex < moCount; ++moIndex) { 1317 Span& moSpan = mOther->fTs[moIndex]; 1318 if (moSpan.fDone) { 1319 continue; 1320 } 1321 if (moSpan.fOther == this) { 1322 if (moSpan.fOtherT == match->fT) { 1323 moStart = moIndex; 1324 moStartT = moSpan.fT; 1325 } 1326 continue; 1327 } 1328 if (moSpan.fOther == tOther) { 1329 SkASSERT(moEnd == -1); 1330 moEnd = moIndex; 1331 moEndT = moSpan.fT; 1332 } 1333 } 1334 if (moStart < 0 || moEnd < 0) { 1335 continue; 1336 } 1337 // FIXME: if moStartT, moEndT are initialized to NaN, can skip this test 1338 if (moStartT == moEndT) { 1339 continue; 1340 } 1341 int toStart = -1; 1342 int toEnd = -1; 1343 double toStartT, toEndT; 1344 for (int toIndex = 0; toIndex < toCount; ++toIndex) { 1345 Span& toSpan = tOther->fTs[toIndex]; 1346 if (toSpan.fOther == this) { 1347 if (toSpan.fOtherT == test->fT) { 1348 toStart = toIndex; 1349 toStartT = toSpan.fT; 1350 } 1351 continue; 1352 } 1353 if (toSpan.fOther == mOther && toSpan.fOtherT == moEndT) { 1354 SkASSERT(toEnd == -1); 1355 toEnd = toIndex; 1356 toEndT = toSpan.fT; 1357 } 1358 } 1359 // FIXME: if toStartT, toEndT are initialized to NaN, can skip this test 1360 if (toStart <= 0 || toEnd <= 0) { 1361 continue; 1362 } 1363 if (toStartT == toEndT) { 1364 continue; 1365 } 1366 // test to see if the segment between there and here is linear 1367 if (!mOther->isLinear(moStart, moEnd) 1368 || !tOther->isLinear(toStart, toEnd)) { 1369 continue; 1370 } 1371 // FIXME: defer implementation until the rest works 1372 // this may share code with regular coincident detection 1373 SkASSERT(0); 1374 #if 0 1375 if (flipped) { 1376 mOther->addTCancel(moStart, moEnd, tOther, tStart, tEnd); 1377 } else { 1378 mOther->addTCoincident(moStart, moEnd, tOther, tStart, tEnd); 1379 } 1380 #endif 1381 } 1382 } 1383 1384 // OPTIMIZATION : for a pair of lines, can we compute points at T (cached) 1385 // and use more concise logic like the old edge walker code? 1386 // FIXME: this needs to deal with coincident edges 1387 Segment* findTop(int& tIndex, int& endIndex) { 1388 // iterate through T intersections and return topmost 1389 // topmost tangent from y-min to first pt is closer to horizontal 1390 SkASSERT(!done()); 1391 int firstT; 1392 int lastT; 1393 SkPoint topPt; 1394 topPt.fY = SK_ScalarMax; 1395 int count = fTs.count(); 1396 // see if either end is not done since we want smaller Y of the pair 1397 bool lastDone = true; 1398 for (int index = 0; index < count; ++index) { 1399 const Span& span = fTs[index]; 1400 if (!span.fDone || !lastDone) { 1401 const SkPoint& intercept = xyAtT(&span); 1402 if (topPt.fY > intercept.fY || (topPt.fY == intercept.fY 1403 && topPt.fX > intercept.fX)) { 1404 topPt = intercept; 1405 firstT = lastT = index; 1406 } else if (topPt == intercept) { 1407 lastT = index; 1408 } 1409 } 1410 lastDone = span.fDone; 1411 } 1412 // sort the edges to find the leftmost 1413 int step = 1; 1414 int end = nextSpan(firstT, step); 1415 if (end == -1) { 1416 step = -1; 1417 end = nextSpan(firstT, step); 1418 SkASSERT(end != -1); 1419 } 1420 // if the topmost T is not on end, or is three-way or more, find left 1421 // look for left-ness from tLeft to firstT (matching y of other) 1422 SkTDArray<Angle> angles; 1423 SkASSERT(firstT - end != 0); 1424 addTwoAngles(end, firstT, angles); 1425 buildAngles(firstT, angles); 1426 SkTDArray<Angle*> sorted; 1427 sortAngles(angles, sorted); 1428 // skip edges that have already been processed 1429 firstT = -1; 1430 Segment* leftSegment; 1431 do { 1432 const Angle* angle = sorted[++firstT]; 1433 leftSegment = angle->segment(); 1434 tIndex = angle->end(); 1435 endIndex = angle->start(); 1436 } while (leftSegment->fTs[SkMin32(tIndex, endIndex)].fDone); 1437 return leftSegment; 1438 } 1439 1440 // FIXME: not crazy about this 1441 // when the intersections are performed, the other index is into an 1442 // incomplete array. as the array grows, the indices become incorrect 1443 // while the following fixes the indices up again, it isn't smart about 1444 // skipping segments whose indices are already correct 1445 // assuming we leave the code that wrote the index in the first place 1446 void fixOtherTIndex() { 1447 int iCount = fTs.count(); 1448 for (int i = 0; i < iCount; ++i) { 1449 Span& iSpan = fTs[i]; 1450 double oT = iSpan.fOtherT; 1451 Segment* other = iSpan.fOther; 1452 int oCount = other->fTs.count(); 1453 for (int o = 0; o < oCount; ++o) { 1454 Span& oSpan = other->fTs[o]; 1455 if (oT == oSpan.fT && this == oSpan.fOther) { 1456 iSpan.fOtherIndex = o; 1457 break; 1458 } 1459 } 1460 } 1461 } 1462 1463 // OPTIMIZATION: uses tail recursion. Unwise? 1464 Span* innerChaseDone(int index, int step, int winding) { 1465 int end = nextSpan(index, step); 1466 SkASSERT(end >= 0); 1467 if (multipleSpans(end)) { 1468 return &fTs[end]; 1469 } 1470 const Span& endSpan = fTs[end]; 1471 Segment* other = endSpan.fOther; 1472 index = endSpan.fOtherIndex; 1473 int otherEnd = other->nextSpan(index, step); 1474 Span* last = other->innerChaseDone(index, step, winding); 1475 other->markDone(SkMin32(index, otherEnd), winding); 1476 return last; 1477 } 1478 1479 Span* innerChaseWinding(int index, int step, int winding) { 1480 int end = nextSpan(index, step); 1481 SkASSERT(end >= 0); 1482 if (multipleSpans(end)) { 1483 return &fTs[end]; 1484 } 1485 const Span& endSpan = fTs[end]; 1486 Segment* other = endSpan.fOther; 1487 index = endSpan.fOtherIndex; 1488 int otherEnd = other->nextSpan(index, step); 1489 int min = SkMin32(index, otherEnd); 1490 if (other->fTs[min].fWindSum != SK_MinS32) { 1491 SkASSERT(other->fTs[index].fWindSum == winding); 1492 return NULL; 1493 } 1494 Span* last = other->innerChaseWinding(index, step, winding); 1495 other->markWinding(min, winding); 1496 return last; 1497 } 1498 1499 void init(const SkPoint pts[], SkPath::Verb verb) { 1500 fPts = pts; 1501 fVerb = verb; 1502 fDoneSpans = 0; 1503 } 1504 1505 bool intersected() const { 1506 return fTs.count() > 0; 1507 } 1508 1509 bool isLinear(int start, int end) const { 1510 if (fVerb == SkPath::kLine_Verb) { 1511 return true; 1512 } 1513 if (fVerb == SkPath::kQuad_Verb) { 1514 SkPoint qPart[3]; 1515 QuadSubDivide(fPts, fTs[start].fT, fTs[end].fT, qPart); 1516 return QuadIsLinear(qPart); 1517 } else { 1518 SkASSERT(fVerb == SkPath::kCubic_Verb); 1519 SkPoint cPart[4]; 1520 CubicSubDivide(fPts, fTs[start].fT, fTs[end].fT, cPart); 1521 return CubicIsLinear(cPart); 1522 } 1523 } 1524 1525 // OPTIMIZE: successive calls could start were the last leaves off 1526 // or calls could specialize to walk forwards or backwards 1527 bool isMissing(double startT) const { 1528 size_t tCount = fTs.count(); 1529 for (size_t index = 0; index < tCount; ++index) { 1530 if (fabs(startT - fTs[index].fT) < FLT_EPSILON) { 1531 return false; 1532 } 1533 } 1534 return true; 1535 } 1536 1537 bool isSimple(int end) const { 1538 int count = fTs.count(); 1539 if (count == 2) { 1540 return true; 1541 } 1542 double t = fTs[end].fT; 1543 if (t < FLT_EPSILON) { 1544 return fTs[1].fT >= FLT_EPSILON; 1545 } 1546 if (t > 1 - FLT_EPSILON) { 1547 return fTs[count - 2].fT <= 1 - FLT_EPSILON; 1548 } 1549 return false; 1550 } 1551 1552 bool isHorizontal() const { 1553 return fBounds.fTop == fBounds.fBottom; 1554 } 1555 1556 bool isVertical() const { 1557 return fBounds.fLeft == fBounds.fRight; 1558 } 1559 1560 SkScalar leftMost(int start, int end) const { 1561 return (*SegmentLeftMost[fVerb])(fPts, fTs[start].fT, fTs[end].fT); 1562 } 1563 1564 // this span is excluded by the winding rule -- chase the ends 1565 // as long as they are unambiguous to mark connections as done 1566 // and give them the same winding value 1567 Span* markAndChaseDone(const Angle* angle, int winding) { 1568 int index = angle->start(); 1569 int endIndex = angle->end(); 1570 int step = SkSign32(endIndex - index); 1571 Span* last = innerChaseDone(index, step, winding); 1572 markDone(SkMin32(index, endIndex), winding); 1573 return last; 1574 } 1575 1576 Span* markAndChaseWinding(const Angle* angle, int winding) { 1577 int index = angle->start(); 1578 int endIndex = angle->end(); 1579 int min = SkMin32(index, endIndex); 1580 int step = SkSign32(endIndex - index); 1581 Span* last = innerChaseWinding(index, step, winding); 1582 markWinding(min, winding); 1583 return last; 1584 } 1585 1586 // FIXME: this should also mark spans with equal (x,y) 1587 // This may be called when the segment is already marked done. While this 1588 // wastes time, it shouldn't do any more than spin through the T spans. 1589 // OPTIMIZATION: abort on first done found (assuming that this code is 1590 // always called to mark segments done). 1591 void markDone(int index, int winding) { 1592 // SkASSERT(!done()); 1593 double referenceT = fTs[index].fT; 1594 int lesser = index; 1595 while (--lesser >= 0 && referenceT - fTs[lesser].fT < FLT_EPSILON) { 1596 Span& span = fTs[lesser]; 1597 if (span.fDone) { 1598 continue; 1599 } 1600 #if DEBUG_MARK_DONE 1601 const SkPoint& pt = xyAtT(&span); 1602 SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n", 1603 __FUNCTION__, fID, lesser, span.fT, pt.fX, pt.fY, winding); 1604 #endif 1605 span.fDone = true; 1606 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); 1607 span.fWindSum = winding; 1608 fDoneSpans++; 1609 } 1610 do { 1611 Span& span = fTs[index]; 1612 // SkASSERT(!span.fDone); 1613 if (span.fDone) { 1614 continue; 1615 } 1616 #if DEBUG_MARK_DONE 1617 const SkPoint& pt = xyAtT(&span); 1618 SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n", 1619 __FUNCTION__, fID, index, span.fT, pt.fX, pt.fY, winding); 1620 #endif 1621 span.fDone = true; 1622 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); 1623 span.fWindSum = winding; 1624 fDoneSpans++; 1625 } while (++index < fTs.count() && fTs[index].fT - referenceT < FLT_EPSILON); 1626 } 1627 1628 void markWinding(int index, int winding) { 1629 SkASSERT(!done()); 1630 double referenceT = fTs[index].fT; 1631 int lesser = index; 1632 while (--lesser >= 0 && referenceT - fTs[lesser].fT < FLT_EPSILON) { 1633 Span& span = fTs[lesser]; 1634 if (span.fDone) { 1635 continue; 1636 } 1637 SkASSERT(span.fWindValue == 1 || winding == 0); 1638 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); 1639 #if DEBUG_MARK_DONE 1640 const SkPoint& pt = xyAtT(&span); 1641 SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n", 1642 __FUNCTION__, fID, lesser, span.fT, pt.fX, pt.fY, winding); 1643 #endif 1644 span.fWindSum = winding; 1645 } 1646 do { 1647 Span& span = fTs[index]; 1648 // SkASSERT(!span.fDone || span.fCoincident); 1649 if (span.fDone) { 1650 continue; 1651 } 1652 SkASSERT(span.fWindValue == 1 || winding == 0); 1653 SkASSERT(span.fWindSum == SK_MinS32 || span.fWindSum == winding); 1654 #if DEBUG_MARK_DONE 1655 const SkPoint& pt = xyAtT(&span); 1656 SkDebugf("%s segment=%d index=%d t=%1.9g pt=(%1.9g,%1.9g) wind=%d\n", 1657 __FUNCTION__, fID, index, span.fT, pt.fX, pt.fY, winding); 1658 #endif 1659 span.fWindSum = winding; 1660 } while (++index < fTs.count() && fTs[index].fT - referenceT < FLT_EPSILON); 1661 } 1662 1663 // return span if when chasing, two or more radiating spans are not done 1664 // OPTIMIZATION: ? multiple spans is detected when there is only one valid 1665 // candidate and the remaining spans have windValue == 0 (canceled by 1666 // coincidence). The coincident edges could either be removed altogether, 1667 // or this code could be more complicated in detecting this case. Worth it? 1668 bool multipleSpans(int end) const { 1669 return end > 0 && end < fTs.count() - 1; 1670 } 1671 1672 // This has callers for two different situations: one establishes the end 1673 // of the current span, and one establishes the beginning of the next span 1674 // (thus the name). When this is looking for the end of the current span, 1675 // coincidence is found when the beginning Ts contain -step and the end 1676 // contains step. When it is looking for the beginning of the next, the 1677 // first Ts found can be ignored and the last Ts should contain -step. 1678 // OPTIMIZATION: probably should split into two functions 1679 int nextSpan(int from, int step) const { 1680 const Span& fromSpan = fTs[from]; 1681 int count = fTs.count(); 1682 int to = from; 1683 while (step > 0 ? ++to < count : --to >= 0) { 1684 const Span& span = fTs[to]; 1685 if ((step > 0 ? span.fT - fromSpan.fT : fromSpan.fT - span.fT) < FLT_EPSILON) { 1686 continue; 1687 } 1688 return to; 1689 } 1690 return -1; 1691 } 1692 1693 const SkPoint* pts() const { 1694 return fPts; 1695 } 1696 1697 void reset() { 1698 init(NULL, (SkPath::Verb) -1); 1699 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax); 1700 fTs.reset(); 1701 } 1702 1703 // OPTIMIZATION: mark as debugging only if used solely by tests 1704 const Span& span(int tIndex) const { 1705 return fTs[tIndex]; 1706 } 1707 1708 int spanSign(int startIndex, int endIndex) const { 1709 return startIndex < endIndex ? -fTs[startIndex].fWindValue : 1710 fTs[endIndex].fWindValue; 1711 } 1712 1713 // OPTIMIZATION: mark as debugging only if used solely by tests 1714 double t(int tIndex) const { 1715 return fTs[tIndex].fT; 1716 } 1717 1718 void updatePts(const SkPoint pts[]) { 1719 fPts = pts; 1720 } 1721 1722 SkPath::Verb verb() const { 1723 return fVerb; 1724 } 1725 1726 int windSum(int tIndex) const { 1727 return fTs[tIndex].fWindSum; 1728 } 1729 1730 int windSum(const Angle* angle) const { 1731 int start = angle->start(); 1732 int end = angle->end(); 1733 int index = SkMin32(start, end); 1734 return windSum(index); 1735 } 1736 1737 int windValue(int tIndex) const { 1738 return fTs[tIndex].fWindValue; 1739 } 1740 1741 int windValue(const Angle* angle) const { 1742 int start = angle->start(); 1743 int end = angle->end(); 1744 int index = SkMin32(start, end); 1745 return windValue(index); 1746 } 1747 1748 SkScalar xAtT(const Span* span) const { 1749 return xyAtT(span).fX; 1750 } 1751 1752 const SkPoint& xyAtT(int index) const { 1753 return xyAtT(&fTs[index]); 1754 } 1755 1756 const SkPoint& xyAtT(const Span* span) const { 1757 if (!span->fPt) { 1758 if (span->fT == 0) { 1759 span->fPt = &fPts[0]; 1760 } else if (span->fT == 1) { 1761 span->fPt = &fPts[fVerb]; 1762 } else { 1763 SkPoint* pt = fIntersections.append(); 1764 (*SegmentXYAtT[fVerb])(fPts, span->fT, pt); 1765 span->fPt = pt; 1766 } 1767 } 1768 return *span->fPt; 1769 } 1770 1771 SkScalar yAtT(int index) const { 1772 return yAtT(&fTs[index]); 1773 } 1774 1775 SkScalar yAtT(const Span* span) const { 1776 return xyAtT(span).fY; 1777 } 1778 1779#if DEBUG_DUMP 1780 void dump() const { 1781 const char className[] = "Segment"; 1782 const int tab = 4; 1783 for (int i = 0; i < fTs.count(); ++i) { 1784 SkPoint out; 1785 (*SegmentXYAtT[fVerb])(fPts, t(i), &out); 1786 SkDebugf("%*s [%d] %s.fTs[%d]=%1.9g (%1.9g,%1.9g) other=%d" 1787 " otherT=%1.9g windSum=%d\n", 1788 tab + sizeof(className), className, fID, 1789 kLVerbStr[fVerb], i, fTs[i].fT, out.fX, out.fY, 1790 fTs[i].fOther->fID, fTs[i].fOtherT, fTs[i].fWindSum); 1791 } 1792 SkDebugf("%*s [%d] fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)", 1793 tab + sizeof(className), className, fID, 1794 fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom); 1795 } 1796#endif 1797 1798#if DEBUG_ACTIVE_SPANS 1799 void debugShowActiveSpans(int contourID, int segmentIndex) { 1800 if (done()) { 1801 return; 1802 } 1803 for (int i = 0; i < fTs.count(); ++i) { 1804 if (fTs[i].fDone) { 1805 continue; 1806 } 1807 SkDebugf("%s contour=%d segment=%d (%d)", __FUNCTION__, contourID, 1808 segmentIndex, fID); 1809 SkDebugf(" (%1.9g,%1.9g", fPts[0].fX, fPts[0].fY); 1810 for (int vIndex = 1; vIndex <= fVerb; ++vIndex) { 1811 SkDebugf(" %1.9g,%1.9g", fPts[vIndex].fX, fPts[vIndex].fY); 1812 } 1813 const Span* span = &fTs[i]; 1814 SkDebugf(") fT=%d (%1.9g) (%1.9g,%1.9g)", i, fTs[i].fT, 1815 xAtT(span), yAtT(i)); 1816 const Segment* other = fTs[i].fOther; 1817 SkDebugf(" other=%d otherT=%1.9g otherIndex=%d", other->fID, 1818 fTs[i].fOtherT, fTs[i].fOtherIndex); 1819 SkDebugf(" windSum=%d windValue=%d\n", fTs[i].fWindSum, 1820 fTs[i].fWindValue); 1821 } 1822 } 1823#endif 1824 1825private: 1826 const SkPoint* fPts; 1827 SkPath::Verb fVerb; 1828 Bounds fBounds; 1829 SkTDArray<Span> fTs; // two or more (always includes t=0 t=1) 1830 // OPTIMIZATION:if intersections array is a pointer, the it could only 1831 // be allocated as needed instead of always initialized -- though maybe 1832 // the initialization is lightweight enough that it hardly matters 1833 mutable SkTDArray<SkPoint> fIntersections; 1834 int fDoneSpans; // used for quick check that segment is finished 1835#if DEBUG_DUMP 1836 int fID; 1837#endif 1838}; 1839 1840class Contour; 1841 1842struct Coincidence { 1843 Contour* fContours[2]; 1844 int fSegments[2]; 1845 double fTs[2][2]; 1846}; 1847 1848class Contour { 1849public: 1850 Contour() { 1851 reset(); 1852#if DEBUG_DUMP 1853 fID = ++gContourID; 1854#endif 1855 } 1856 1857 bool operator<(const Contour& rh) const { 1858 return fBounds.fTop == rh.fBounds.fTop 1859 ? fBounds.fLeft < rh.fBounds.fLeft 1860 : fBounds.fTop < rh.fBounds.fTop; 1861 } 1862 1863 void addCoincident(int index, Contour* other, int otherIndex, 1864 const Intersections& ts, bool swap) { 1865 Coincidence& coincidence = *fCoincidences.append(); 1866 coincidence.fContours[0] = this; 1867 coincidence.fContours[1] = other; 1868 coincidence.fSegments[0] = index; 1869 coincidence.fSegments[1] = otherIndex; 1870 coincidence.fTs[swap][0] = ts.fT[0][0]; 1871 coincidence.fTs[swap][1] = ts.fT[0][1]; 1872 coincidence.fTs[!swap][0] = ts.fT[1][0]; 1873 coincidence.fTs[!swap][1] = ts.fT[1][1]; 1874 } 1875 1876 void addCross(const Contour* crosser) { 1877#ifdef DEBUG_CROSS 1878 for (int index = 0; index < fCrosses.count(); ++index) { 1879 SkASSERT(fCrosses[index] != crosser); 1880 } 1881#endif 1882 *fCrosses.append() = crosser; 1883 } 1884 1885 void addCubic(const SkPoint pts[4]) { 1886 fSegments.push_back().addCubic(pts); 1887 fContainsCurves = true; 1888 } 1889 1890 int addLine(const SkPoint pts[2]) { 1891 fSegments.push_back().addLine(pts); 1892 return fSegments.count(); 1893 } 1894 1895 void addOtherT(int segIndex, int tIndex, double otherT, int otherIndex) { 1896 fSegments[segIndex].addOtherT(tIndex, otherT, otherIndex); 1897 } 1898 1899 int addQuad(const SkPoint pts[3]) { 1900 fSegments.push_back().addQuad(pts); 1901 fContainsCurves = true; 1902 return fSegments.count(); 1903 } 1904 1905 int addT(int segIndex, double newT, Contour* other, int otherIndex) { 1906 containsIntercepts(); 1907 return fSegments[segIndex].addT(newT, &other->fSegments[otherIndex]); 1908 } 1909 1910 const Bounds& bounds() const { 1911 return fBounds; 1912 } 1913 1914 void complete() { 1915 setBounds(); 1916 fContainsIntercepts = false; 1917 } 1918 1919 void containsIntercepts() { 1920 fContainsIntercepts = true; 1921 } 1922 1923 const Segment* crossedSegment(const SkPoint& basePt, SkScalar& bestY, 1924 int &tIndex, double& hitT) { 1925 int segmentCount = fSegments.count(); 1926 const Segment* bestSegment = NULL; 1927 for (int test = 0; test < segmentCount; ++test) { 1928 Segment* testSegment = &fSegments[test]; 1929 const SkRect& bounds = testSegment->bounds(); 1930 if (bounds.fTop < bestY) { 1931 continue; 1932 } 1933 if (bounds.fTop > basePt.fY) { 1934 continue; 1935 } 1936 if (bounds.fLeft > basePt.fX) { 1937 continue; 1938 } 1939 if (bounds.fRight < basePt.fX) { 1940 continue; 1941 } 1942 double testHitT; 1943 int testT = testSegment->crossedSpan(basePt, bestY, testHitT); 1944 if (testT >= 0) { 1945 bestSegment = testSegment; 1946 tIndex = testT; 1947 hitT = testHitT; 1948 } 1949 } 1950 return bestSegment; 1951 } 1952 1953 bool crosses(const Contour* crosser) const { 1954 if (this == crosser) { 1955 return true; 1956 } 1957 for (int index = 0; index < fCrosses.count(); ++index) { 1958 if (fCrosses[index] == crosser) { 1959 return true; 1960 } 1961 } 1962 return false; 1963 } 1964 1965 void findTooCloseToCall(int winding) { 1966 int segmentCount = fSegments.count(); 1967 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { 1968 fSegments[sIndex].findTooCloseToCall(winding); 1969 } 1970 } 1971 1972 void fixOtherTIndex() { 1973 int segmentCount = fSegments.count(); 1974 for (int sIndex = 0; sIndex < segmentCount; ++sIndex) { 1975 fSegments[sIndex].fixOtherTIndex(); 1976 } 1977 } 1978 1979 void reset() { 1980 fSegments.reset(); 1981 fBounds.set(SK_ScalarMax, SK_ScalarMax, SK_ScalarMax, SK_ScalarMax); 1982 fContainsCurves = fContainsIntercepts = false; 1983 fWindingSum = SK_MinS32; 1984 } 1985 1986 void resolveCoincidence(int winding) { 1987 int count = fCoincidences.count(); 1988 for (int index = 0; index < count; ++index) { 1989 Coincidence& coincidence = fCoincidences[index]; 1990 Contour* thisContour = coincidence.fContours[0]; 1991 Contour* otherContour = coincidence.fContours[1]; 1992 int thisIndex = coincidence.fSegments[0]; 1993 int otherIndex = coincidence.fSegments[1]; 1994 Segment& thisOne = thisContour->fSegments[thisIndex]; 1995 Segment& other = otherContour->fSegments[otherIndex]; 1996 double startT = coincidence.fTs[0][0]; 1997 double endT = coincidence.fTs[0][1]; 1998 if (startT > endT) { 1999 SkTSwap<double>(startT, endT); 2000 } 2001 SkASSERT(endT - startT >= FLT_EPSILON); 2002 double oStartT = coincidence.fTs[1][0]; 2003 double oEndT = coincidence.fTs[1][1]; 2004 if (oStartT > oEndT) { 2005 SkTSwap<double>(oStartT, oEndT); 2006 } 2007 SkASSERT(oEndT - oStartT >= FLT_EPSILON); 2008 if (winding > 0 || thisOne.cancels(other)) { 2009 // make sure startT and endT have t entries 2010 if (thisOne.isMissing(startT) || other.isMissing(oEndT)) { 2011 thisOne.addTPair(startT, other, oEndT); 2012 } 2013 if (thisOne.isMissing(endT) || other.isMissing(oStartT)) { 2014 other.addTPair(oStartT, thisOne, endT); 2015 } 2016 thisOne.addTCancel(startT, endT, other, oStartT, oEndT); 2017 } else { 2018 if (thisOne.isMissing(startT) || other.isMissing(oStartT)) { 2019 thisOne.addTPair(startT, other, oStartT); 2020 } 2021 if (thisOne.isMissing(endT) || other.isMissing(oEndT)) { 2022 other.addTPair(oEndT, thisOne, endT); 2023 } 2024 thisOne.addTCoincident(startT, endT, other, oStartT, oEndT); 2025 } 2026 } 2027 } 2028 2029 const SkTArray<Segment>& segments() { 2030 return fSegments; 2031 } 2032 2033 void setWinding(int winding) { 2034 SkASSERT(fWindingSum < 0); 2035 fWindingSum = winding; 2036 } 2037 2038 // OPTIMIZATION: feel pretty uneasy about this. It seems like once again 2039 // we need to sort and walk edges in y, but that on the surface opens the 2040 // same can of worms as before. But then, this is a rough sort based on 2041 // segments' top, and not a true sort, so it could be ameniable to regular 2042 // sorting instead of linear searching. Still feel like I'm missing something 2043 Segment* topSegment(SkScalar& bestY) { 2044 int segmentCount = fSegments.count(); 2045 SkASSERT(segmentCount > 0); 2046 int best = -1; 2047 Segment* bestSegment = NULL; 2048 while (++best < segmentCount) { 2049 Segment* testSegment = &fSegments[best]; 2050 if (testSegment->done()) { 2051 continue; 2052 } 2053 bestSegment = testSegment; 2054 break; 2055 } 2056 if (!bestSegment) { 2057 return NULL; 2058 } 2059 SkScalar bestTop = bestSegment->activeTop(); 2060 for (int test = best + 1; test < segmentCount; ++test) { 2061 Segment* testSegment = &fSegments[test]; 2062 if (testSegment->done()) { 2063 continue; 2064 } 2065 if (testSegment->bounds().fTop > bestTop) { 2066 continue; 2067 } 2068 SkScalar testTop = testSegment->activeTop(); 2069 if (bestTop > testTop) { 2070 bestTop = testTop; 2071 bestSegment = testSegment; 2072 } 2073 } 2074 bestY = bestTop; 2075 return bestSegment; 2076 } 2077 2078 int updateSegment(int index, const SkPoint* pts) { 2079 Segment& segment = fSegments[index]; 2080 segment.updatePts(pts); 2081 return segment.verb() + 1; 2082 } 2083 2084 int windSum() { 2085 if (fWindingSum >= 0) { 2086 return fWindingSum; 2087 } 2088 // check peers 2089 int count = fCrosses.count(); 2090 for (int index = 0; index < count; ++index) { 2091 const Contour* crosser = fCrosses[index]; 2092 if (0 <= crosser->fWindingSum) { 2093 fWindingSum = crosser->fWindingSum; 2094 break; 2095 } 2096 } 2097 return fWindingSum; 2098 } 2099 2100#if DEBUG_TEST 2101 SkTArray<Segment>& debugSegments() { 2102 return fSegments; 2103 } 2104#endif 2105 2106#if DEBUG_DUMP 2107 void dump() { 2108 int i; 2109 const char className[] = "Contour"; 2110 const int tab = 4; 2111 SkDebugf("%s %p (contour=%d)\n", className, this, fID); 2112 for (i = 0; i < fSegments.count(); ++i) { 2113 SkDebugf("%*s.fSegments[%d]:\n", tab + sizeof(className), 2114 className, i); 2115 fSegments[i].dump(); 2116 } 2117 SkDebugf("%*s.fBounds=(l:%1.9g, t:%1.9g r:%1.9g, b:%1.9g)\n", 2118 tab + sizeof(className), className, 2119 fBounds.fLeft, fBounds.fTop, 2120 fBounds.fRight, fBounds.fBottom); 2121 SkDebugf("%*s.fContainsIntercepts=%d\n", tab + sizeof(className), 2122 className, fContainsIntercepts); 2123 SkDebugf("%*s.fContainsCurves=%d\n", tab + sizeof(className), 2124 className, fContainsCurves); 2125 } 2126#endif 2127 2128#if DEBUG_ACTIVE_SPANS 2129 void debugShowActiveSpans() { 2130 for (int index = 0; index < fSegments.count(); ++index) { 2131 fSegments[index].debugShowActiveSpans(fID, index); 2132 } 2133 } 2134#endif 2135 2136protected: 2137 void setBounds() { 2138 int count = fSegments.count(); 2139 if (count == 0) { 2140 SkDebugf("%s empty contour\n", __FUNCTION__); 2141 SkASSERT(0); 2142 // FIXME: delete empty contour? 2143 return; 2144 } 2145 fBounds = fSegments.front().bounds(); 2146 for (int index = 1; index < count; ++index) { 2147 fBounds.add(fSegments[index].bounds()); 2148 } 2149 } 2150 2151private: 2152 SkTArray<Segment> fSegments; 2153 SkTDArray<Coincidence> fCoincidences; 2154 SkTDArray<const Contour*> fCrosses; 2155 Bounds fBounds; 2156 bool fContainsIntercepts; 2157 bool fContainsCurves; 2158 int fWindingSum; // initial winding number outside 2159#if DEBUG_DUMP 2160 int fID; 2161#endif 2162}; 2163 2164class EdgeBuilder { 2165public: 2166 2167EdgeBuilder(const SkPath& path, SkTArray<Contour>& contours) 2168 : fPath(path) 2169 , fCurrentContour(NULL) 2170 , fContours(contours) 2171{ 2172#if DEBUG_DUMP 2173 gContourID = 0; 2174 gSegmentID = 0; 2175#endif 2176 walk(); 2177} 2178 2179protected: 2180 2181void complete() { 2182 if (fCurrentContour && fCurrentContour->segments().count()) { 2183 fCurrentContour->complete(); 2184 fCurrentContour = NULL; 2185 } 2186} 2187 2188void walk() { 2189 // FIXME:remove once we can access path pts directly 2190 SkPath::RawIter iter(fPath); // FIXME: access path directly when allowed 2191 SkPoint pts[4]; 2192 SkPath::Verb verb; 2193 do { 2194 verb = iter.next(pts); 2195 *fPathVerbs.append() = verb; 2196 if (verb == SkPath::kMove_Verb) { 2197 *fPathPts.append() = pts[0]; 2198 } else if (verb >= SkPath::kLine_Verb && verb <= SkPath::kCubic_Verb) { 2199 fPathPts.append(verb, &pts[1]); 2200 } 2201 } while (verb != SkPath::kDone_Verb); 2202 // FIXME: end of section to remove once path pts are accessed directly 2203 2204 SkPath::Verb reducedVerb; 2205 uint8_t* verbPtr = fPathVerbs.begin(); 2206 const SkPoint* pointsPtr = fPathPts.begin(); 2207 const SkPoint* finalCurveStart = NULL; 2208 const SkPoint* finalCurveEnd = NULL; 2209 while ((verb = (SkPath::Verb) *verbPtr++) != SkPath::kDone_Verb) { 2210 switch (verb) { 2211 case SkPath::kMove_Verb: 2212 complete(); 2213 if (!fCurrentContour) { 2214 fCurrentContour = fContours.push_back_n(1); 2215 finalCurveEnd = pointsPtr++; 2216 *fExtra.append() = -1; // start new contour 2217 } 2218 continue; 2219 case SkPath::kLine_Verb: 2220 // skip degenerate points 2221 if (pointsPtr[-1].fX != pointsPtr[0].fX 2222 || pointsPtr[-1].fY != pointsPtr[0].fY) { 2223 fCurrentContour->addLine(&pointsPtr[-1]); 2224 } 2225 break; 2226 case SkPath::kQuad_Verb: 2227 2228 reducedVerb = QuadReduceOrder(&pointsPtr[-1], fReducePts); 2229 if (reducedVerb == 0) { 2230 break; // skip degenerate points 2231 } 2232 if (reducedVerb == 1) { 2233 *fExtra.append() = 2234 fCurrentContour->addLine(fReducePts.end() - 2); 2235 break; 2236 } 2237 fCurrentContour->addQuad(&pointsPtr[-1]); 2238 break; 2239 case SkPath::kCubic_Verb: 2240 reducedVerb = CubicReduceOrder(&pointsPtr[-1], fReducePts); 2241 if (reducedVerb == 0) { 2242 break; // skip degenerate points 2243 } 2244 if (reducedVerb == 1) { 2245 *fExtra.append() = 2246 fCurrentContour->addLine(fReducePts.end() - 2); 2247 break; 2248 } 2249 if (reducedVerb == 2) { 2250 *fExtra.append() = 2251 fCurrentContour->addQuad(fReducePts.end() - 3); 2252 break; 2253 } 2254 fCurrentContour->addCubic(&pointsPtr[-1]); 2255 break; 2256 case SkPath::kClose_Verb: 2257 SkASSERT(fCurrentContour); 2258 if (finalCurveStart && finalCurveEnd 2259 && *finalCurveStart != *finalCurveEnd) { 2260 *fReducePts.append() = *finalCurveStart; 2261 *fReducePts.append() = *finalCurveEnd; 2262 *fExtra.append() = 2263 fCurrentContour->addLine(fReducePts.end() - 2); 2264 } 2265 complete(); 2266 continue; 2267 default: 2268 SkDEBUGFAIL("bad verb"); 2269 return; 2270 } 2271 finalCurveStart = &pointsPtr[verb - 1]; 2272 pointsPtr += verb; 2273 SkASSERT(fCurrentContour); 2274 } 2275 complete(); 2276 if (fCurrentContour && !fCurrentContour->segments().count()) { 2277 fContours.pop_back(); 2278 } 2279 // correct pointers in contours since fReducePts may have moved as it grew 2280 int cIndex = 0; 2281 int extraCount = fExtra.count(); 2282 SkASSERT(extraCount == 0 || fExtra[0] == -1); 2283 int eIndex = 0; 2284 int rIndex = 0; 2285 while (++eIndex < extraCount) { 2286 int offset = fExtra[eIndex]; 2287 if (offset < 0) { 2288 ++cIndex; 2289 continue; 2290 } 2291 fCurrentContour = &fContours[cIndex]; 2292 rIndex += fCurrentContour->updateSegment(offset - 1, 2293 &fReducePts[rIndex]); 2294 } 2295 fExtra.reset(); // we're done with this 2296} 2297 2298private: 2299 const SkPath& fPath; 2300 SkTDArray<SkPoint> fPathPts; // FIXME: point directly to path pts instead 2301 SkTDArray<uint8_t> fPathVerbs; // FIXME: remove 2302 Contour* fCurrentContour; 2303 SkTArray<Contour>& fContours; 2304 SkTDArray<SkPoint> fReducePts; // segments created on the fly 2305 SkTDArray<int> fExtra; // -1 marks new contour, > 0 offsets into contour 2306}; 2307 2308class Work { 2309public: 2310 enum SegmentType { 2311 kHorizontalLine_Segment = -1, 2312 kVerticalLine_Segment = 0, 2313 kLine_Segment = SkPath::kLine_Verb, 2314 kQuad_Segment = SkPath::kQuad_Verb, 2315 kCubic_Segment = SkPath::kCubic_Verb, 2316 }; 2317 2318 void addCoincident(Work& other, const Intersections& ts, bool swap) { 2319 fContour->addCoincident(fIndex, other.fContour, other.fIndex, ts, swap); 2320 } 2321 2322 // FIXME: does it make sense to write otherIndex now if we're going to 2323 // fix it up later? 2324 void addOtherT(int index, double otherT, int otherIndex) { 2325 fContour->addOtherT(fIndex, index, otherT, otherIndex); 2326 } 2327 2328 // Avoid collapsing t values that are close to the same since 2329 // we walk ts to describe consecutive intersections. Since a pair of ts can 2330 // be nearly equal, any problems caused by this should be taken care 2331 // of later. 2332 // On the edge or out of range values are negative; add 2 to get end 2333 int addT(double newT, const Work& other) { 2334 return fContour->addT(fIndex, newT, other.fContour, other.fIndex); 2335 } 2336 2337 bool advance() { 2338 return ++fIndex < fLast; 2339 } 2340 2341 SkScalar bottom() const { 2342 return bounds().fBottom; 2343 } 2344 2345 const Bounds& bounds() const { 2346 return fContour->segments()[fIndex].bounds(); 2347 } 2348 2349 const SkPoint* cubic() const { 2350 return fCubic; 2351 } 2352 2353 void init(Contour* contour) { 2354 fContour = contour; 2355 fIndex = 0; 2356 fLast = contour->segments().count(); 2357 } 2358 2359 bool isAdjacent(const Work& next) { 2360 return fContour == next.fContour && fIndex + 1 == next.fIndex; 2361 } 2362 2363 bool isFirstLast(const Work& next) { 2364 return fContour == next.fContour && fIndex == 0 2365 && next.fIndex == fLast - 1; 2366 } 2367 2368 SkScalar left() const { 2369 return bounds().fLeft; 2370 } 2371 2372 void promoteToCubic() { 2373 fCubic[0] = pts()[0]; 2374 fCubic[2] = pts()[1]; 2375 fCubic[3] = pts()[2]; 2376 fCubic[1].fX = (fCubic[0].fX + fCubic[2].fX * 2) / 3; 2377 fCubic[1].fY = (fCubic[0].fY + fCubic[2].fY * 2) / 3; 2378 fCubic[2].fX = (fCubic[3].fX + fCubic[2].fX * 2) / 3; 2379 fCubic[2].fY = (fCubic[3].fY + fCubic[2].fY * 2) / 3; 2380 } 2381 2382 const SkPoint* pts() const { 2383 return fContour->segments()[fIndex].pts(); 2384 } 2385 2386 SkScalar right() const { 2387 return bounds().fRight; 2388 } 2389 2390 ptrdiff_t segmentIndex() const { 2391 return fIndex; 2392 } 2393 2394 SegmentType segmentType() const { 2395 const Segment& segment = fContour->segments()[fIndex]; 2396 SegmentType type = (SegmentType) segment.verb(); 2397 if (type != kLine_Segment) { 2398 return type; 2399 } 2400 if (segment.isHorizontal()) { 2401 return kHorizontalLine_Segment; 2402 } 2403 if (segment.isVertical()) { 2404 return kVerticalLine_Segment; 2405 } 2406 return kLine_Segment; 2407 } 2408 2409 bool startAfter(const Work& after) { 2410 fIndex = after.fIndex; 2411 return advance(); 2412 } 2413 2414 SkScalar top() const { 2415 return bounds().fTop; 2416 } 2417 2418 SkPath::Verb verb() const { 2419 return fContour->segments()[fIndex].verb(); 2420 } 2421 2422 SkScalar x() const { 2423 return bounds().fLeft; 2424 } 2425 2426 bool xFlipped() const { 2427 return x() != pts()[0].fX; 2428 } 2429 2430 SkScalar y() const { 2431 return bounds().fTop; 2432 } 2433 2434 bool yFlipped() const { 2435 return y() != pts()[0].fY; 2436 } 2437 2438protected: 2439 Contour* fContour; 2440 SkPoint fCubic[4]; 2441 int fIndex; 2442 int fLast; 2443}; 2444 2445#if DEBUG_ADD_INTERSECTING_TS 2446static void debugShowLineIntersection(int pts, const Work& wt, 2447 const Work& wn, const double wtTs[2], const double wnTs[2]) { 2448 if (!pts) { 2449 SkDebugf("%s no intersect (%1.9g,%1.9g %1.9g,%1.9g) (%1.9g,%1.9g %1.9g,%1.9g)\n", 2450 __FUNCTION__, wt.pts()[0].fX, wt.pts()[0].fY, 2451 wt.pts()[1].fX, wt.pts()[1].fY, wn.pts()[0].fX, wn.pts()[0].fY, 2452 wn.pts()[1].fX, wn.pts()[1].fY); 2453 return; 2454 } 2455 SkPoint wtOutPt, wnOutPt; 2456 LineXYAtT(wt.pts(), wtTs[0], &wtOutPt); 2457 LineXYAtT(wn.pts(), wnTs[0], &wnOutPt); 2458 SkDebugf("%s wtTs[0]=%g (%g,%g, %g,%g) (%g,%g)", 2459 __FUNCTION__, 2460 wtTs[0], wt.pts()[0].fX, wt.pts()[0].fY, 2461 wt.pts()[1].fX, wt.pts()[1].fY, wtOutPt.fX, wtOutPt.fY); 2462 if (pts == 2) { 2463 SkDebugf(" wtTs[1]=%g", wtTs[1]); 2464 } 2465 SkDebugf(" wnTs[0]=%g (%g,%g, %g,%g) (%g,%g)", 2466 wnTs[0], wn.pts()[0].fX, wn.pts()[0].fY, 2467 wn.pts()[1].fX, wn.pts()[1].fY, wnOutPt.fX, wnOutPt.fY); 2468 if (pts == 2) { 2469 SkDebugf(" wnTs[1]=%g", wnTs[1]); 2470 } 2471 SkDebugf("\n"); 2472} 2473#else 2474static void debugShowLineIntersection(int , const Work& , 2475 const Work& , const double [2], const double [2]) { 2476} 2477#endif 2478 2479static bool addIntersectTs(Contour* test, Contour* next) { 2480 2481 if (test != next) { 2482 if (test->bounds().fBottom < next->bounds().fTop) { 2483 return false; 2484 } 2485 if (!Bounds::Intersects(test->bounds(), next->bounds())) { 2486 return true; 2487 } 2488 } 2489 Work wt; 2490 wt.init(test); 2491 bool foundCommonContour = test == next; 2492 do { 2493 Work wn; 2494 wn.init(next); 2495 if (test == next && !wn.startAfter(wt)) { 2496 continue; 2497 } 2498 do { 2499 if (!Bounds::Intersects(wt.bounds(), wn.bounds())) { 2500 continue; 2501 } 2502 int pts; 2503 Intersections ts; 2504 bool swap = false; 2505 switch (wt.segmentType()) { 2506 case Work::kHorizontalLine_Segment: 2507 swap = true; 2508 switch (wn.segmentType()) { 2509 case Work::kHorizontalLine_Segment: 2510 case Work::kVerticalLine_Segment: 2511 case Work::kLine_Segment: { 2512 pts = HLineIntersect(wn.pts(), wt.left(), 2513 wt.right(), wt.y(), wt.xFlipped(), ts); 2514 debugShowLineIntersection(pts, wt, wn, 2515 ts.fT[1], ts.fT[0]); 2516 break; 2517 } 2518 case Work::kQuad_Segment: { 2519 pts = HQuadIntersect(wn.pts(), wt.left(), 2520 wt.right(), wt.y(), wt.xFlipped(), ts); 2521 break; 2522 } 2523 case Work::kCubic_Segment: { 2524 pts = HCubicIntersect(wn.pts(), wt.left(), 2525 wt.right(), wt.y(), wt.xFlipped(), ts); 2526 break; 2527 } 2528 default: 2529 SkASSERT(0); 2530 } 2531 break; 2532 case Work::kVerticalLine_Segment: 2533 swap = true; 2534 switch (wn.segmentType()) { 2535 case Work::kHorizontalLine_Segment: 2536 case Work::kVerticalLine_Segment: 2537 case Work::kLine_Segment: { 2538 pts = VLineIntersect(wn.pts(), wt.top(), 2539 wt.bottom(), wt.x(), wt.yFlipped(), ts); 2540 debugShowLineIntersection(pts, wt, wn, 2541 ts.fT[1], ts.fT[0]); 2542 break; 2543 } 2544 case Work::kQuad_Segment: { 2545 pts = VQuadIntersect(wn.pts(), wt.top(), 2546 wt.bottom(), wt.x(), wt.yFlipped(), ts); 2547 break; 2548 } 2549 case Work::kCubic_Segment: { 2550 pts = VCubicIntersect(wn.pts(), wt.top(), 2551 wt.bottom(), wt.x(), wt.yFlipped(), ts); 2552 break; 2553 } 2554 default: 2555 SkASSERT(0); 2556 } 2557 break; 2558 case Work::kLine_Segment: 2559 switch (wn.segmentType()) { 2560 case Work::kHorizontalLine_Segment: 2561 pts = HLineIntersect(wt.pts(), wn.left(), 2562 wn.right(), wn.y(), wn.xFlipped(), ts); 2563 debugShowLineIntersection(pts, wt, wn, 2564 ts.fT[1], ts.fT[0]); 2565 break; 2566 case Work::kVerticalLine_Segment: 2567 pts = VLineIntersect(wt.pts(), wn.top(), 2568 wn.bottom(), wn.x(), wn.yFlipped(), ts); 2569 debugShowLineIntersection(pts, wt, wn, 2570 ts.fT[1], ts.fT[0]); 2571 break; 2572 case Work::kLine_Segment: { 2573 pts = LineIntersect(wt.pts(), wn.pts(), ts); 2574 debugShowLineIntersection(pts, wt, wn, 2575 ts.fT[1], ts.fT[0]); 2576 break; 2577 } 2578 case Work::kQuad_Segment: { 2579 swap = true; 2580 pts = QuadLineIntersect(wn.pts(), wt.pts(), ts); 2581 break; 2582 } 2583 case Work::kCubic_Segment: { 2584 swap = true; 2585 pts = CubicLineIntersect(wn.pts(), wt.pts(), ts); 2586 break; 2587 } 2588 default: 2589 SkASSERT(0); 2590 } 2591 break; 2592 case Work::kQuad_Segment: 2593 switch (wn.segmentType()) { 2594 case Work::kHorizontalLine_Segment: 2595 pts = HQuadIntersect(wt.pts(), wn.left(), 2596 wn.right(), wn.y(), wn.xFlipped(), ts); 2597 break; 2598 case Work::kVerticalLine_Segment: 2599 pts = VQuadIntersect(wt.pts(), wn.top(), 2600 wn.bottom(), wn.x(), wn.yFlipped(), ts); 2601 break; 2602 case Work::kLine_Segment: { 2603 pts = QuadLineIntersect(wt.pts(), wn.pts(), ts); 2604 break; 2605 } 2606 case Work::kQuad_Segment: { 2607 pts = QuadIntersect(wt.pts(), wn.pts(), ts); 2608 break; 2609 } 2610 case Work::kCubic_Segment: { 2611 wt.promoteToCubic(); 2612 pts = CubicIntersect(wt.cubic(), wn.pts(), ts); 2613 break; 2614 } 2615 default: 2616 SkASSERT(0); 2617 } 2618 break; 2619 case Work::kCubic_Segment: 2620 switch (wn.segmentType()) { 2621 case Work::kHorizontalLine_Segment: 2622 pts = HCubicIntersect(wt.pts(), wn.left(), 2623 wn.right(), wn.y(), wn.xFlipped(), ts); 2624 break; 2625 case Work::kVerticalLine_Segment: 2626 pts = VCubicIntersect(wt.pts(), wn.top(), 2627 wn.bottom(), wn.x(), wn.yFlipped(), ts); 2628 break; 2629 case Work::kLine_Segment: { 2630 pts = CubicLineIntersect(wt.pts(), wn.pts(), ts); 2631 break; 2632 } 2633 case Work::kQuad_Segment: { 2634 wn.promoteToCubic(); 2635 pts = CubicIntersect(wt.pts(), wn.cubic(), ts); 2636 break; 2637 } 2638 case Work::kCubic_Segment: { 2639 pts = CubicIntersect(wt.pts(), wn.pts(), ts); 2640 break; 2641 } 2642 default: 2643 SkASSERT(0); 2644 } 2645 break; 2646 default: 2647 SkASSERT(0); 2648 } 2649 if (!foundCommonContour && pts > 0) { 2650 test->addCross(next); 2651 next->addCross(test); 2652 foundCommonContour = true; 2653 } 2654 // in addition to recording T values, record matching segment 2655 if (pts == 2 && wn.segmentType() <= Work::kLine_Segment 2656 && wt.segmentType() <= Work::kLine_Segment) { 2657 wt.addCoincident(wn, ts, swap); 2658 continue; 2659 } 2660 for (int pt = 0; pt < pts; ++pt) { 2661 SkASSERT(ts.fT[0][pt] >= 0 && ts.fT[0][pt] <= 1); 2662 SkASSERT(ts.fT[1][pt] >= 0 && ts.fT[1][pt] <= 1); 2663 int testTAt = wt.addT(ts.fT[swap][pt], wn); 2664 int nextTAt = wn.addT(ts.fT[!swap][pt], wt); 2665 wt.addOtherT(testTAt, ts.fT[!swap][pt], nextTAt); 2666 wn.addOtherT(nextTAt, ts.fT[swap][pt], testTAt); 2667 } 2668 } while (wn.advance()); 2669 } while (wt.advance()); 2670 return true; 2671} 2672 2673// resolve any coincident pairs found while intersecting, and 2674// see if coincidence is formed by clipping non-concident segments 2675static void coincidenceCheck(SkTDArray<Contour*>& contourList, int winding) { 2676 int contourCount = contourList.count(); 2677 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 2678 Contour* contour = contourList[cIndex]; 2679 contour->findTooCloseToCall(winding); 2680 } 2681 for (int cIndex = 0; cIndex < contourCount; ++cIndex) { 2682 Contour* contour = contourList[cIndex]; 2683 contour->resolveCoincidence(winding); 2684 } 2685} 2686 2687// project a ray from the top of the contour up and see if it hits anything 2688// note: when we compute line intersections, we keep track of whether 2689// two contours touch, so we need only look at contours not touching this one. 2690// OPTIMIZATION: sort contourList vertically to avoid linear walk 2691static int innerContourCheck(SkTDArray<Contour*>& contourList, 2692 Contour* baseContour, const SkPoint& basePt) { 2693 int contourCount = contourList.count(); 2694 int winding = 0; 2695 SkScalar bestY = SK_ScalarMin; 2696 for (int cTest = 0; cTest < contourCount; ++cTest) { 2697 Contour* contour = contourList[cTest]; 2698 if (basePt.fY < contour->bounds().fTop) { 2699 continue; 2700 } 2701 if (bestY > contour->bounds().fBottom) { 2702 continue; 2703 } 2704 if (baseContour->crosses(contour)) { 2705 continue; 2706 } 2707 int tIndex; 2708 double tHit; 2709 const Segment* test = contour->crossedSegment(basePt, bestY, tIndex, 2710 tHit); 2711 if (!test) { 2712 continue; 2713 } 2714 // If the ray hit the end of a span, we need to construct the wheel of 2715 // angles to find the span closest to the ray -- even if there are just 2716 // two spokes on the wheel. 2717 if (tHit == test->t(tIndex)) { 2718 SkTDArray<Angle> angles; 2719 int end = test->nextSpan(tIndex, 1); 2720 if (end < 0) { 2721 end = test->nextSpan(tIndex, -1); 2722 } 2723 test->addTwoAngles(tIndex, end, angles); 2724 // test->buildAnglesInner(tIndex, angles); 2725 test->buildAngles(tIndex, angles); 2726 SkTDArray<Angle*> sorted; 2727 sortAngles(angles, sorted); 2728 const Angle* angle = sorted[0]; 2729 test = angle->segment(); 2730 SkScalar testDx = (*SegmentDXAtT[test->verb()])(test->pts(), tHit); 2731 if (testDx == 0) { 2732 angle = *(sorted.end() - 1); 2733 test = angle->segment(); 2734 SkASSERT((*SegmentDXAtT[test->verb()])(test->pts(), tHit) != 0); 2735 } 2736 tIndex = angle->start(); // lesser Y 2737 winding = test->windSum(SkMin32(tIndex, angle->end())); 2738 #if DEBUG_WINDING 2739 SkDebugf("%s 1 winding=%d\n", __FUNCTION__, winding); 2740 #endif 2741 } else { 2742 winding = test->windSum(tIndex); 2743 #if DEBUG_WINDING 2744 SkDebugf("%s 2 winding=%d\n", __FUNCTION__, winding); 2745 #endif 2746 } 2747 // see if a + change in T results in a +/- change in X (compute x'(T)) 2748 SkScalar dx = (*SegmentDXAtT[test->verb()])(test->pts(), tHit); 2749 #if DEBUG_WINDING 2750 SkDebugf("%s dx=%1.9g\n", __FUNCTION__, dx); 2751 #endif 2752 SkASSERT(dx != 0); 2753 if (winding * dx > 0) { // if same signs, result is negative 2754 winding += dx > 0 ? -1 : 1; 2755 #if DEBUG_WINDING 2756 SkDebugf("%s 3 winding=%d\n", __FUNCTION__, winding); 2757 #endif 2758 } 2759 } 2760 baseContour->setWinding(winding); 2761 return winding; 2762} 2763 2764// OPTIMIZATION: not crazy about linear search here to find top active y. 2765// seems like we should break down and do the sort, or maybe sort each 2766// contours' segments? 2767// Once the segment array is built, there's no reason I can think of not to 2768// sort it in Y. hmmm 2769// FIXME: return the contour found to pass to inner contour check 2770static Segment* findTopContour(SkTDArray<Contour*>& contourList, 2771 Contour*& topContour) { 2772 int contourCount = contourList.count(); 2773 int cIndex = 0; 2774 Segment* topStart; 2775 SkScalar bestY = SK_ScalarMax; 2776 Contour* contour; 2777 do { 2778 contour = contourList[cIndex]; 2779 topStart = contour->topSegment(bestY); 2780 } while (!topStart && ++cIndex < contourCount); 2781 if (!topStart) { 2782 return NULL; 2783 } 2784 topContour = contour; 2785 while (++cIndex < contourCount) { 2786 contour = contourList[cIndex]; 2787 if (bestY < contour->bounds().fTop) { 2788 continue; 2789 } 2790 SkScalar testY = SK_ScalarMax; 2791 Segment* test = contour->topSegment(testY); 2792 if (!test || bestY <= testY) { 2793 continue; 2794 } 2795 topContour = contour; 2796 topStart = test; 2797 bestY = testY; 2798 } 2799 return topStart; 2800} 2801 2802static Segment* findChase(SkTDArray<Span*>& chase, int& tIndex, int& endIndex) { 2803 while (chase.count()) { 2804 Span* span = chase[chase.count() - 1]; 2805 const Span& backPtr = span->fOther->span(span->fOtherIndex); 2806 Segment* segment = backPtr.fOther; 2807 tIndex = backPtr.fOtherIndex; 2808 SkTDArray<Angle> angles; 2809 int done = 0; 2810 if (segment->activeAngle(tIndex, done, angles)) { 2811 Angle* last = angles.end() - 1; 2812 tIndex = last->start(); 2813 endIndex = last->end(); 2814 return last->segment(); 2815 } 2816 if (done == angles.count()) { 2817 chase.pop(&span); 2818 continue; 2819 } 2820 SkTDArray<Angle*> sorted; 2821 sortAngles(angles, sorted); 2822 // find first angle, initialize winding to computed fWindSum 2823 int firstIndex = -1; 2824 const Angle* angle; 2825 int winding; 2826 do { 2827 angle = sorted[++firstIndex]; 2828 winding = angle->segment()->windSum(angle); 2829 } while (winding == SK_MinS32); 2830 int firstSign = angle->sign(); 2831 if (firstSign * winding > 0) { 2832 winding -= firstSign; 2833 } 2834 SkDebugf("%s firstSign=%d\n", __FUNCTION__, firstSign); 2835 // we care about first sign and whether wind sum indicates this 2836 // edge is inside or outside. Maybe need to pass span winding 2837 // or first winding or something into this function? 2838 // advance to first undone angle, then return it and winding 2839 // (to set whether edges are active or not) 2840 int nextIndex = firstIndex + 1; 2841 int angleCount = sorted.count(); 2842 int lastIndex = firstIndex != 0 ? firstIndex : angleCount; 2843 do { 2844 SkASSERT(nextIndex != firstIndex); 2845 if (nextIndex == angleCount) { 2846 nextIndex = 0; 2847 } 2848 const Angle* angle = sorted[nextIndex]; 2849 segment = angle->segment(); 2850 int windValue = segment->windValue(angle); 2851 SkASSERT(windValue > 0); 2852 int maxWinding = winding; 2853 winding -= angle->sign() * windValue; 2854 if (maxWinding * winding < 0) { 2855 SkDebugf("%s flipped sign %d %d\n", __FUNCTION__, maxWinding, winding); 2856 } 2857 tIndex = angle->start(); 2858 endIndex = angle->end(); 2859 int lesser = SkMin32(tIndex, endIndex); 2860 const Span& nextSpan = segment->span(lesser); 2861 if (!nextSpan.fDone) { 2862 // FIXME: this be wrong. assign startWinding if edge is in 2863 // same direction. If the direction is opposite, winding to 2864 // assign is flipped sign or +/- 1? 2865 if (abs(maxWinding) < abs(winding)) { 2866 maxWinding = winding; 2867 } 2868 segment->markWinding(lesser, maxWinding); 2869 break; 2870 } 2871 } while (++nextIndex != lastIndex); 2872 return segment; 2873 } 2874 return NULL; 2875} 2876 2877#if DEBUG_ACTIVE_SPANS 2878static void debugShowActiveSpans(SkTDArray<Contour*>& contourList) { 2879 for (int index = 0; index < contourList.count(); ++ index) { 2880 contourList[index]->debugShowActiveSpans(); 2881 } 2882} 2883#endif 2884 2885// Each segment may have an inside or an outside. Segments contained within 2886// winding may have insides on either side, and form a contour that should be 2887// ignored. Segments that are coincident with opposing direction segments may 2888// have outsides on either side, and should also disappear. 2889// 'Normal' segments will have one inside and one outside. Subsequent connections 2890// when winding should follow the intersection direction. If more than one edge 2891// is an option, choose first edge that continues the inside. 2892 // since we start with leftmost top edge, we'll traverse through a 2893 // smaller angle counterclockwise to get to the next edge. 2894static void bridge(SkTDArray<Contour*>& contourList, SkPath& simple) { 2895 bool firstContour = true; 2896 do { 2897 Contour* topContour; 2898 Segment* topStart = findTopContour(contourList, topContour); 2899 if (!topStart) { 2900 break; 2901 } 2902 // Start at the top. Above the top is outside, below is inside. 2903 // follow edges to intersection by changing the index by direction. 2904 int index, endIndex; 2905 Segment* current = topStart->findTop(index, endIndex); 2906 int contourWinding; 2907 if (firstContour) { 2908 contourWinding = 0; 2909 firstContour = false; 2910 } else { 2911 const SkPoint& topPoint = current->xyAtT(endIndex); 2912 contourWinding = innerContourCheck(contourList, topContour, topPoint); 2913#if DEBUG_WINDING 2914 SkDebugf("%s contourWinding=%d\n", __FUNCTION__, contourWinding); 2915#endif 2916 } 2917 SkPoint lastPt; 2918 bool firstTime = true; 2919 int winding = contourWinding; 2920 int spanWinding = current->spanSign(index, endIndex); 2921 // int firstWinding = contourWinding + spanWinding; 2922 // FIXME: needs work. While it works in limited situations, it does 2923 // not always compute winding correctly. Active should be removed and instead 2924 // the initial winding should be correctly passed in so that if the 2925 // inner contour is wound the same way, it never finds an accumulated 2926 // winding of zero. Inside 'find next', we need to look for transitions 2927 // other than zero when resolving sorted angles. 2928 SkTDArray<Span*> chaseArray; 2929 do { 2930 bool active = winding * spanWinding <= 0; 2931 const SkPoint* firstPt = NULL; 2932 do { 2933 SkASSERT(!current->done()); 2934 int nextStart, nextEnd, flipped = 1; 2935 Segment* next = current->findNext(chaseArray, 2936 winding + spanWinding, index, 2937 endIndex, nextStart, nextEnd, flipped, firstTime); 2938 if (!next) { 2939 break; 2940 } 2941 if (!firstPt) { 2942 firstPt = ¤t->addMoveTo(index, simple, active); 2943 } 2944 lastPt = current->addCurveTo(index, endIndex, simple, active); 2945 current = next; 2946 index = nextStart; 2947 endIndex = nextEnd; 2948 spanWinding = SkSign32(spanWinding) * flipped * next->windValue( 2949 SkMin32(nextStart, nextEnd)); 2950 #if DEBUG_WINDING 2951 SkDebugf("%s spanWinding=%d\n", __FUNCTION__, spanWinding); 2952 #endif 2953 firstTime = false; 2954 } while (*firstPt != lastPt && (active || !current->done())); 2955 if (firstPt && active) { 2956 #if DEBUG_PATH_CONSTRUCTION 2957 SkDebugf("%s close\n", __FUNCTION__); 2958 #endif 2959 simple.close(); 2960 } 2961 current = findChase(chaseArray, index, endIndex); 2962#if DEBUG_ACTIVE_SPANS 2963 debugShowActiveSpans(contourList); 2964#endif 2965 if (!current) { 2966 break; 2967 } 2968 int lesser = SkMin32(index, endIndex); 2969 spanWinding = current->windSum(lesser); 2970 int spanValue = current->windValue(lesser); 2971 SkASSERT(spanWinding != SK_MinS32); 2972 int spanSign = current->spanSign(index, endIndex); 2973 #if DEBUG_WINDING 2974 SkDebugf("%s spanWinding=%d spanSign=%d winding=%d spanValue=%d\n", 2975 __FUNCTION__, spanWinding, spanSign, winding, spanValue); 2976 #endif 2977 if (spanWinding * spanSign < 0) { 2978 #if DEBUG_WINDING 2979 SkDebugf("%s spanWinding * spanSign < 0\n", __FUNCTION__); 2980 #endif 2981 // SkTSwap<int>(index, endIndex); 2982 } 2983 if (abs(spanWinding) > spanValue) { 2984 #if DEBUG_WINDING 2985 SkDebugf("%s abs(spanWinding) > spanValue\n", __FUNCTION__); 2986 #endif 2987 winding = spanWinding; 2988 spanWinding = spanValue * SkSign32(spanWinding); 2989 winding -= spanWinding; 2990 } 2991 } while (true); 2992 } while (true); 2993} 2994 2995static void fixOtherTIndex(SkTDArray<Contour*>& contourList) { 2996 int contourCount = contourList.count(); 2997 for (int cTest = 0; cTest < contourCount; ++cTest) { 2998 Contour* contour = contourList[cTest]; 2999 contour->fixOtherTIndex(); 3000 } 3001} 3002 3003static void makeContourList(SkTArray<Contour>& contours, 3004 SkTDArray<Contour*>& list) { 3005 int count = contours.count(); 3006 if (count == 0) { 3007 return; 3008 } 3009 for (int index = 0; index < count; ++index) { 3010 *list.append() = &contours[index]; 3011 } 3012 QSort<Contour>(list.begin(), list.end() - 1); 3013} 3014 3015void simplifyx(const SkPath& path, SkPath& simple) { 3016 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness 3017 int winding = (path.getFillType() & 1) ? 1 : -1; 3018 simple.reset(); 3019 simple.setFillType(SkPath::kEvenOdd_FillType); 3020 3021 // turn path into list of segments 3022 SkTArray<Contour> contours; 3023 // FIXME: add self-intersecting cubics' T values to segment 3024 EdgeBuilder builder(path, contours); 3025 SkTDArray<Contour*> contourList; 3026 makeContourList(contours, contourList); 3027 Contour** currentPtr = contourList.begin(); 3028 if (!currentPtr) { 3029 return; 3030 } 3031 Contour** listEnd = contourList.end(); 3032 // find all intersections between segments 3033 do { 3034 Contour** nextPtr = currentPtr; 3035 Contour* current = *currentPtr++; 3036 Contour* next; 3037 do { 3038 next = *nextPtr++; 3039 } while (addIntersectTs(current, next) && nextPtr != listEnd); 3040 } while (currentPtr != listEnd); 3041 // eat through coincident edges 3042 coincidenceCheck(contourList, winding); 3043 fixOtherTIndex(contourList); 3044 // construct closed contours 3045 bridge(contourList, simple); 3046} 3047 3048