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