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