SkScan_Path.cpp revision 96fcdcc219d2a0d3579719b84b28bede76efba64
1/* 2 * Copyright 2006 The Android Open Source Project 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 8#include "SkScanPriv.h" 9#include "SkBlitter.h" 10#include "SkEdge.h" 11#include "SkEdgeBuilder.h" 12#include "SkGeometry.h" 13#include "SkPath.h" 14#include "SkQuadClipper.h" 15#include "SkRasterClip.h" 16#include "SkRegion.h" 17#include "SkTemplates.h" 18#include "SkTSort.h" 19 20#define kEDGE_HEAD_Y SK_MinS32 21#define kEDGE_TAIL_Y SK_MaxS32 22 23#ifdef SK_DEBUG 24 static void validate_sort(const SkEdge* edge) { 25 int y = kEDGE_HEAD_Y; 26 27 while (edge->fFirstY != SK_MaxS32) { 28 edge->validate(); 29 SkASSERT(y <= edge->fFirstY); 30 31 y = edge->fFirstY; 32 edge = edge->fNext; 33 } 34 } 35#else 36 #define validate_sort(edge) 37#endif 38 39static inline void remove_edge(SkEdge* edge) { 40 edge->fPrev->fNext = edge->fNext; 41 edge->fNext->fPrev = edge->fPrev; 42} 43 44static inline void insert_edge_after(SkEdge* edge, SkEdge* afterMe) { 45 edge->fPrev = afterMe; 46 edge->fNext = afterMe->fNext; 47 afterMe->fNext->fPrev = edge; 48 afterMe->fNext = edge; 49} 50 51static void backward_insert_edge_based_on_x(SkEdge* edge SkDECLAREPARAM(int, curr_y)) { 52 SkFixed x = edge->fX; 53 54 SkEdge* prev = edge->fPrev; 55 while (prev->fX > x) { 56 prev = prev->fPrev; 57 } 58 if (prev->fNext != edge) { 59 remove_edge(edge); 60 insert_edge_after(edge, prev); 61 } 62} 63 64static void insert_new_edges(SkEdge* newEdge, int curr_y) { 65 SkASSERT(newEdge->fFirstY >= curr_y); 66 67 while (newEdge->fFirstY == curr_y) { 68 SkEdge* next = newEdge->fNext; 69 backward_insert_edge_based_on_x(newEdge SkPARAM(curr_y)); 70 newEdge = next; 71 } 72} 73 74#ifdef SK_DEBUG 75static void validate_edges_for_y(const SkEdge* edge, int curr_y) { 76 while (edge->fFirstY <= curr_y) { 77 SkASSERT(edge->fPrev && edge->fNext); 78 SkASSERT(edge->fPrev->fNext == edge); 79 SkASSERT(edge->fNext->fPrev == edge); 80 SkASSERT(edge->fFirstY <= edge->fLastY); 81 82 SkASSERT(edge->fPrev->fX <= edge->fX); 83 edge = edge->fNext; 84 } 85} 86#else 87 #define validate_edges_for_y(edge, curr_y) 88#endif 89 90#if defined _WIN32 && _MSC_VER >= 1300 // disable warning : local variable used without having been initialized 91#pragma warning ( push ) 92#pragma warning ( disable : 4701 ) 93#endif 94 95typedef void (*PrePostProc)(SkBlitter* blitter, int y, bool isStartOfScanline); 96#define PREPOST_START true 97#define PREPOST_END false 98 99static void walk_edges(SkEdge* prevHead, SkPath::FillType fillType, 100 SkBlitter* blitter, int start_y, int stop_y, 101 PrePostProc proc, int rightClip) { 102 validate_sort(prevHead->fNext); 103 104 int curr_y = start_y; 105 // returns 1 for evenodd, -1 for winding, regardless of inverse-ness 106 int windingMask = (fillType & 1) ? 1 : -1; 107 108 for (;;) { 109 int w = 0; 110 int left SK_INIT_TO_AVOID_WARNING; 111 bool in_interval = false; 112 SkEdge* currE = prevHead->fNext; 113 SkFixed prevX = prevHead->fX; 114 115 validate_edges_for_y(currE, curr_y); 116 117 if (proc) { 118 proc(blitter, curr_y, PREPOST_START); // pre-proc 119 } 120 121 while (currE->fFirstY <= curr_y) { 122 SkASSERT(currE->fLastY >= curr_y); 123 124 int x = SkFixedRoundToInt(currE->fX); 125 w += currE->fWinding; 126 if ((w & windingMask) == 0) { // we finished an interval 127 SkASSERT(in_interval); 128 int width = x - left; 129 SkASSERT(width >= 0); 130 if (width) 131 blitter->blitH(left, curr_y, width); 132 in_interval = false; 133 } else if (!in_interval) { 134 left = x; 135 in_interval = true; 136 } 137 138 SkEdge* next = currE->fNext; 139 SkFixed newX; 140 141 if (currE->fLastY == curr_y) { // are we done with this edge? 142 if (currE->fCurveCount < 0) { 143 if (((SkCubicEdge*)currE)->updateCubic()) { 144 SkASSERT(currE->fFirstY == curr_y + 1); 145 146 newX = currE->fX; 147 goto NEXT_X; 148 } 149 } else if (currE->fCurveCount > 0) { 150 if (((SkQuadraticEdge*)currE)->updateQuadratic()) { 151 newX = currE->fX; 152 goto NEXT_X; 153 } 154 } 155 remove_edge(currE); 156 } else { 157 SkASSERT(currE->fLastY > curr_y); 158 newX = currE->fX + currE->fDX; 159 currE->fX = newX; 160 NEXT_X: 161 if (newX < prevX) { // ripple currE backwards until it is x-sorted 162 backward_insert_edge_based_on_x(currE SkPARAM(curr_y)); 163 } else { 164 prevX = newX; 165 } 166 } 167 currE = next; 168 SkASSERT(currE); 169 } 170 171 // was our right-edge culled away? 172 if (in_interval) { 173 int width = rightClip - left; 174 if (width > 0) { 175 blitter->blitH(left, curr_y, width); 176 } 177 } 178 179 if (proc) { 180 proc(blitter, curr_y, PREPOST_END); // post-proc 181 } 182 183 curr_y += 1; 184 if (curr_y >= stop_y) { 185 break; 186 } 187 // now currE points to the first edge with a Yint larger than curr_y 188 insert_new_edges(currE, curr_y); 189 } 190} 191 192// return true if we're done with this edge 193static bool update_edge(SkEdge* edge, int last_y) { 194 SkASSERT(edge->fLastY >= last_y); 195 if (last_y == edge->fLastY) { 196 if (edge->fCurveCount < 0) { 197 if (((SkCubicEdge*)edge)->updateCubic()) { 198 SkASSERT(edge->fFirstY == last_y + 1); 199 return false; 200 } 201 } else if (edge->fCurveCount > 0) { 202 if (((SkQuadraticEdge*)edge)->updateQuadratic()) { 203 SkASSERT(edge->fFirstY == last_y + 1); 204 return false; 205 } 206 } 207 return true; 208 } 209 return false; 210} 211 212static void walk_convex_edges(SkEdge* prevHead, SkPath::FillType, 213 SkBlitter* blitter, int start_y, int stop_y, 214 PrePostProc proc) { 215 validate_sort(prevHead->fNext); 216 217 SkEdge* leftE = prevHead->fNext; 218 SkEdge* riteE = leftE->fNext; 219 SkEdge* currE = riteE->fNext; 220 221#if 0 222 int local_top = leftE->fFirstY; 223 SkASSERT(local_top == riteE->fFirstY); 224#else 225 // our edge choppers for curves can result in the initial edges 226 // not lining up, so we take the max. 227 int local_top = SkMax32(leftE->fFirstY, riteE->fFirstY); 228#endif 229 SkASSERT(local_top >= start_y); 230 231 for (;;) { 232 SkASSERT(leftE->fFirstY <= stop_y); 233 SkASSERT(riteE->fFirstY <= stop_y); 234 235 if (leftE->fX > riteE->fX || (leftE->fX == riteE->fX && 236 leftE->fDX > riteE->fDX)) { 237 SkTSwap(leftE, riteE); 238 } 239 240 int local_bot = SkMin32(leftE->fLastY, riteE->fLastY); 241 local_bot = SkMin32(local_bot, stop_y - 1); 242 SkASSERT(local_top <= local_bot); 243 244 SkFixed left = leftE->fX; 245 SkFixed dLeft = leftE->fDX; 246 SkFixed rite = riteE->fX; 247 SkFixed dRite = riteE->fDX; 248 int count = local_bot - local_top; 249 SkASSERT(count >= 0); 250 if (0 == (dLeft | dRite)) { 251 int L = SkFixedRoundToInt(left); 252 int R = SkFixedRoundToInt(rite); 253 if (L < R) { 254 count += 1; 255 blitter->blitRect(L, local_top, R - L, count); 256 } 257 local_top = local_bot + 1; 258 } else { 259 do { 260 int L = SkFixedRoundToInt(left); 261 int R = SkFixedRoundToInt(rite); 262 if (L < R) { 263 blitter->blitH(L, local_top, R - L); 264 } 265 left += dLeft; 266 rite += dRite; 267 local_top += 1; 268 } while (--count >= 0); 269 } 270 271 leftE->fX = left; 272 riteE->fX = rite; 273 274 if (update_edge(leftE, local_bot)) { 275 if (currE->fFirstY >= stop_y) { 276 break; 277 } 278 leftE = currE; 279 currE = currE->fNext; 280 } 281 if (update_edge(riteE, local_bot)) { 282 if (currE->fFirstY >= stop_y) { 283 break; 284 } 285 riteE = currE; 286 currE = currE->fNext; 287 } 288 289 SkASSERT(leftE); 290 SkASSERT(riteE); 291 292 // check our bottom clip 293 SkASSERT(local_top == local_bot + 1); 294 if (local_top >= stop_y) { 295 break; 296 } 297 } 298} 299 300/////////////////////////////////////////////////////////////////////////////// 301 302// this guy overrides blitH, and will call its proxy blitter with the inverse 303// of the spans it is given (clipped to the left/right of the cliprect) 304// 305// used to implement inverse filltypes on paths 306// 307class InverseBlitter : public SkBlitter { 308public: 309 void setBlitter(SkBlitter* blitter, const SkIRect& clip, int shift) { 310 fBlitter = blitter; 311 fFirstX = clip.fLeft << shift; 312 fLastX = clip.fRight << shift; 313 } 314 void prepost(int y, bool isStart) { 315 if (isStart) { 316 fPrevX = fFirstX; 317 } else { 318 int invWidth = fLastX - fPrevX; 319 if (invWidth > 0) { 320 fBlitter->blitH(fPrevX, y, invWidth); 321 } 322 } 323 } 324 325 // overrides 326 void blitH(int x, int y, int width) override { 327 int invWidth = x - fPrevX; 328 if (invWidth > 0) { 329 fBlitter->blitH(fPrevX, y, invWidth); 330 } 331 fPrevX = x + width; 332 } 333 334 // we do not expect to get called with these entrypoints 335 void blitAntiH(int, int, const SkAlpha[], const int16_t runs[]) override { 336 SkDEBUGFAIL("blitAntiH unexpected"); 337 } 338 void blitV(int x, int y, int height, SkAlpha alpha) override { 339 SkDEBUGFAIL("blitV unexpected"); 340 } 341 void blitRect(int x, int y, int width, int height) override { 342 SkDEBUGFAIL("blitRect unexpected"); 343 } 344 void blitMask(const SkMask&, const SkIRect& clip) override { 345 SkDEBUGFAIL("blitMask unexpected"); 346 } 347 const SkPixmap* justAnOpaqueColor(uint32_t* value) override { 348 SkDEBUGFAIL("justAnOpaqueColor unexpected"); 349 return nullptr; 350 } 351 352private: 353 SkBlitter* fBlitter; 354 int fFirstX, fLastX, fPrevX; 355}; 356 357static void PrePostInverseBlitterProc(SkBlitter* blitter, int y, bool isStart) { 358 ((InverseBlitter*)blitter)->prepost(y, isStart); 359} 360 361/////////////////////////////////////////////////////////////////////////////// 362 363#if defined _WIN32 && _MSC_VER >= 1300 364#pragma warning ( pop ) 365#endif 366 367static bool operator<(const SkEdge& a, const SkEdge& b) { 368 int valuea = a.fFirstY; 369 int valueb = b.fFirstY; 370 371 if (valuea == valueb) { 372 valuea = a.fX; 373 valueb = b.fX; 374 } 375 376 return valuea < valueb; 377} 378 379static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) { 380 SkTQSort(list, list + count - 1); 381 382 // now make the edges linked in sorted order 383 for (int i = 1; i < count; i++) { 384 list[i - 1]->fNext = list[i]; 385 list[i]->fPrev = list[i - 1]; 386 } 387 388 *last = list[count - 1]; 389 return list[0]; 390} 391 392// clipRect may be null, even though we always have a clip. This indicates that 393// the path is contained in the clip, and so we can ignore it during the blit 394// 395// clipRect (if no null) has already been shifted up 396// 397void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitter, 398 int start_y, int stop_y, int shiftEdgesUp, const SkRegion& clipRgn) { 399 SkASSERT(blitter); 400 401 SkEdgeBuilder builder; 402 403 // If we're convex, then we need both edges, even the right edge is past the clip 404 const bool canCullToTheRight = !path.isConvex(); 405 406 int count = builder.build(path, clipRect, shiftEdgesUp, canCullToTheRight); 407 SkASSERT(count >= 0); 408 409 SkEdge** list = builder.edgeList(); 410 411 if (0 == count) { 412 if (path.isInverseFillType()) { 413 /* 414 * Since we are in inverse-fill, our caller has already drawn above 415 * our top (start_y) and will draw below our bottom (stop_y). Thus 416 * we need to restrict our drawing to the intersection of the clip 417 * and those two limits. 418 */ 419 SkIRect rect = clipRgn.getBounds(); 420 if (rect.fTop < start_y) { 421 rect.fTop = start_y; 422 } 423 if (rect.fBottom > stop_y) { 424 rect.fBottom = stop_y; 425 } 426 if (!rect.isEmpty()) { 427 blitter->blitRect(rect.fLeft << shiftEdgesUp, 428 rect.fTop << shiftEdgesUp, 429 rect.width() << shiftEdgesUp, 430 rect.height() << shiftEdgesUp); 431 } 432 } 433 return; 434 } 435 436 SkEdge headEdge, tailEdge, *last; 437 // this returns the first and last edge after they're sorted into a dlink list 438 SkEdge* edge = sort_edges(list, count, &last); 439 440 headEdge.fPrev = nullptr; 441 headEdge.fNext = edge; 442 headEdge.fFirstY = kEDGE_HEAD_Y; 443 headEdge.fX = SK_MinS32; 444 edge->fPrev = &headEdge; 445 446 tailEdge.fPrev = last; 447 tailEdge.fNext = nullptr; 448 tailEdge.fFirstY = kEDGE_TAIL_Y; 449 last->fNext = &tailEdge; 450 451 // now edge is the head of the sorted linklist 452 453 start_y <<= shiftEdgesUp; 454 stop_y <<= shiftEdgesUp; 455 if (clipRect && start_y < clipRect->fTop) { 456 start_y = clipRect->fTop; 457 } 458 if (clipRect && stop_y > clipRect->fBottom) { 459 stop_y = clipRect->fBottom; 460 } 461 462 InverseBlitter ib; 463 PrePostProc proc = nullptr; 464 465 if (path.isInverseFillType()) { 466 ib.setBlitter(blitter, clipRgn.getBounds(), shiftEdgesUp); 467 blitter = &ib; 468 proc = PrePostInverseBlitterProc; 469 } 470 471 if (path.isConvex() && (nullptr == proc)) { 472 SkASSERT(count >= 2); // convex walker does not handle missing right edges 473 walk_convex_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, nullptr); 474 } else { 475 int rightEdge; 476 if (clipRect) { 477 rightEdge = clipRect->right(); 478 } else { 479 rightEdge = SkScalarRoundToInt(path.getBounds().right()) << shiftEdgesUp; 480 } 481 482 walk_edges(&headEdge, path.getFillType(), blitter, start_y, stop_y, proc, rightEdge); 483 } 484} 485 486void sk_blit_above(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) { 487 const SkIRect& cr = clip.getBounds(); 488 SkIRect tmp; 489 490 tmp.fLeft = cr.fLeft; 491 tmp.fRight = cr.fRight; 492 tmp.fTop = cr.fTop; 493 tmp.fBottom = ir.fTop; 494 if (!tmp.isEmpty()) { 495 blitter->blitRectRegion(tmp, clip); 496 } 497} 498 499void sk_blit_below(SkBlitter* blitter, const SkIRect& ir, const SkRegion& clip) { 500 const SkIRect& cr = clip.getBounds(); 501 SkIRect tmp; 502 503 tmp.fLeft = cr.fLeft; 504 tmp.fRight = cr.fRight; 505 tmp.fTop = ir.fBottom; 506 tmp.fBottom = cr.fBottom; 507 if (!tmp.isEmpty()) { 508 blitter->blitRectRegion(tmp, clip); 509 } 510} 511 512/////////////////////////////////////////////////////////////////////////////// 513 514/** 515 * If the caller is drawing an inverse-fill path, then it pass true for 516 * skipRejectTest, so we don't abort drawing just because the src bounds (ir) 517 * is outside of the clip. 518 */ 519SkScanClipper::SkScanClipper(SkBlitter* blitter, const SkRegion* clip, 520 const SkIRect& ir, bool skipRejectTest) { 521 fBlitter = nullptr; // null means blit nothing 522 fClipRect = nullptr; 523 524 if (clip) { 525 fClipRect = &clip->getBounds(); 526 if (!skipRejectTest && !SkIRect::Intersects(*fClipRect, ir)) { // completely clipped out 527 return; 528 } 529 530 if (clip->isRect()) { 531 if (fClipRect->contains(ir)) { 532 fClipRect = nullptr; 533 } else { 534 // only need a wrapper blitter if we're horizontally clipped 535 if (fClipRect->fLeft > ir.fLeft || fClipRect->fRight < ir.fRight) { 536 fRectBlitter.init(blitter, *fClipRect); 537 blitter = &fRectBlitter; 538 } 539 } 540 } else { 541 fRgnBlitter.init(blitter, clip); 542 blitter = &fRgnBlitter; 543 } 544 } 545 fBlitter = blitter; 546} 547 548/////////////////////////////////////////////////////////////////////////////// 549 550static bool clip_to_limit(const SkRegion& orig, SkRegion* reduced) { 551 const int32_t limit = 32767; 552 553 SkIRect limitR; 554 limitR.set(-limit, -limit, limit, limit); 555 if (limitR.contains(orig.getBounds())) { 556 return false; 557 } 558 reduced->op(orig, limitR, SkRegion::kIntersect_Op); 559 return true; 560} 561 562void SkScan::FillPath(const SkPath& path, const SkRegion& origClip, 563 SkBlitter* blitter) { 564 if (origClip.isEmpty()) { 565 return; 566 } 567 568 // Our edges are fixed-point, and don't like the bounds of the clip to 569 // exceed that. Here we trim the clip just so we don't overflow later on 570 const SkRegion* clipPtr = &origClip; 571 SkRegion finiteClip; 572 if (clip_to_limit(origClip, &finiteClip)) { 573 if (finiteClip.isEmpty()) { 574 return; 575 } 576 clipPtr = &finiteClip; 577 } 578 // don't reference "origClip" any more, just use clipPtr 579 580 SkIRect ir; 581 // We deliberately call dround() instead of round(), since we can't afford to generate a 582 // bounds that is tighter than the corresponding SkEdges. The edge code basically converts 583 // the floats to fixed, and then "rounds". If we called round() instead of dround() here, 584 // we could generate the wrong ir for values like 0.4999997. 585 path.getBounds().dround(&ir); 586 if (ir.isEmpty()) { 587 if (path.isInverseFillType()) { 588 blitter->blitRegion(*clipPtr); 589 } 590 return; 591 } 592 593 SkScanClipper clipper(blitter, clipPtr, ir, path.isInverseFillType()); 594 595 blitter = clipper.getBlitter(); 596 if (blitter) { 597 // we have to keep our calls to blitter in sorted order, so we 598 // must blit the above section first, then the middle, then the bottom. 599 if (path.isInverseFillType()) { 600 sk_blit_above(blitter, ir, *clipPtr); 601 } 602 sk_fill_path(path, clipper.getClipRect(), blitter, ir.fTop, ir.fBottom, 603 0, *clipPtr); 604 if (path.isInverseFillType()) { 605 sk_blit_below(blitter, ir, *clipPtr); 606 } 607 } else { 608 // what does it mean to not have a blitter if path.isInverseFillType??? 609 } 610} 611 612void SkScan::FillPath(const SkPath& path, const SkIRect& ir, 613 SkBlitter* blitter) { 614 SkRegion rgn(ir); 615 FillPath(path, rgn, blitter); 616} 617 618/////////////////////////////////////////////////////////////////////////////// 619 620static int build_tri_edges(SkEdge edge[], const SkPoint pts[], 621 const SkIRect* clipRect, SkEdge* list[]) { 622 SkEdge** start = list; 623 624 if (edge->setLine(pts[0], pts[1], clipRect, 0)) { 625 *list++ = edge; 626 edge = (SkEdge*)((char*)edge + sizeof(SkEdge)); 627 } 628 if (edge->setLine(pts[1], pts[2], clipRect, 0)) { 629 *list++ = edge; 630 edge = (SkEdge*)((char*)edge + sizeof(SkEdge)); 631 } 632 if (edge->setLine(pts[2], pts[0], clipRect, 0)) { 633 *list++ = edge; 634 } 635 return (int)(list - start); 636} 637 638 639static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect, 640 SkBlitter* blitter, const SkIRect& ir) { 641 SkASSERT(pts && blitter); 642 643 SkEdge edgeStorage[3]; 644 SkEdge* list[3]; 645 646 int count = build_tri_edges(edgeStorage, pts, clipRect, list); 647 if (count < 2) { 648 return; 649 } 650 651 SkEdge headEdge, tailEdge, *last; 652 653 // this returns the first and last edge after they're sorted into a dlink list 654 SkEdge* edge = sort_edges(list, count, &last); 655 656 headEdge.fPrev = nullptr; 657 headEdge.fNext = edge; 658 headEdge.fFirstY = kEDGE_HEAD_Y; 659 headEdge.fX = SK_MinS32; 660 edge->fPrev = &headEdge; 661 662 tailEdge.fPrev = last; 663 tailEdge.fNext = nullptr; 664 tailEdge.fFirstY = kEDGE_TAIL_Y; 665 last->fNext = &tailEdge; 666 667 // now edge is the head of the sorted linklist 668 int stop_y = ir.fBottom; 669 if (clipRect && stop_y > clipRect->fBottom) { 670 stop_y = clipRect->fBottom; 671 } 672 int start_y = ir.fTop; 673 if (clipRect && start_y < clipRect->fTop) { 674 start_y = clipRect->fTop; 675 } 676 walk_convex_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, nullptr); 677// walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, start_y, stop_y, nullptr); 678} 679 680void SkScan::FillTriangle(const SkPoint pts[], const SkRasterClip& clip, 681 SkBlitter* blitter) { 682 if (clip.isEmpty()) { 683 return; 684 } 685 686 SkRect r; 687 SkIRect ir; 688 r.set(pts, 3); 689 r.round(&ir); 690 if (ir.isEmpty() || !SkIRect::Intersects(ir, clip.getBounds())) { 691 return; 692 } 693 694 SkAAClipBlitterWrapper wrap; 695 const SkRegion* clipRgn; 696 if (clip.isBW()) { 697 clipRgn = &clip.bwRgn(); 698 } else { 699 wrap.init(clip, blitter); 700 clipRgn = &wrap.getRgn(); 701 blitter = wrap.getBlitter(); 702 } 703 704 SkScanClipper clipper(blitter, clipRgn, ir); 705 blitter = clipper.getBlitter(); 706 if (blitter) { 707 sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir); 708 } 709} 710