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