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