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