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