SkScan_Path.cpp revision 5ebbe14f76da3028e5d4523c093a0f4a2cf8e982
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 387 // this overflows if valuea >>> valueb or vice-versa 388 // return valuea - valueb; 389 // do perform the slower but safe compares 390 return (valuea < valueb) ? -1 : (valuea > valueb); 391 } 392} 393 394static SkEdge* sort_edges(SkEdge* list[], int count, SkEdge** last) 395{ 396 qsort(list, count, sizeof(SkEdge*), edge_compare); 397 398 // now make the edges linked in sorted order 399 for (int i = 1; i < count; i++) 400 { 401 list[i - 1]->fNext = list[i]; 402 list[i]->fPrev = list[i - 1]; 403 } 404 405 *last = list[count - 1]; 406 return list[0]; 407} 408 409#ifdef SK_DEBUG 410/* 'quick' computation of the max sized needed to allocated for 411 our edgelist. 412*/ 413static int worst_case_edge_count(const SkPath& path, size_t* storage) 414{ 415 size_t size = 0; 416 int edgeCount = 0; 417 418 SkPath::Iter iter(path, true); 419 SkPath::Verb verb; 420 421 while ((verb = iter.next(NULL)) != SkPath::kDone_Verb) 422 { 423 switch (verb) { 424 case SkPath::kLine_Verb: 425 edgeCount += 1; 426 size += sizeof(SkQuadraticEdge); // treat line like Quad (in case its > 512) 427 break; 428 case SkPath::kQuad_Verb: 429 edgeCount += 2; // might need 2 edges when we chop on Y extrema 430 size += 2 * sizeof(SkQuadraticEdge); 431 break; 432 case SkPath::kCubic_Verb: 433 edgeCount += 3; // might need 3 edges when we chop on Y extrema 434 size += 3 * sizeof(SkCubicEdge); 435 break; 436 default: 437 break; 438 } 439 } 440 441 SkASSERT(storage); 442 *storage = size; 443 return edgeCount; 444} 445#endif 446 447/* Much faster than worst_case_edge_count, but over estimates even more 448*/ 449static int cheap_worst_case_edge_count(const SkPath& path, size_t* storage) { 450 int ptCount = path.getPoints(NULL, 0); 451 // worst case is curve, close, curve, close, as that is 452 // 2 lines per pt, or : pts * 2 453 // 2 quads + 1 line per 2 pts, or : pts * 3 / 2 454 // 3 cubics + 1 line per 3 pts : pts * 4 / 3 455 int edgeCount = ptCount << 1; 456 // worst storage, due to relative size of different edge types, is 457 // quads * 3 / 2 458 size_t quadSize = (ptCount * 3 >> 1) * sizeof(SkQuadraticEdge); 459#if 0 460 size_t lineSize = (ptCount << 1) * sizeof(SkEdge); 461 size_t cubicSize = (ptCount * 3 / 4) * sizeof(SkCubicEdge); 462 SkASSERT(lineSize <= quadSize); 463 SkASSERT(cubicSize <= quadSize); 464#endif 465 *storage = quadSize; 466 return edgeCount; 467} 468 469// clipRect may be null, even though we always have a clip. This indicates that 470// the path is contained in the clip, and so we can ignore it during the blit 471// 472// clipRect (if no null) has already been shifted up 473// 474void sk_fill_path(const SkPath& path, const SkIRect* clipRect, SkBlitter* blitter, 475 int stop_y, int shiftEdgesUp, const SkRegion& clipRgn) 476{ 477 SkASSERT(&path && blitter); 478 479 size_t size; 480 int maxCount = cheap_worst_case_edge_count(path, &size); 481 482#ifdef SK_DEBUG 483 { 484 size_t size2; 485 int maxCount2 = worst_case_edge_count(path, &size2); 486 487 SkASSERT(maxCount >= maxCount2 && size >= size2); 488 } 489#endif 490 491 SkAutoMalloc memory(maxCount * sizeof(SkEdge*) + size); 492 SkEdge** list = (SkEdge**)memory.get(); 493 SkEdge* edge = (SkEdge*)(list + maxCount); 494 int count = build_edges(edge, path, clipRect, list, shiftEdgesUp); 495 SkEdge headEdge, tailEdge, *last; 496 497 SkASSERT(count <= maxCount); 498 if (count < 2) { 499 return; 500 } 501 502 // this returns the first and last edge after they're sorted into a dlink list 503 edge = sort_edges(list, count, &last); 504 505 headEdge.fPrev = NULL; 506 headEdge.fNext = edge; 507 headEdge.fFirstY = kEDGE_HEAD_Y; 508 headEdge.fX = SK_MinS32; 509 edge->fPrev = &headEdge; 510 511 tailEdge.fPrev = last; 512 tailEdge.fNext = NULL; 513 tailEdge.fFirstY = kEDGE_TAIL_Y; 514 last->fNext = &tailEdge; 515 516 // now edge is the head of the sorted linklist 517 518 stop_y <<= shiftEdgesUp; 519 if (clipRect && stop_y > clipRect->fBottom) { 520 stop_y = clipRect->fBottom; 521 } 522 523 InverseBlitter ib; 524 PrePostProc proc = NULL; 525 526 if (path.isInverseFillType()) { 527 ib.setBlitter(blitter, clipRgn.getBounds(), shiftEdgesUp); 528 blitter = &ib; 529 proc = PrePostInverseBlitterProc; 530 } 531 532 walk_edges(&headEdge, path.getFillType(), blitter, stop_y, proc); 533} 534 535void sk_blit_above_and_below(SkBlitter* blitter, const SkIRect& ir, 536 const SkRegion& clip) { 537 const SkIRect& cr = clip.getBounds(); 538 SkIRect tmp; 539 540 tmp.fLeft = cr.fLeft; 541 tmp.fRight = cr.fRight; 542 543 tmp.fTop = cr.fTop; 544 tmp.fBottom = ir.fTop; 545 if (!tmp.isEmpty()) { 546 blitter->blitRectRegion(tmp, clip); 547 } 548 549 tmp.fTop = ir.fBottom; 550 tmp.fBottom = cr.fBottom; 551 if (!tmp.isEmpty()) { 552 blitter->blitRectRegion(tmp, clip); 553 } 554} 555 556///////////////////////////////////////////////////////////////////////////////////// 557 558SkScanClipper::SkScanClipper(SkBlitter* blitter, const SkRegion* clip, const SkIRect& ir) 559{ 560 fBlitter = NULL; // null means blit nothing 561 fClipRect = NULL; 562 563 if (clip) 564 { 565 fClipRect = &clip->getBounds(); 566 if (!SkIRect::Intersects(*fClipRect, ir)) // completely clipped out 567 return; 568 569 if (clip->isRect()) 570 { 571 if (fClipRect->contains(ir)) 572 fClipRect = NULL; 573 else 574 { 575 // only need a wrapper blitter if we're horizontally clipped 576 if (fClipRect->fLeft > ir.fLeft || fClipRect->fRight < ir.fRight) 577 { 578 fRectBlitter.init(blitter, *fClipRect); 579 blitter = &fRectBlitter; 580 } 581 } 582 } 583 else 584 { 585 fRgnBlitter.init(blitter, clip); 586 blitter = &fRgnBlitter; 587 } 588 } 589 fBlitter = blitter; 590} 591 592/////////////////////////////////////////////////////////////////////////////// 593 594void SkScan::FillPath(const SkPath& path, const SkRegion& clip, 595 SkBlitter* blitter) { 596 if (clip.isEmpty()) { 597 return; 598 } 599 600 SkIRect ir; 601 path.getBounds().round(&ir); 602 if (ir.isEmpty()) { 603 if (path.isInverseFillType()) { 604 blitter->blitRegion(clip); 605 } 606 return; 607 } 608 609 SkScanClipper clipper(blitter, &clip, ir); 610 611 blitter = clipper.getBlitter(); 612 if (blitter) { 613 if (path.isInverseFillType()) { 614 sk_blit_above_and_below(blitter, ir, clip); 615 } 616 sk_fill_path(path, clipper.getClipRect(), blitter, ir.fBottom, 0, clip); 617 } else { 618 // what does it mean to not have a blitter if path.isInverseFillType??? 619 } 620} 621 622/////////////////////////////////////////////////////////////////////////////// 623 624static int build_tri_edges(SkEdge edge[], const SkPoint pts[], 625 const SkIRect* clipRect, SkEdge* list[]) { 626 SkEdge** start = list; 627 628 if (edge->setLine(pts[0], pts[1], clipRect, 0)) { 629 *list++ = edge; 630 edge = (SkEdge*)((char*)edge + sizeof(SkEdge)); 631 } 632 if (edge->setLine(pts[1], pts[2], clipRect, 0)) { 633 *list++ = edge; 634 edge = (SkEdge*)((char*)edge + sizeof(SkEdge)); 635 } 636 if (edge->setLine(pts[2], pts[0], clipRect, 0)) { 637 *list++ = edge; 638 } 639 return (int)(list - start); 640} 641 642 643static void sk_fill_triangle(const SkPoint pts[], const SkIRect* clipRect, 644 SkBlitter* blitter, const SkIRect& ir) { 645 SkASSERT(pts && blitter); 646 647 SkEdge edgeStorage[3]; 648 SkEdge* list[3]; 649 650 int count = build_tri_edges(edgeStorage, pts, clipRect, list); 651 if (count < 2) { 652 return; 653 } 654 655 SkEdge headEdge, tailEdge, *last; 656 657 // this returns the first and last edge after they're sorted into a dlink list 658 SkEdge* edge = sort_edges(list, count, &last); 659 660 headEdge.fPrev = NULL; 661 headEdge.fNext = edge; 662 headEdge.fFirstY = kEDGE_HEAD_Y; 663 headEdge.fX = SK_MinS32; 664 edge->fPrev = &headEdge; 665 666 tailEdge.fPrev = last; 667 tailEdge.fNext = NULL; 668 tailEdge.fFirstY = kEDGE_TAIL_Y; 669 last->fNext = &tailEdge; 670 671 // now edge is the head of the sorted linklist 672 int stop_y = ir.fBottom; 673 if (clipRect && stop_y > clipRect->fBottom) { 674 stop_y = clipRect->fBottom; 675 } 676 walk_edges(&headEdge, SkPath::kEvenOdd_FillType, blitter, stop_y, NULL); 677} 678 679void SkScan::FillTriangle(const SkPoint pts[], const SkRegion* clip, 680 SkBlitter* blitter) { 681 if (clip && clip->isEmpty()) { 682 return; 683 } 684 685 SkRect r; 686 SkIRect ir; 687 r.set(pts, 3); 688 r.round(&ir); 689 if (ir.isEmpty()) { 690 return; 691 } 692 693 SkScanClipper clipper(blitter, clip, ir); 694 695 blitter = clipper.getBlitter(); 696 if (NULL != blitter) { 697 sk_fill_triangle(pts, clipper.getClipRect(), blitter, ir); 698 } 699} 700 701