SkAAClip.cpp revision 493c65f1aa0864857c21b2be096740a17ef1430a
1 2/* 3 * Copyright 2011 Google Inc. 4 * 5 * Use of this source code is governed by a BSD-style license that can be 6 * found in the LICENSE file. 7 */ 8 9#include "SkAAClip.h" 10#include "SkBlitter.h" 11#include "SkColorPriv.h" 12#include "SkPath.h" 13#include "SkScan.h" 14#include "SkThread.h" 15#include "SkUtils.h" 16 17class AutoAAClipValidate { 18public: 19 AutoAAClipValidate(const SkAAClip& clip) : fClip(clip) { 20 fClip.validate(); 21 } 22 ~AutoAAClipValidate() { 23 fClip.validate(); 24 } 25private: 26 const SkAAClip& fClip; 27}; 28 29#ifdef SK_DEBUG 30 #define AUTO_AACLIP_VALIDATE(clip) AutoAAClipValidate acv(clip) 31#else 32 #define AUTO_AACLIP_VALIDATE(clip) 33#endif 34 35/////////////////////////////////////////////////////////////////////////////// 36 37#define kMaxInt32 0x7FFFFFFF 38 39static inline bool x_in_rect(int x, const SkIRect& rect) { 40 return (unsigned)(x - rect.fLeft) < (unsigned)rect.width(); 41} 42 43static inline bool y_in_rect(int y, const SkIRect& rect) { 44 return (unsigned)(y - rect.fTop) < (unsigned)rect.height(); 45} 46 47/* 48 * Data runs are packed [count, alpha] 49 */ 50 51struct SkAAClip::YOffset { 52 int32_t fY; 53 uint32_t fOffset; 54}; 55 56struct SkAAClip::RunHead { 57 int32_t fRefCnt; 58 int32_t fRowCount; 59 size_t fDataSize; 60 61 YOffset* yoffsets() { 62 return (YOffset*)((char*)this + sizeof(RunHead)); 63 } 64 const YOffset* yoffsets() const { 65 return (const YOffset*)((const char*)this + sizeof(RunHead)); 66 } 67 uint8_t* data() { 68 return (uint8_t*)(this->yoffsets() + fRowCount); 69 } 70 const uint8_t* data() const { 71 return (const uint8_t*)(this->yoffsets() + fRowCount); 72 } 73 74 static RunHead* Alloc(int rowCount, size_t dataSize) { 75 size_t size = sizeof(RunHead) + rowCount * sizeof(YOffset) + dataSize; 76 RunHead* head = (RunHead*)sk_malloc_throw(size); 77 head->fRefCnt = 1; 78 head->fRowCount = rowCount; 79 head->fDataSize = dataSize; 80 return head; 81 } 82 83 static int ComputeRowSizeForWidth(int width) { 84 // 2 bytes per segment, where each segment can store up to 255 for count 85 int segments = 0; 86 while (width > 0) { 87 segments += 1; 88 int n = SkMin32(width, 255); 89 width -= n; 90 } 91 return segments * 2; // each segment is row[0] + row[1] (n + alpha) 92 } 93 94 static RunHead* AllocRect(const SkIRect& bounds) { 95 SkASSERT(!bounds.isEmpty()); 96 int width = bounds.width(); 97 size_t rowSize = ComputeRowSizeForWidth(width); 98 RunHead* head = RunHead::Alloc(1, rowSize); 99 YOffset* yoff = head->yoffsets(); 100 yoff->fY = bounds.height() - 1; 101 yoff->fOffset = 0; 102 uint8_t* row = head->data(); 103 while (width > 0) { 104 int n = SkMin32(width, 255); 105 row[0] = n; 106 row[1] = 0xFF; 107 width -= n; 108 row += 2; 109 } 110 return head; 111 } 112}; 113 114class SkAAClip::Iter { 115public: 116 Iter(const SkAAClip&); 117 118 bool done() const { return fDone; } 119 int top() const { return fTop; } 120 int bottom() const { return fBottom; } 121 const uint8_t* data() const { return fData; } 122 void next(); 123 124private: 125 const YOffset* fCurrYOff; 126 const YOffset* fStopYOff; 127 const uint8_t* fData; 128 129 int fTop, fBottom; 130 bool fDone; 131}; 132 133SkAAClip::Iter::Iter(const SkAAClip& clip) { 134 if (clip.isEmpty()) { 135 fDone = true; 136 fTop = fBottom = clip.fBounds.fBottom; 137 fData = NULL; 138 fStopYOff = NULL; 139 return; 140 } 141 142 const RunHead* head = clip.fRunHead; 143 fCurrYOff = head->yoffsets(); 144 fStopYOff = fCurrYOff + head->fRowCount; 145 fData = head->data() + fCurrYOff->fOffset; 146 147 // setup first value 148 fTop = clip.fBounds.fTop; 149 fBottom = clip.fBounds.fTop + fCurrYOff->fY + 1; 150 fDone = false; 151} 152 153void SkAAClip::Iter::next() { 154 if (!fDone) { 155 const YOffset* prev = fCurrYOff; 156 const YOffset* curr = prev + 1; 157 SkASSERT(curr <= fStopYOff); 158 159 fTop = fBottom; 160 if (curr >= fStopYOff) { 161 fDone = true; 162 fBottom = kMaxInt32; 163 fData = NULL; 164 } else { 165 fBottom += curr->fY - prev->fY; 166 fData += curr->fOffset - prev->fOffset; 167 fCurrYOff = curr; 168 } 169 } 170} 171 172#ifdef SK_DEBUG 173// assert we're exactly width-wide, and then return the number of bytes used 174static size_t compute_row_length(const uint8_t row[], int width) { 175 const uint8_t* origRow = row; 176 while (width > 0) { 177 int n = row[0]; 178 SkASSERT(n > 0); 179 SkASSERT(n <= width); 180 row += 2; 181 width -= n; 182 } 183 SkASSERT(0 == width); 184 return row - origRow; 185} 186 187void SkAAClip::validate() const { 188 if (NULL == fRunHead) { 189 SkASSERT(fBounds.isEmpty()); 190 return; 191 } 192 193 const RunHead* head = fRunHead; 194 SkASSERT(head->fRefCnt > 0); 195 SkASSERT(head->fRowCount > 0); 196 197 const YOffset* yoff = head->yoffsets(); 198 const YOffset* ystop = yoff + head->fRowCount; 199 const int lastY = fBounds.height() - 1; 200 201 // Y and offset must be monotonic 202 int prevY = -1; 203 int32_t prevOffset = -1; 204 while (yoff < ystop) { 205 SkASSERT(prevY < yoff->fY); 206 SkASSERT(yoff->fY <= lastY); 207 prevY = yoff->fY; 208 SkASSERT(prevOffset < (int32_t)yoff->fOffset); 209 prevOffset = yoff->fOffset; 210 const uint8_t* row = head->data() + yoff->fOffset; 211 size_t rowLength = compute_row_length(row, fBounds.width()); 212 SkASSERT(yoff->fOffset + rowLength <= head->fDataSize); 213 yoff += 1; 214 } 215 // check the last entry; 216 --yoff; 217 SkASSERT(yoff->fY == lastY); 218} 219#endif 220 221/////////////////////////////////////////////////////////////////////////////// 222 223// Count the number of zeros on the left and right edges of the passed in 224// RLE row. If 'row' is all zeros return 'width' in both variables. 225static void count_left_right_zeros(const uint8_t* row, int width, 226 int* leftZ, int* riteZ) { 227 int zeros = 0; 228 do { 229 if (row[1]) { 230 break; 231 } 232 int n = row[0]; 233 SkASSERT(n > 0); 234 SkASSERT(n <= width); 235 zeros += n; 236 row += 2; 237 width -= n; 238 } while (width > 0); 239 *leftZ = zeros; 240 241 if (0 == width) { 242 // this line is completely empty return 'width' in both variables 243 *riteZ = *leftZ; 244 return; 245 } 246 247 zeros = 0; 248 while (width > 0) { 249 int n = row[0]; 250 SkASSERT(n > 0); 251 if (0 == row[1]) { 252 zeros += n; 253 } else { 254 zeros = 0; 255 } 256 row += 2; 257 width -= n; 258 } 259 *riteZ = zeros; 260} 261 262#ifdef SK_DEBUG 263static void test_count_left_right_zeros() { 264 static bool gOnce; 265 if (gOnce) { 266 return; 267 } 268 gOnce = true; 269 270 const uint8_t data0[] = { 0, 0, 10, 0xFF }; 271 const uint8_t data1[] = { 0, 0, 5, 0xFF, 2, 0, 3, 0xFF }; 272 const uint8_t data2[] = { 7, 0, 5, 0, 2, 0, 3, 0xFF }; 273 const uint8_t data3[] = { 0, 5, 5, 0xFF, 2, 0, 3, 0 }; 274 const uint8_t data4[] = { 2, 3, 2, 0, 5, 0xFF, 3, 0 }; 275 const uint8_t data5[] = { 10, 10, 10, 0 }; 276 const uint8_t data6[] = { 2, 2, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 }; 277 278 const uint8_t* array[] = { 279 data0, data1, data2, data3, data4, data5, data6 280 }; 281 282 for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) { 283 const uint8_t* data = array[i]; 284 const int expectedL = *data++; 285 const int expectedR = *data++; 286 int L = 12345, R = 12345; 287 count_left_right_zeros(data, 10, &L, &R); 288 SkASSERT(expectedL == L); 289 SkASSERT(expectedR == R); 290 } 291} 292#endif 293 294// modify row in place, trimming off (zeros) from the left and right sides. 295// return the number of bytes that were completely eliminated from the left 296static int trim_row_left_right(uint8_t* row, int width, int leftZ, int riteZ) { 297 int trim = 0; 298 while (leftZ > 0) { 299 SkASSERT(0 == row[1]); 300 int n = row[0]; 301 SkASSERT(n > 0); 302 SkASSERT(n <= width); 303 width -= n; 304 row += 2; 305 if (n > leftZ) { 306 row[-2] = n - leftZ; 307 break; 308 } 309 trim += 2; 310 leftZ -= n; 311 SkASSERT(leftZ >= 0); 312 } 313 314 if (riteZ) { 315 // walk row to the end, and then we'll back up to trim riteZ 316 while (width > 0) { 317 int n = row[0]; 318 SkASSERT(n <= width); 319 width -= n; 320 row += 2; 321 } 322 // now skip whole runs of zeros 323 do { 324 row -= 2; 325 SkASSERT(0 == row[1]); 326 int n = row[0]; 327 SkASSERT(n > 0); 328 if (n > riteZ) { 329 row[0] = n - riteZ; 330 break; 331 } 332 riteZ -= n; 333 SkASSERT(riteZ >= 0); 334 } while (riteZ > 0); 335 } 336 337 return trim; 338} 339 340#ifdef SK_DEBUG 341// assert that this row is exactly this width 342static void assert_row_width(const uint8_t* row, int width) { 343 while (width > 0) { 344 int n = row[0]; 345 SkASSERT(n > 0); 346 SkASSERT(n <= width); 347 width -= n; 348 row += 2; 349 } 350 SkASSERT(0 == width); 351} 352 353static void test_trim_row_left_right() { 354 static bool gOnce; 355 if (gOnce) { 356 return; 357 } 358 gOnce = true; 359 360 uint8_t data0[] = { 0, 0, 0, 10, 10, 0xFF }; 361 uint8_t data1[] = { 2, 0, 0, 10, 5, 0, 2, 0, 3, 0xFF }; 362 uint8_t data2[] = { 5, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF }; 363 uint8_t data3[] = { 6, 0, 2, 10, 5, 0, 2, 0, 3, 0xFF }; 364 uint8_t data4[] = { 0, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 }; 365 uint8_t data5[] = { 1, 0, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 }; 366 uint8_t data6[] = { 0, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 }; 367 uint8_t data7[] = { 1, 1, 0, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 }; 368 uint8_t data8[] = { 2, 2, 2, 10, 2, 0, 2, 0xFF, 2, 0, 2, 0xFF, 2, 0 }; 369 uint8_t data9[] = { 5, 2, 4, 10, 2, 0, 2, 0, 2, 0, 2, 0xFF, 2, 0 }; 370 uint8_t data10[] ={ 74, 0, 4, 150, 9, 0, 65, 0, 76, 0xFF }; 371 372 uint8_t* array[] = { 373 data0, data1, data2, data3, data4, 374 data5, data6, data7, data8, data9, 375 data10 376 }; 377 378 for (size_t i = 0; i < SK_ARRAY_COUNT(array); ++i) { 379 uint8_t* data = array[i]; 380 const int trimL = *data++; 381 const int trimR = *data++; 382 const int expectedSkip = *data++; 383 const int origWidth = *data++; 384 assert_row_width(data, origWidth); 385 int skip = trim_row_left_right(data, origWidth, trimL, trimR); 386 SkASSERT(expectedSkip == skip); 387 int expectedWidth = origWidth - trimL - trimR; 388 assert_row_width(data + skip, expectedWidth); 389 } 390} 391#endif 392 393bool SkAAClip::trimLeftRight() { 394 SkDEBUGCODE(test_trim_row_left_right();) 395 396 if (this->isEmpty()) { 397 return false; 398 } 399 400 AUTO_AACLIP_VALIDATE(*this); 401 402 const int width = fBounds.width(); 403 RunHead* head = fRunHead; 404 YOffset* yoff = head->yoffsets(); 405 YOffset* stop = yoff + head->fRowCount; 406 uint8_t* base = head->data(); 407 408 // After this loop, 'leftZeros' & 'rightZeros' will contain the minimum 409 // number of zeros on the left and right of the clip. This information 410 // can be used to shrink the bounding box. 411 int leftZeros = width; 412 int riteZeros = width; 413 while (yoff < stop) { 414 int L, R; 415 count_left_right_zeros(base + yoff->fOffset, width, &L, &R); 416 SkASSERT(L + R < width || (L == width && R == width)); 417 if (L < leftZeros) { 418 leftZeros = L; 419 } 420 if (R < riteZeros) { 421 riteZeros = R; 422 } 423 if (0 == (leftZeros | riteZeros)) { 424 // no trimming to do 425 return true; 426 } 427 yoff += 1; 428 } 429 430 SkASSERT(leftZeros || riteZeros); 431 if (width == leftZeros) { 432 SkASSERT(width == riteZeros); 433 return this->setEmpty(); 434 } 435 436 this->validate(); 437 438 fBounds.fLeft += leftZeros; 439 fBounds.fRight -= riteZeros; 440 SkASSERT(!fBounds.isEmpty()); 441 442 // For now we don't realloc the storage (for time), we just shrink in place 443 // This means we don't have to do any memmoves either, since we can just 444 // play tricks with the yoff->fOffset for each row 445 yoff = head->yoffsets(); 446 while (yoff < stop) { 447 uint8_t* row = base + yoff->fOffset; 448 SkDEBUGCODE((void)compute_row_length(row, width);) 449 yoff->fOffset += trim_row_left_right(row, width, leftZeros, riteZeros); 450 SkDEBUGCODE((void)compute_row_length(base + yoff->fOffset, width - leftZeros - riteZeros);) 451 yoff += 1; 452 } 453 return true; 454} 455 456static bool row_is_all_zeros(const uint8_t* row, int width) { 457 SkASSERT(width > 0); 458 do { 459 if (row[1]) { 460 return false; 461 } 462 int n = row[0]; 463 SkASSERT(n <= width); 464 width -= n; 465 row += 2; 466 } while (width > 0); 467 SkASSERT(0 == width); 468 return true; 469} 470 471bool SkAAClip::trimTopBottom() { 472 if (this->isEmpty()) { 473 return false; 474 } 475 476 this->validate(); 477 478 const int width = fBounds.width(); 479 RunHead* head = fRunHead; 480 YOffset* yoff = head->yoffsets(); 481 YOffset* stop = yoff + head->fRowCount; 482 const uint8_t* base = head->data(); 483 484 // Look to trim away empty rows from the top. 485 // 486 int skip = 0; 487 while (yoff < stop) { 488 const uint8_t* data = base + yoff->fOffset; 489 if (!row_is_all_zeros(data, width)) { 490 break; 491 } 492 skip += 1; 493 yoff += 1; 494 } 495 SkASSERT(skip <= head->fRowCount); 496 if (skip == head->fRowCount) { 497 return this->setEmpty(); 498 } 499 if (skip > 0) { 500 // adjust fRowCount and fBounds.fTop, and slide all the data up 501 // as we remove [skip] number of YOffset entries 502 yoff = head->yoffsets(); 503 int dy = yoff[skip - 1].fY + 1; 504 for (int i = skip; i < head->fRowCount; ++i) { 505 SkASSERT(yoff[i].fY >= dy); 506 yoff[i].fY -= dy; 507 } 508 YOffset* dst = head->yoffsets(); 509 size_t size = head->fRowCount * sizeof(YOffset) + head->fDataSize; 510 memmove(dst, dst + skip, size - skip * sizeof(YOffset)); 511 512 fBounds.fTop += dy; 513 SkASSERT(!fBounds.isEmpty()); 514 head->fRowCount -= skip; 515 SkASSERT(head->fRowCount > 0); 516 517 this->validate(); 518 // need to reset this after the memmove 519 base = head->data(); 520 } 521 522 // Look to trim away empty rows from the bottom. 523 // We know that we have at least one non-zero row, so we can just walk 524 // backwards without checking for running past the start. 525 // 526 stop = yoff = head->yoffsets() + head->fRowCount; 527 do { 528 yoff -= 1; 529 } while (row_is_all_zeros(base + yoff->fOffset, width)); 530 skip = stop - yoff - 1; 531 SkASSERT(skip >= 0 && skip < head->fRowCount); 532 if (skip > 0) { 533 // removing from the bottom is easier than from the top, as we don't 534 // have to adjust any of the Y values, we just have to trim the array 535 memmove(stop - skip, stop, head->fDataSize); 536 537 fBounds.fBottom = fBounds.fTop + yoff->fY + 1; 538 SkASSERT(!fBounds.isEmpty()); 539 head->fRowCount -= skip; 540 SkASSERT(head->fRowCount > 0); 541 } 542 this->validate(); 543 544 return true; 545} 546 547// can't validate before we're done, since trimming is part of the process of 548// making us valid after the Builder. Since we build from top to bottom, its 549// possible our fBounds.fBottom is bigger than our last scanline of data, so 550// we trim fBounds.fBottom back up. 551// 552// TODO: check for duplicates in X and Y to further compress our data 553// 554bool SkAAClip::trimBounds() { 555 if (this->isEmpty()) { 556 return false; 557 } 558 559 const RunHead* head = fRunHead; 560 const YOffset* yoff = head->yoffsets(); 561 562 SkASSERT(head->fRowCount > 0); 563 const YOffset& lastY = yoff[head->fRowCount - 1]; 564 SkASSERT(lastY.fY + 1 <= fBounds.height()); 565 fBounds.fBottom = fBounds.fTop + lastY.fY + 1; 566 SkASSERT(lastY.fY + 1 == fBounds.height()); 567 SkASSERT(!fBounds.isEmpty()); 568 569 return this->trimTopBottom() && this->trimLeftRight(); 570} 571 572/////////////////////////////////////////////////////////////////////////////// 573 574void SkAAClip::freeRuns() { 575 if (fRunHead) { 576 SkASSERT(fRunHead->fRefCnt >= 1); 577 if (1 == sk_atomic_dec(&fRunHead->fRefCnt)) { 578 sk_free(fRunHead); 579 } 580 } 581} 582 583SkAAClip::SkAAClip() { 584 fBounds.setEmpty(); 585 fRunHead = NULL; 586} 587 588SkAAClip::SkAAClip(const SkAAClip& src) { 589 SkDEBUGCODE(fBounds.setEmpty();) // need this for validate 590 fRunHead = NULL; 591 *this = src; 592} 593 594SkAAClip::~SkAAClip() { 595 this->freeRuns(); 596} 597 598SkAAClip& SkAAClip::operator=(const SkAAClip& src) { 599 AUTO_AACLIP_VALIDATE(*this); 600 src.validate(); 601 602 if (this != &src) { 603 this->freeRuns(); 604 fBounds = src.fBounds; 605 fRunHead = src.fRunHead; 606 if (fRunHead) { 607 sk_atomic_inc(&fRunHead->fRefCnt); 608 } 609 } 610 return *this; 611} 612 613bool operator==(const SkAAClip& a, const SkAAClip& b) { 614 a.validate(); 615 b.validate(); 616 617 if (&a == &b) { 618 return true; 619 } 620 if (a.fBounds != b.fBounds) { 621 return false; 622 } 623 624 const SkAAClip::RunHead* ah = a.fRunHead; 625 const SkAAClip::RunHead* bh = b.fRunHead; 626 627 // this catches empties and rects being equal 628 if (ah == bh) { 629 return true; 630 } 631 632 // now we insist that both are complex (but different ptrs) 633 if (!a.fRunHead || !b.fRunHead) { 634 return false; 635 } 636 637 return ah->fRowCount == bh->fRowCount && 638 ah->fDataSize == bh->fDataSize && 639 !memcmp(ah->data(), bh->data(), ah->fDataSize); 640} 641 642void SkAAClip::swap(SkAAClip& other) { 643 AUTO_AACLIP_VALIDATE(*this); 644 other.validate(); 645 646 SkTSwap(fBounds, other.fBounds); 647 SkTSwap(fRunHead, other.fRunHead); 648} 649 650bool SkAAClip::set(const SkAAClip& src) { 651 *this = src; 652 return !this->isEmpty(); 653} 654 655bool SkAAClip::setEmpty() { 656 this->freeRuns(); 657 fBounds.setEmpty(); 658 fRunHead = NULL; 659 return false; 660} 661 662bool SkAAClip::setRect(const SkIRect& bounds) { 663 if (bounds.isEmpty()) { 664 return this->setEmpty(); 665 } 666 667 AUTO_AACLIP_VALIDATE(*this); 668 669#if 0 670 SkRect r; 671 r.set(bounds); 672 SkPath path; 673 path.addRect(r); 674 return this->setPath(path); 675#else 676 this->freeRuns(); 677 fBounds = bounds; 678 fRunHead = RunHead::AllocRect(bounds); 679 SkASSERT(!this->isEmpty()); 680 return true; 681#endif 682} 683 684bool SkAAClip::setRect(const SkRect& r, bool doAA) { 685 if (r.isEmpty()) { 686 return this->setEmpty(); 687 } 688 689 AUTO_AACLIP_VALIDATE(*this); 690 691 // TODO: special case this 692 693 SkPath path; 694 path.addRect(r); 695 return this->setPath(path, NULL, doAA); 696} 697 698static void append_run(SkTDArray<uint8_t>& array, uint8_t value, int count) { 699 SkASSERT(count >= 0); 700 while (count > 0) { 701 int n = count; 702 if (n > 255) { 703 n = 255; 704 } 705 uint8_t* data = array.append(2); 706 data[0] = n; 707 data[1] = value; 708 count -= n; 709 } 710} 711 712bool SkAAClip::setRegion(const SkRegion& rgn) { 713 if (rgn.isEmpty()) { 714 return this->setEmpty(); 715 } 716 if (rgn.isRect()) { 717 return this->setRect(rgn.getBounds()); 718 } 719 720#if 0 721 SkAAClip clip; 722 SkRegion::Iterator iter(rgn); 723 for (; !iter.done(); iter.next()) { 724 clip.op(iter.rect(), SkRegion::kUnion_Op); 725 } 726 this->swap(clip); 727 return !this->isEmpty(); 728#else 729 const SkIRect& bounds = rgn.getBounds(); 730 const int offsetX = bounds.fLeft; 731 const int offsetY = bounds.fTop; 732 733 SkTDArray<YOffset> yArray; 734 SkTDArray<uint8_t> xArray; 735 736 yArray.setReserve(SkMin32(bounds.height(), 1024)); 737 xArray.setReserve(SkMin32(bounds.width() * 128, 64 * 1024)); 738 739 SkRegion::Iterator iter(rgn); 740 int prevRight = 0; 741 int prevBot = 0; 742 YOffset* currY = NULL; 743 744 for (; !iter.done(); iter.next()) { 745 const SkIRect& r = iter.rect(); 746 SkASSERT(bounds.contains(r)); 747 748 int bot = r.fBottom - offsetY; 749 SkASSERT(bot >= prevBot); 750 if (bot > prevBot) { 751 if (currY) { 752 // flush current row 753 append_run(xArray, 0, bounds.width() - prevRight); 754 } 755 // did we introduce an empty-gap from the prev row? 756 int top = r.fTop - offsetY; 757 if (top > prevBot) { 758 currY = yArray.append(); 759 currY->fY = top - 1; 760 currY->fOffset = xArray.count(); 761 append_run(xArray, 0, bounds.width()); 762 } 763 // create a new record for this Y value 764 currY = yArray.append(); 765 currY->fY = bot - 1; 766 currY->fOffset = xArray.count(); 767 prevRight = 0; 768 prevBot = bot; 769 } 770 771 int x = r.fLeft - offsetX; 772 append_run(xArray, 0, x - prevRight); 773 774 int w = r.fRight - r.fLeft; 775 append_run(xArray, 0xFF, w); 776 prevRight = x + w; 777 SkASSERT(prevRight <= bounds.width()); 778 } 779 // flush last row 780 append_run(xArray, 0, bounds.width() - prevRight); 781 782 // now pack everything into a RunHead 783 RunHead* head = RunHead::Alloc(yArray.count(), xArray.bytes()); 784 memcpy(head->yoffsets(), yArray.begin(), yArray.bytes()); 785 memcpy(head->data(), xArray.begin(), xArray.bytes()); 786 787 this->setEmpty(); 788 fBounds = bounds; 789 fRunHead = head; 790 this->validate(); 791 return true; 792#endif 793} 794 795/////////////////////////////////////////////////////////////////////////////// 796 797const uint8_t* SkAAClip::findRow(int y, int* lastYForRow) const { 798 SkASSERT(fRunHead); 799 800 if (!y_in_rect(y, fBounds)) { 801 return NULL; 802 } 803 y -= fBounds.y(); // our yoffs values are relative to the top 804 805 const YOffset* yoff = fRunHead->yoffsets(); 806 while (yoff->fY < y) { 807 yoff += 1; 808 SkASSERT(yoff - fRunHead->yoffsets() < fRunHead->fRowCount); 809 } 810 811 if (lastYForRow) { 812 *lastYForRow = fBounds.y() + yoff->fY; 813 } 814 return fRunHead->data() + yoff->fOffset; 815} 816 817const uint8_t* SkAAClip::findX(const uint8_t data[], int x, int* initialCount) const { 818 SkASSERT(x_in_rect(x, fBounds)); 819 x -= fBounds.x(); 820 821 // first skip up to X 822 for (;;) { 823 int n = data[0]; 824 if (x < n) { 825 if (initialCount) { 826 *initialCount = n - x; 827 } 828 break; 829 } 830 data += 2; 831 x -= n; 832 } 833 return data; 834} 835 836bool SkAAClip::quickContains(int left, int top, int right, int bottom) const { 837 if (this->isEmpty()) { 838 return false; 839 } 840 if (!fBounds.contains(left, top, right, bottom)) { 841 return false; 842 } 843#if 0 844 if (this->isRect()) { 845 return true; 846 } 847#endif 848 849 int lastY SK_INIT_TO_AVOID_WARNING; 850 const uint8_t* row = this->findRow(top, &lastY); 851 if (lastY < bottom) { 852 return false; 853 } 854 // now just need to check in X 855 int count; 856 row = this->findX(row, left, &count); 857#if 0 858 return count >= (right - left) && 0xFF == row[1]; 859#else 860 int rectWidth = right - left; 861 while (0xFF == row[1]) { 862 if (count >= rectWidth) { 863 return true; 864 } 865 rectWidth -= count; 866 row += 2; 867 count = row[0]; 868 } 869 return false; 870#endif 871} 872 873/////////////////////////////////////////////////////////////////////////////// 874 875class SkAAClip::Builder { 876 SkIRect fBounds; 877 struct Row { 878 int fY; 879 int fWidth; 880 SkTDArray<uint8_t>* fData; 881 }; 882 SkTDArray<Row> fRows; 883 Row* fCurrRow; 884 int fPrevY; 885 int fWidth; 886 int fMinY; 887 888public: 889 Builder(const SkIRect& bounds) : fBounds(bounds) { 890 fPrevY = -1; 891 fWidth = bounds.width(); 892 fCurrRow = NULL; 893 fMinY = bounds.fTop; 894 } 895 896 ~Builder() { 897 Row* row = fRows.begin(); 898 Row* stop = fRows.end(); 899 while (row < stop) { 900 delete row->fData; 901 row += 1; 902 } 903 } 904 905 const SkIRect& getBounds() const { return fBounds; } 906 907 void addRun(int x, int y, U8CPU alpha, int count) { 908 SkASSERT(count > 0); 909 SkASSERT(fBounds.contains(x, y)); 910 SkASSERT(fBounds.contains(x + count - 1, y)); 911 912 x -= fBounds.left(); 913 y -= fBounds.top(); 914 915 Row* row = fCurrRow; 916 if (y != fPrevY) { 917 SkASSERT(y > fPrevY); 918 fPrevY = y; 919 row = this->flushRow(true); 920 row->fY = y; 921 row->fWidth = 0; 922 SkASSERT(row->fData); 923 SkASSERT(0 == row->fData->count()); 924 fCurrRow = row; 925 } 926 927 SkASSERT(row->fWidth <= x); 928 SkASSERT(row->fWidth < fBounds.width()); 929 930 SkTDArray<uint8_t>& data = *row->fData; 931 932 int gap = x - row->fWidth; 933 if (gap) { 934 AppendRun(data, 0, gap); 935 row->fWidth += gap; 936 SkASSERT(row->fWidth < fBounds.width()); 937 } 938 939 AppendRun(data, alpha, count); 940 row->fWidth += count; 941 SkASSERT(row->fWidth <= fBounds.width()); 942 } 943 944 void addColumn(int x, int y, U8CPU alpha, int height) { 945 SkASSERT(fBounds.contains(x, y + height - 1)); 946 947 this->addRun(x, y, alpha, 1); 948 this->flushRowH(fCurrRow); 949 y -= fBounds.fTop; 950 SkASSERT(y == fCurrRow->fY); 951 fCurrRow->fY = y + height - 1; 952 } 953 954 void addRectRun(int x, int y, int width, int height) { 955 SkASSERT(fBounds.contains(x + width - 1, y + height - 1)); 956 this->addRun(x, y, 0xFF, width); 957 958 // we assum the rect must be all we'll see for these scanlines 959 // so we ensure our row goes all the way to our right 960 this->flushRowH(fCurrRow); 961 962 y -= fBounds.fTop; 963 SkASSERT(y == fCurrRow->fY); 964 fCurrRow->fY = y + height - 1; 965 } 966 967 void addAntiRectRun(int x, int y, int width, int height, 968 SkAlpha leftAlpha, SkAlpha rightAlpha) { 969 SkASSERT(fBounds.contains(x + width - 1 + 970 (leftAlpha > 0 ? 1 : 0) + (rightAlpha > 0 ? 1 : 0), 971 y + height - 1)); 972 SkASSERT(width >= 0); 973 974 // Conceptually we're always adding 3 runs, but we should 975 // merge or omit them if possible. 976 if (leftAlpha == 0xFF) { 977 width++; 978 } else if (leftAlpha > 0) { 979 this->addRun(x++, y, leftAlpha, 1); 980 } 981 if (rightAlpha == 0xFF) { 982 width++; 983 } 984 if (width > 0) { 985 this->addRun(x, y, 0xFF, width); 986 } 987 if (rightAlpha > 0 && rightAlpha < 255) { 988 this->addRun(x + width, y, rightAlpha, 1); 989 } 990 991 // we assume the rect must be all we'll see for these scanlines 992 // so we ensure our row goes all the way to our right 993 this->flushRowH(fCurrRow); 994 995 y -= fBounds.fTop; 996 SkASSERT(y == fCurrRow->fY); 997 fCurrRow->fY = y + height - 1; 998 } 999 1000 bool finish(SkAAClip* target) { 1001 this->flushRow(false); 1002 1003 const Row* row = fRows.begin(); 1004 const Row* stop = fRows.end(); 1005 1006 size_t dataSize = 0; 1007 while (row < stop) { 1008 dataSize += row->fData->count(); 1009 row += 1; 1010 } 1011 1012 if (0 == dataSize) { 1013 return target->setEmpty(); 1014 } 1015 1016 SkASSERT(fMinY >= fBounds.fTop); 1017 SkASSERT(fMinY < fBounds.fBottom); 1018 int adjustY = fMinY - fBounds.fTop; 1019 fBounds.fTop = fMinY; 1020 1021 RunHead* head = RunHead::Alloc(fRows.count(), dataSize); 1022 YOffset* yoffset = head->yoffsets(); 1023 uint8_t* data = head->data(); 1024 uint8_t* baseData = data; 1025 1026 row = fRows.begin(); 1027 SkDEBUGCODE(int prevY = row->fY - 1;) 1028 while (row < stop) { 1029 SkASSERT(prevY < row->fY); // must be monotonic 1030 SkDEBUGCODE(prevY = row->fY); 1031 1032 yoffset->fY = row->fY - adjustY; 1033 yoffset->fOffset = data - baseData; 1034 yoffset += 1; 1035 1036 size_t n = row->fData->count(); 1037 memcpy(data, row->fData->begin(), n); 1038#ifdef SK_DEBUG 1039 size_t bytesNeeded = compute_row_length(data, fBounds.width()); 1040 SkASSERT(bytesNeeded == n); 1041#endif 1042 data += n; 1043 1044 row += 1; 1045 } 1046 1047 target->freeRuns(); 1048 target->fBounds = fBounds; 1049 target->fRunHead = head; 1050 return target->trimBounds(); 1051 } 1052 1053 void dump() { 1054 this->validate(); 1055 int y; 1056 for (y = 0; y < fRows.count(); ++y) { 1057 const Row& row = fRows[y]; 1058 SkDebugf("Y:%3d W:%3d", row.fY, row.fWidth); 1059 const SkTDArray<uint8_t>& data = *row.fData; 1060 int count = data.count(); 1061 SkASSERT(!(count & 1)); 1062 const uint8_t* ptr = data.begin(); 1063 for (int x = 0; x < count; x += 2) { 1064 SkDebugf(" [%3d:%02X]", ptr[0], ptr[1]); 1065 ptr += 2; 1066 } 1067 SkDebugf("\n"); 1068 } 1069 } 1070 1071 void validate() { 1072#ifdef SK_DEBUG 1073 if (false) { // avoid bit rot, suppress warning 1074 test_count_left_right_zeros(); 1075 } 1076 int prevY = -1; 1077 for (int i = 0; i < fRows.count(); ++i) { 1078 const Row& row = fRows[i]; 1079 SkASSERT(prevY < row.fY); 1080 SkASSERT(fWidth == row.fWidth); 1081 int count = row.fData->count(); 1082 const uint8_t* ptr = row.fData->begin(); 1083 SkASSERT(!(count & 1)); 1084 int w = 0; 1085 for (int x = 0; x < count; x += 2) { 1086 int n = ptr[0]; 1087 SkASSERT(n > 0); 1088 w += n; 1089 SkASSERT(w <= fWidth); 1090 ptr += 2; 1091 } 1092 SkASSERT(w == fWidth); 1093 prevY = row.fY; 1094 } 1095#endif 1096 } 1097 1098 // only called by BuilderBlitter 1099 void setMinY(int y) { 1100 fMinY = y; 1101 } 1102 1103private: 1104 void flushRowH(Row* row) { 1105 // flush current row if needed 1106 if (row->fWidth < fWidth) { 1107 AppendRun(*row->fData, 0, fWidth - row->fWidth); 1108 row->fWidth = fWidth; 1109 } 1110 } 1111 1112 Row* flushRow(bool readyForAnother) { 1113 Row* next = NULL; 1114 int count = fRows.count(); 1115 if (count > 0) { 1116 this->flushRowH(&fRows[count - 1]); 1117 } 1118 if (count > 1) { 1119 // are our last two runs the same? 1120 Row* prev = &fRows[count - 2]; 1121 Row* curr = &fRows[count - 1]; 1122 SkASSERT(prev->fWidth == fWidth); 1123 SkASSERT(curr->fWidth == fWidth); 1124 if (*prev->fData == *curr->fData) { 1125 prev->fY = curr->fY; 1126 if (readyForAnother) { 1127 curr->fData->rewind(); 1128 next = curr; 1129 } else { 1130 delete curr->fData; 1131 fRows.removeShuffle(count - 1); 1132 } 1133 } else { 1134 if (readyForAnother) { 1135 next = fRows.append(); 1136 next->fData = new SkTDArray<uint8_t>; 1137 } 1138 } 1139 } else { 1140 if (readyForAnother) { 1141 next = fRows.append(); 1142 next->fData = new SkTDArray<uint8_t>; 1143 } 1144 } 1145 return next; 1146 } 1147 1148 static void AppendRun(SkTDArray<uint8_t>& data, U8CPU alpha, int count) { 1149 do { 1150 int n = count; 1151 if (n > 255) { 1152 n = 255; 1153 } 1154 uint8_t* ptr = data.append(2); 1155 ptr[0] = n; 1156 ptr[1] = alpha; 1157 count -= n; 1158 } while (count > 0); 1159 } 1160}; 1161 1162class SkAAClip::BuilderBlitter : public SkBlitter { 1163 int fLastY; 1164 1165 /* 1166 If we see a gap of 1 or more empty scanlines while building in Y-order, 1167 we inject an explicit empty scanline (alpha==0) 1168 1169 See AAClipTest.cpp : test_path_with_hole() 1170 */ 1171 void checkForYGap(int y) { 1172 SkASSERT(y >= fLastY); 1173 if (fLastY > -SK_MaxS32) { 1174 int gap = y - fLastY; 1175 if (gap > 1) { 1176 fBuilder->addRun(fLeft, y - 1, 0, fRight - fLeft); 1177 } 1178 } 1179 fLastY = y; 1180 } 1181 1182public: 1183 1184 BuilderBlitter(Builder* builder) { 1185 fBuilder = builder; 1186 fLeft = builder->getBounds().fLeft; 1187 fRight = builder->getBounds().fRight; 1188 fMinY = SK_MaxS32; 1189 fLastY = -SK_MaxS32; // sentinel 1190 } 1191 1192 void finish() { 1193 if (fMinY < SK_MaxS32) { 1194 fBuilder->setMinY(fMinY); 1195 } 1196 } 1197 1198 /** 1199 Must evaluate clips in scan-line order, so don't want to allow blitV(), 1200 but an AAClip can be clipped down to a single pixel wide, so we 1201 must support it (given AntiRect semantics: minimum width is 2). 1202 Instead we'll rely on the runtime asserts to guarantee Y monotonicity; 1203 any failure cases that misses may have minor artifacts. 1204 */ 1205 virtual void blitV(int x, int y, int height, SkAlpha alpha) SK_OVERRIDE { 1206 this->recordMinY(y); 1207 fBuilder->addColumn(x, y, alpha, height); 1208 fLastY = y + height - 1; 1209 } 1210 1211 virtual void blitRect(int x, int y, int width, int height) SK_OVERRIDE { 1212 this->recordMinY(y); 1213 this->checkForYGap(y); 1214 fBuilder->addRectRun(x, y, width, height); 1215 fLastY = y + height - 1; 1216 } 1217 1218 virtual void blitAntiRect(int x, int y, int width, int height, 1219 SkAlpha leftAlpha, SkAlpha rightAlpha) SK_OVERRIDE { 1220 this->recordMinY(y); 1221 this->checkForYGap(y); 1222 fBuilder->addAntiRectRun(x, y, width, height, leftAlpha, rightAlpha); 1223 fLastY = y + height - 1; 1224 } 1225 1226 virtual void blitMask(const SkMask&, const SkIRect& clip) SK_OVERRIDE 1227 { unexpected(); } 1228 1229 virtual const SkBitmap* justAnOpaqueColor(uint32_t*) SK_OVERRIDE { 1230 return NULL; 1231 } 1232 1233 virtual void blitH(int x, int y, int width) SK_OVERRIDE { 1234 this->recordMinY(y); 1235 this->checkForYGap(y); 1236 fBuilder->addRun(x, y, 0xFF, width); 1237 } 1238 1239 virtual void blitAntiH(int x, int y, const SkAlpha alpha[], 1240 const int16_t runs[]) SK_OVERRIDE { 1241 this->recordMinY(y); 1242 this->checkForYGap(y); 1243 for (;;) { 1244 int count = *runs; 1245 if (count <= 0) { 1246 return; 1247 } 1248 1249 // The supersampler's buffer can be the width of the device, so 1250 // we may have to trim the run to our bounds. If so, we assert that 1251 // the extra spans are always alpha==0 1252 int localX = x; 1253 int localCount = count; 1254 if (x < fLeft) { 1255 SkASSERT(0 == *alpha); 1256 int gap = fLeft - x; 1257 SkASSERT(gap <= count); 1258 localX += gap; 1259 localCount -= gap; 1260 } 1261 int right = x + count; 1262 if (right > fRight) { 1263 SkASSERT(0 == *alpha); 1264 localCount -= right - fRight; 1265 SkASSERT(localCount >= 0); 1266 } 1267 1268 if (localCount) { 1269 fBuilder->addRun(localX, y, *alpha, localCount); 1270 } 1271 // Next run 1272 runs += count; 1273 alpha += count; 1274 x += count; 1275 } 1276 } 1277 1278private: 1279 Builder* fBuilder; 1280 int fLeft; // cache of builder's bounds' left edge 1281 int fRight; 1282 int fMinY; 1283 1284 /* 1285 * We track this, in case the scan converter skipped some number of 1286 * scanlines at the (relative to the bounds it was given). This allows 1287 * the builder, during its finish, to trip its bounds down to the "real" 1288 * top. 1289 */ 1290 void recordMinY(int y) { 1291 if (y < fMinY) { 1292 fMinY = y; 1293 } 1294 } 1295 1296 void unexpected() { 1297 SkDebugf("---- did not expect to get called here"); 1298 sk_throw(); 1299 } 1300}; 1301 1302bool SkAAClip::setPath(const SkPath& path, const SkRegion* clip, bool doAA) { 1303 AUTO_AACLIP_VALIDATE(*this); 1304 1305 if (clip && clip->isEmpty()) { 1306 return this->setEmpty(); 1307 } 1308 1309 SkIRect ibounds; 1310 path.getBounds().roundOut(&ibounds); 1311 1312 SkRegion tmpClip; 1313 if (NULL == clip) { 1314 tmpClip.setRect(ibounds); 1315 clip = &tmpClip; 1316 } 1317 1318 if (path.isInverseFillType()) { 1319 ibounds = clip->getBounds(); 1320 } else { 1321 if (ibounds.isEmpty() || !ibounds.intersect(clip->getBounds())) { 1322 return this->setEmpty(); 1323 } 1324 } 1325 1326 Builder builder(ibounds); 1327 BuilderBlitter blitter(&builder); 1328 1329 if (doAA) { 1330 SkScan::AntiFillPath(path, *clip, &blitter, true); 1331 } else { 1332 SkScan::FillPath(path, *clip, &blitter); 1333 } 1334 1335 blitter.finish(); 1336 return builder.finish(this); 1337} 1338 1339/////////////////////////////////////////////////////////////////////////////// 1340 1341typedef void (*RowProc)(SkAAClip::Builder&, int bottom, 1342 const uint8_t* rowA, const SkIRect& rectA, 1343 const uint8_t* rowB, const SkIRect& rectB); 1344 1345typedef U8CPU (*AlphaProc)(U8CPU alphaA, U8CPU alphaB); 1346 1347static U8CPU sectAlphaProc(U8CPU alphaA, U8CPU alphaB) { 1348 // Multiply 1349 return SkMulDiv255Round(alphaA, alphaB); 1350} 1351 1352static U8CPU unionAlphaProc(U8CPU alphaA, U8CPU alphaB) { 1353 // SrcOver 1354 return alphaA + alphaB - SkMulDiv255Round(alphaA, alphaB); 1355} 1356 1357static U8CPU diffAlphaProc(U8CPU alphaA, U8CPU alphaB) { 1358 // SrcOut 1359 return SkMulDiv255Round(alphaA, 0xFF - alphaB); 1360} 1361 1362static U8CPU xorAlphaProc(U8CPU alphaA, U8CPU alphaB) { 1363 // XOR 1364 return alphaA + alphaB - 2 * SkMulDiv255Round(alphaA, alphaB); 1365} 1366 1367static AlphaProc find_alpha_proc(SkRegion::Op op) { 1368 switch (op) { 1369 case SkRegion::kIntersect_Op: 1370 return sectAlphaProc; 1371 case SkRegion::kDifference_Op: 1372 return diffAlphaProc; 1373 case SkRegion::kUnion_Op: 1374 return unionAlphaProc; 1375 case SkRegion::kXOR_Op: 1376 return xorAlphaProc; 1377 default: 1378 SkDEBUGFAIL("unexpected region op"); 1379 return sectAlphaProc; 1380 } 1381} 1382 1383static const uint8_t gEmptyRow[] = { 1384 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 1385 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 1386 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 1387 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 1388 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 1389 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 1390 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 1391 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 0xFF, 0, 1392}; 1393 1394class RowIter { 1395public: 1396 RowIter(const uint8_t* row, const SkIRect& bounds) { 1397 fRow = row; 1398 fLeft = bounds.fLeft; 1399 fBoundsRight = bounds.fRight; 1400 if (row) { 1401 fRight = bounds.fLeft + row[0]; 1402 SkASSERT(fRight <= fBoundsRight); 1403 fAlpha = row[1]; 1404 fDone = false; 1405 } else { 1406 fDone = true; 1407 fRight = kMaxInt32; 1408 fAlpha = 0; 1409 } 1410 } 1411 1412 bool done() const { return fDone; } 1413 int left() const { return fLeft; } 1414 int right() const { return fRight; } 1415 U8CPU alpha() const { return fAlpha; } 1416 void next() { 1417 if (!fDone) { 1418 fLeft = fRight; 1419 if (fRight == fBoundsRight) { 1420 fDone = true; 1421 fRight = kMaxInt32; 1422 fAlpha = 0; 1423 } else { 1424 fRow += 2; 1425 fRight += fRow[0]; 1426 fAlpha = fRow[1]; 1427 SkASSERT(fRight <= fBoundsRight); 1428 } 1429 } 1430 } 1431 1432private: 1433 const uint8_t* fRow; 1434 int fLeft; 1435 int fRight; 1436 int fBoundsRight; 1437 bool fDone; 1438 uint8_t fAlpha; 1439}; 1440 1441static void adjust_row(RowIter& iter, int& leftA, int& riteA, int rite) { 1442 if (rite == riteA) { 1443 iter.next(); 1444 leftA = iter.left(); 1445 riteA = iter.right(); 1446 } 1447} 1448 1449#if 0 // UNUSED 1450static bool intersect(int& min, int& max, int boundsMin, int boundsMax) { 1451 SkASSERT(min < max); 1452 SkASSERT(boundsMin < boundsMax); 1453 if (min >= boundsMax || max <= boundsMin) { 1454 return false; 1455 } 1456 if (min < boundsMin) { 1457 min = boundsMin; 1458 } 1459 if (max > boundsMax) { 1460 max = boundsMax; 1461 } 1462 return true; 1463} 1464#endif 1465 1466static void operatorX(SkAAClip::Builder& builder, int lastY, 1467 RowIter& iterA, RowIter& iterB, 1468 AlphaProc proc, const SkIRect& bounds) { 1469 int leftA = iterA.left(); 1470 int riteA = iterA.right(); 1471 int leftB = iterB.left(); 1472 int riteB = iterB.right(); 1473 1474 int prevRite = bounds.fLeft; 1475 1476 do { 1477 U8CPU alphaA = 0; 1478 U8CPU alphaB = 0; 1479 int left, rite; 1480 1481 if (leftA < leftB) { 1482 left = leftA; 1483 alphaA = iterA.alpha(); 1484 if (riteA <= leftB) { 1485 rite = riteA; 1486 } else { 1487 rite = leftA = leftB; 1488 } 1489 } else if (leftB < leftA) { 1490 left = leftB; 1491 alphaB = iterB.alpha(); 1492 if (riteB <= leftA) { 1493 rite = riteB; 1494 } else { 1495 rite = leftB = leftA; 1496 } 1497 } else { 1498 left = leftA; // or leftB, since leftA == leftB 1499 rite = leftA = leftB = SkMin32(riteA, riteB); 1500 alphaA = iterA.alpha(); 1501 alphaB = iterB.alpha(); 1502 } 1503 1504 if (left >= bounds.fRight) { 1505 break; 1506 } 1507 if (rite > bounds.fRight) { 1508 rite = bounds.fRight; 1509 } 1510 1511 if (left >= bounds.fLeft) { 1512 SkASSERT(rite > left); 1513 builder.addRun(left, lastY, proc(alphaA, alphaB), rite - left); 1514 prevRite = rite; 1515 } 1516 1517 adjust_row(iterA, leftA, riteA, rite); 1518 adjust_row(iterB, leftB, riteB, rite); 1519 } while (!iterA.done() || !iterB.done()); 1520 1521 if (prevRite < bounds.fRight) { 1522 builder.addRun(prevRite, lastY, 0, bounds.fRight - prevRite); 1523 } 1524} 1525 1526static void adjust_iter(SkAAClip::Iter& iter, int& topA, int& botA, int bot) { 1527 if (bot == botA) { 1528 iter.next(); 1529 topA = botA; 1530 SkASSERT(botA == iter.top()); 1531 botA = iter.bottom(); 1532 } 1533} 1534 1535static void operateY(SkAAClip::Builder& builder, const SkAAClip& A, 1536 const SkAAClip& B, SkRegion::Op op) { 1537 AlphaProc proc = find_alpha_proc(op); 1538 const SkIRect& bounds = builder.getBounds(); 1539 1540 SkAAClip::Iter iterA(A); 1541 SkAAClip::Iter iterB(B); 1542 1543 SkASSERT(!iterA.done()); 1544 int topA = iterA.top(); 1545 int botA = iterA.bottom(); 1546 SkASSERT(!iterB.done()); 1547 int topB = iterB.top(); 1548 int botB = iterB.bottom(); 1549 1550 do { 1551 const uint8_t* rowA = NULL; 1552 const uint8_t* rowB = NULL; 1553 int top, bot; 1554 1555 if (topA < topB) { 1556 top = topA; 1557 rowA = iterA.data(); 1558 if (botA <= topB) { 1559 bot = botA; 1560 } else { 1561 bot = topA = topB; 1562 } 1563 1564 } else if (topB < topA) { 1565 top = topB; 1566 rowB = iterB.data(); 1567 if (botB <= topA) { 1568 bot = botB; 1569 } else { 1570 bot = topB = topA; 1571 } 1572 } else { 1573 top = topA; // or topB, since topA == topB 1574 bot = topA = topB = SkMin32(botA, botB); 1575 rowA = iterA.data(); 1576 rowB = iterB.data(); 1577 } 1578 1579 if (top >= bounds.fBottom) { 1580 break; 1581 } 1582 1583 if (bot > bounds.fBottom) { 1584 bot = bounds.fBottom; 1585 } 1586 SkASSERT(top < bot); 1587 1588 if (!rowA && !rowB) { 1589 builder.addRun(bounds.fLeft, bot - 1, 0, bounds.width()); 1590 } else if (top >= bounds.fTop) { 1591 SkASSERT(bot <= bounds.fBottom); 1592 RowIter rowIterA(rowA, rowA ? A.getBounds() : bounds); 1593 RowIter rowIterB(rowB, rowB ? B.getBounds() : bounds); 1594 operatorX(builder, bot - 1, rowIterA, rowIterB, proc, bounds); 1595 } 1596 1597 adjust_iter(iterA, topA, botA, bot); 1598 adjust_iter(iterB, topB, botB, bot); 1599 } while (!iterA.done() || !iterB.done()); 1600} 1601 1602bool SkAAClip::op(const SkAAClip& clipAOrig, const SkAAClip& clipBOrig, 1603 SkRegion::Op op) { 1604 AUTO_AACLIP_VALIDATE(*this); 1605 1606 if (SkRegion::kReplace_Op == op) { 1607 return this->set(clipBOrig); 1608 } 1609 1610 const SkAAClip* clipA = &clipAOrig; 1611 const SkAAClip* clipB = &clipBOrig; 1612 1613 if (SkRegion::kReverseDifference_Op == op) { 1614 SkTSwap(clipA, clipB); 1615 op = SkRegion::kDifference_Op; 1616 } 1617 1618 bool a_empty = clipA->isEmpty(); 1619 bool b_empty = clipB->isEmpty(); 1620 1621 SkIRect bounds; 1622 switch (op) { 1623 case SkRegion::kDifference_Op: 1624 if (a_empty) { 1625 return this->setEmpty(); 1626 } 1627 if (b_empty || !SkIRect::Intersects(clipA->fBounds, clipB->fBounds)) { 1628 return this->set(*clipA); 1629 } 1630 bounds = clipA->fBounds; 1631 break; 1632 1633 case SkRegion::kIntersect_Op: 1634 if ((a_empty | b_empty) || !bounds.intersect(clipA->fBounds, 1635 clipB->fBounds)) { 1636 return this->setEmpty(); 1637 } 1638 break; 1639 1640 case SkRegion::kUnion_Op: 1641 case SkRegion::kXOR_Op: 1642 if (a_empty) { 1643 return this->set(*clipB); 1644 } 1645 if (b_empty) { 1646 return this->set(*clipA); 1647 } 1648 bounds = clipA->fBounds; 1649 bounds.join(clipB->fBounds); 1650 break; 1651 1652 default: 1653 SkDEBUGFAIL("unknown region op"); 1654 return !this->isEmpty(); 1655 } 1656 1657 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds)); 1658 SkASSERT(SkIRect::Intersects(bounds, clipB->fBounds)); 1659 1660 Builder builder(bounds); 1661 operateY(builder, *clipA, *clipB, op); 1662 1663 return builder.finish(this); 1664} 1665 1666/* 1667 * It can be expensive to build a local aaclip before applying the op, so 1668 * we first see if we can restrict the bounds of new rect to our current 1669 * bounds, or note that the new rect subsumes our current clip. 1670 */ 1671 1672bool SkAAClip::op(const SkIRect& rOrig, SkRegion::Op op) { 1673 SkIRect rStorage; 1674 const SkIRect* r = &rOrig; 1675 1676 switch (op) { 1677 case SkRegion::kIntersect_Op: 1678 if (!rStorage.intersect(rOrig, fBounds)) { 1679 // no overlap, so we're empty 1680 return this->setEmpty(); 1681 } 1682 if (rStorage == fBounds) { 1683 // we were wholly inside the rect, no change 1684 return !this->isEmpty(); 1685 } 1686 if (this->quickContains(rStorage)) { 1687 // the intersection is wholly inside us, we're a rect 1688 return this->setRect(rStorage); 1689 } 1690 r = &rStorage; // use the intersected bounds 1691 break; 1692 case SkRegion::kDifference_Op: 1693 break; 1694 case SkRegion::kUnion_Op: 1695 if (rOrig.contains(fBounds)) { 1696 return this->setRect(rOrig); 1697 } 1698 break; 1699 default: 1700 break; 1701 } 1702 1703 SkAAClip clip; 1704 clip.setRect(*r); 1705 return this->op(*this, clip, op); 1706} 1707 1708bool SkAAClip::op(const SkRect& rOrig, SkRegion::Op op, bool doAA) { 1709 SkRect rStorage, boundsStorage; 1710 const SkRect* r = &rOrig; 1711 1712 boundsStorage.set(fBounds); 1713 switch (op) { 1714 case SkRegion::kIntersect_Op: 1715 case SkRegion::kDifference_Op: 1716 if (!rStorage.intersect(rOrig, boundsStorage)) { 1717 if (SkRegion::kIntersect_Op == op) { 1718 return this->setEmpty(); 1719 } else { // kDifference 1720 return !this->isEmpty(); 1721 } 1722 } 1723 r = &rStorage; // use the intersected bounds 1724 break; 1725 case SkRegion::kUnion_Op: 1726 if (rOrig.contains(boundsStorage)) { 1727 return this->setRect(rOrig); 1728 } 1729 break; 1730 default: 1731 break; 1732 } 1733 1734 SkAAClip clip; 1735 clip.setRect(*r, doAA); 1736 return this->op(*this, clip, op); 1737} 1738 1739bool SkAAClip::op(const SkAAClip& clip, SkRegion::Op op) { 1740 return this->op(*this, clip, op); 1741} 1742 1743/////////////////////////////////////////////////////////////////////////////// 1744 1745bool SkAAClip::translate(int dx, int dy, SkAAClip* dst) const { 1746 if (NULL == dst) { 1747 return !this->isEmpty(); 1748 } 1749 1750 if (this->isEmpty()) { 1751 return dst->setEmpty(); 1752 } 1753 1754 if (this != dst) { 1755 sk_atomic_inc(&fRunHead->fRefCnt); 1756 dst->freeRuns(); 1757 dst->fRunHead = fRunHead; 1758 dst->fBounds = fBounds; 1759 } 1760 dst->fBounds.offset(dx, dy); 1761 return true; 1762} 1763 1764static void expand_row_to_mask(uint8_t* SK_RESTRICT mask, 1765 const uint8_t* SK_RESTRICT row, 1766 int width) { 1767 while (width > 0) { 1768 int n = row[0]; 1769 SkASSERT(width >= n); 1770 memset(mask, row[1], n); 1771 mask += n; 1772 row += 2; 1773 width -= n; 1774 } 1775 SkASSERT(0 == width); 1776} 1777 1778void SkAAClip::copyToMask(SkMask* mask) const { 1779 mask->fFormat = SkMask::kA8_Format; 1780 if (this->isEmpty()) { 1781 mask->fBounds.setEmpty(); 1782 mask->fImage = NULL; 1783 mask->fRowBytes = 0; 1784 return; 1785 } 1786 1787 mask->fBounds = fBounds; 1788 mask->fRowBytes = fBounds.width(); 1789 size_t size = mask->computeImageSize(); 1790 mask->fImage = SkMask::AllocImage(size); 1791 1792 Iter iter(*this); 1793 uint8_t* dst = mask->fImage; 1794 const int width = fBounds.width(); 1795 1796 int y = fBounds.fTop; 1797 while (!iter.done()) { 1798 do { 1799 expand_row_to_mask(dst, iter.data(), width); 1800 dst += mask->fRowBytes; 1801 } while (++y < iter.bottom()); 1802 iter.next(); 1803 } 1804} 1805 1806/////////////////////////////////////////////////////////////////////////////// 1807/////////////////////////////////////////////////////////////////////////////// 1808 1809static void expandToRuns(const uint8_t* SK_RESTRICT data, int initialCount, int width, 1810 int16_t* SK_RESTRICT runs, SkAlpha* SK_RESTRICT aa) { 1811 // we don't read our initial n from data, since the caller may have had to 1812 // clip it, hence the initialCount parameter. 1813 int n = initialCount; 1814 for (;;) { 1815 if (n > width) { 1816 n = width; 1817 } 1818 SkASSERT(n > 0); 1819 runs[0] = n; 1820 runs += n; 1821 1822 aa[0] = data[1]; 1823 aa += n; 1824 1825 data += 2; 1826 width -= n; 1827 if (0 == width) { 1828 break; 1829 } 1830 // load the next count 1831 n = data[0]; 1832 } 1833 runs[0] = 0; // sentinel 1834} 1835 1836SkAAClipBlitter::~SkAAClipBlitter() { 1837 sk_free(fScanlineScratch); 1838} 1839 1840void SkAAClipBlitter::ensureRunsAndAA() { 1841 if (NULL == fScanlineScratch) { 1842 // add 1 so we can store the terminating run count of 0 1843 int count = fAAClipBounds.width() + 1; 1844 // we use this either for fRuns + fAA, or a scaline of a mask 1845 // which may be as deep as 32bits 1846 fScanlineScratch = sk_malloc_throw(count * sizeof(SkPMColor)); 1847 fRuns = (int16_t*)fScanlineScratch; 1848 fAA = (SkAlpha*)(fRuns + count); 1849 } 1850} 1851 1852void SkAAClipBlitter::blitH(int x, int y, int width) { 1853 SkASSERT(width > 0); 1854 SkASSERT(fAAClipBounds.contains(x, y)); 1855 SkASSERT(fAAClipBounds.contains(x + width - 1, y)); 1856 1857 const uint8_t* row = fAAClip->findRow(y); 1858 int initialCount; 1859 row = fAAClip->findX(row, x, &initialCount); 1860 1861 if (initialCount >= width) { 1862 SkAlpha alpha = row[1]; 1863 if (0 == alpha) { 1864 return; 1865 } 1866 if (0xFF == alpha) { 1867 fBlitter->blitH(x, y, width); 1868 return; 1869 } 1870 } 1871 1872 this->ensureRunsAndAA(); 1873 expandToRuns(row, initialCount, width, fRuns, fAA); 1874 1875 fBlitter->blitAntiH(x, y, fAA, fRuns); 1876} 1877 1878static void merge(const uint8_t* SK_RESTRICT row, int rowN, 1879 const SkAlpha* SK_RESTRICT srcAA, 1880 const int16_t* SK_RESTRICT srcRuns, 1881 SkAlpha* SK_RESTRICT dstAA, 1882 int16_t* SK_RESTRICT dstRuns, 1883 int width) { 1884 SkDEBUGCODE(int accumulated = 0;) 1885 int srcN = srcRuns[0]; 1886 // do we need this check? 1887 if (0 == srcN) { 1888 return; 1889 } 1890 1891 for (;;) { 1892 SkASSERT(rowN > 0); 1893 SkASSERT(srcN > 0); 1894 1895 unsigned newAlpha = SkMulDiv255Round(srcAA[0], row[1]); 1896 int minN = SkMin32(srcN, rowN); 1897 dstRuns[0] = minN; 1898 dstRuns += minN; 1899 dstAA[0] = newAlpha; 1900 dstAA += minN; 1901 1902 if (0 == (srcN -= minN)) { 1903 srcN = srcRuns[0]; // refresh 1904 srcRuns += srcN; 1905 srcAA += srcN; 1906 srcN = srcRuns[0]; // reload 1907 if (0 == srcN) { 1908 break; 1909 } 1910 } 1911 if (0 == (rowN -= minN)) { 1912 row += 2; 1913 rowN = row[0]; // reload 1914 } 1915 1916 SkDEBUGCODE(accumulated += minN;) 1917 SkASSERT(accumulated <= width); 1918 } 1919 dstRuns[0] = 0; 1920} 1921 1922void SkAAClipBlitter::blitAntiH(int x, int y, const SkAlpha aa[], 1923 const int16_t runs[]) { 1924 1925 const uint8_t* row = fAAClip->findRow(y); 1926 int initialCount; 1927 row = fAAClip->findX(row, x, &initialCount); 1928 1929 this->ensureRunsAndAA(); 1930 1931 merge(row, initialCount, aa, runs, fAA, fRuns, fAAClipBounds.width()); 1932 fBlitter->blitAntiH(x, y, fAA, fRuns); 1933} 1934 1935void SkAAClipBlitter::blitV(int x, int y, int height, SkAlpha alpha) { 1936 if (fAAClip->quickContains(x, y, x + 1, y + height)) { 1937 fBlitter->blitV(x, y, height, alpha); 1938 return; 1939 } 1940 1941 for (;;) { 1942 int lastY SK_INIT_TO_AVOID_WARNING; 1943 const uint8_t* row = fAAClip->findRow(y, &lastY); 1944 int dy = lastY - y + 1; 1945 if (dy > height) { 1946 dy = height; 1947 } 1948 height -= dy; 1949 1950 row = fAAClip->findX(row, x); 1951 SkAlpha newAlpha = SkMulDiv255Round(alpha, row[1]); 1952 if (newAlpha) { 1953 fBlitter->blitV(x, y, dy, newAlpha); 1954 } 1955 SkASSERT(height >= 0); 1956 if (height <= 0) { 1957 break; 1958 } 1959 y = lastY + 1; 1960 } 1961} 1962 1963void SkAAClipBlitter::blitRect(int x, int y, int width, int height) { 1964 if (fAAClip->quickContains(x, y, x + width, y + height)) { 1965 fBlitter->blitRect(x, y, width, height); 1966 return; 1967 } 1968 1969 while (--height >= 0) { 1970 this->blitH(x, y, width); 1971 y += 1; 1972 } 1973} 1974 1975typedef void (*MergeAAProc)(const void* src, int width, const uint8_t* row, 1976 int initialRowCount, void* dst); 1977 1978static void small_memcpy(void* dst, const void* src, size_t n) { 1979 memcpy(dst, src, n); 1980} 1981 1982static void small_bzero(void* dst, size_t n) { 1983 sk_bzero(dst, n); 1984} 1985 1986static inline uint8_t mergeOne(uint8_t value, unsigned alpha) { 1987 return SkMulDiv255Round(value, alpha); 1988} 1989static inline uint16_t mergeOne(uint16_t value, unsigned alpha) { 1990 unsigned r = SkGetPackedR16(value); 1991 unsigned g = SkGetPackedG16(value); 1992 unsigned b = SkGetPackedB16(value); 1993 return SkPackRGB16(SkMulDiv255Round(r, alpha), 1994 SkMulDiv255Round(g, alpha), 1995 SkMulDiv255Round(b, alpha)); 1996} 1997static inline SkPMColor mergeOne(SkPMColor value, unsigned alpha) { 1998 unsigned a = SkGetPackedA32(value); 1999 unsigned r = SkGetPackedR32(value); 2000 unsigned g = SkGetPackedG32(value); 2001 unsigned b = SkGetPackedB32(value); 2002 return SkPackARGB32(SkMulDiv255Round(a, alpha), 2003 SkMulDiv255Round(r, alpha), 2004 SkMulDiv255Round(g, alpha), 2005 SkMulDiv255Round(b, alpha)); 2006} 2007 2008template <typename T> void mergeT(const T* SK_RESTRICT src, int srcN, 2009 const uint8_t* SK_RESTRICT row, int rowN, 2010 T* SK_RESTRICT dst) { 2011 for (;;) { 2012 SkASSERT(rowN > 0); 2013 SkASSERT(srcN > 0); 2014 2015 int n = SkMin32(rowN, srcN); 2016 unsigned rowA = row[1]; 2017 if (0xFF == rowA) { 2018 small_memcpy(dst, src, n * sizeof(T)); 2019 } else if (0 == rowA) { 2020 small_bzero(dst, n * sizeof(T)); 2021 } else { 2022 for (int i = 0; i < n; ++i) { 2023 dst[i] = mergeOne(src[i], rowA); 2024 } 2025 } 2026 2027 if (0 == (srcN -= n)) { 2028 break; 2029 } 2030 2031 src += n; 2032 dst += n; 2033 2034 SkASSERT(rowN == n); 2035 row += 2; 2036 rowN = row[0]; 2037 } 2038} 2039 2040static MergeAAProc find_merge_aa_proc(SkMask::Format format) { 2041 switch (format) { 2042 case SkMask::kBW_Format: 2043 SkDEBUGFAIL("unsupported"); 2044 return NULL; 2045 case SkMask::kA8_Format: 2046 case SkMask::k3D_Format: { 2047 void (*proc8)(const uint8_t*, int, const uint8_t*, int, uint8_t*) = mergeT; 2048 return (MergeAAProc)proc8; 2049 } 2050 case SkMask::kLCD16_Format: { 2051 void (*proc16)(const uint16_t*, int, const uint8_t*, int, uint16_t*) = mergeT; 2052 return (MergeAAProc)proc16; 2053 } 2054 case SkMask::kLCD32_Format: { 2055 void (*proc32)(const SkPMColor*, int, const uint8_t*, int, SkPMColor*) = mergeT; 2056 return (MergeAAProc)proc32; 2057 } 2058 default: 2059 SkDEBUGFAIL("unsupported"); 2060 return NULL; 2061 } 2062} 2063 2064static U8CPU bit2byte(int bitInAByte) { 2065 SkASSERT(bitInAByte <= 0xFF); 2066 // negation turns any non-zero into 0xFFFFFF??, so we just shift down 2067 // some value >= 8 to get a full FF value 2068 return -bitInAByte >> 8; 2069} 2070 2071static void upscaleBW2A8(SkMask* dstMask, const SkMask& srcMask) { 2072 SkASSERT(SkMask::kBW_Format == srcMask.fFormat); 2073 SkASSERT(SkMask::kA8_Format == dstMask->fFormat); 2074 2075 const int width = srcMask.fBounds.width(); 2076 const int height = srcMask.fBounds.height(); 2077 2078 const uint8_t* SK_RESTRICT src = (const uint8_t*)srcMask.fImage; 2079 const size_t srcRB = srcMask.fRowBytes; 2080 uint8_t* SK_RESTRICT dst = (uint8_t*)dstMask->fImage; 2081 const size_t dstRB = dstMask->fRowBytes; 2082 2083 const int wholeBytes = width >> 3; 2084 const int leftOverBits = width & 7; 2085 2086 for (int y = 0; y < height; ++y) { 2087 uint8_t* SK_RESTRICT d = dst; 2088 for (int i = 0; i < wholeBytes; ++i) { 2089 int srcByte = src[i]; 2090 d[0] = bit2byte(srcByte & (1 << 7)); 2091 d[1] = bit2byte(srcByte & (1 << 6)); 2092 d[2] = bit2byte(srcByte & (1 << 5)); 2093 d[3] = bit2byte(srcByte & (1 << 4)); 2094 d[4] = bit2byte(srcByte & (1 << 3)); 2095 d[5] = bit2byte(srcByte & (1 << 2)); 2096 d[6] = bit2byte(srcByte & (1 << 1)); 2097 d[7] = bit2byte(srcByte & (1 << 0)); 2098 d += 8; 2099 } 2100 if (leftOverBits) { 2101 int srcByte = src[wholeBytes]; 2102 for (int x = 0; x < leftOverBits; ++x) { 2103 *d++ = bit2byte(srcByte & 0x80); 2104 srcByte <<= 1; 2105 } 2106 } 2107 src += srcRB; 2108 dst += dstRB; 2109 } 2110} 2111 2112void SkAAClipBlitter::blitMask(const SkMask& origMask, const SkIRect& clip) { 2113 SkASSERT(fAAClip->getBounds().contains(clip)); 2114 2115 if (fAAClip->quickContains(clip)) { 2116 fBlitter->blitMask(origMask, clip); 2117 return; 2118 } 2119 2120 const SkMask* mask = &origMask; 2121 2122 // if we're BW, we need to upscale to A8 (ugh) 2123 SkMask grayMask; 2124 grayMask.fImage = NULL; 2125 if (SkMask::kBW_Format == origMask.fFormat) { 2126 grayMask.fFormat = SkMask::kA8_Format; 2127 grayMask.fBounds = origMask.fBounds; 2128 grayMask.fRowBytes = origMask.fBounds.width(); 2129 size_t size = grayMask.computeImageSize(); 2130 grayMask.fImage = (uint8_t*)fGrayMaskScratch.reset(size, 2131 SkAutoMalloc::kReuse_OnShrink); 2132 2133 upscaleBW2A8(&grayMask, origMask); 2134 mask = &grayMask; 2135 } 2136 2137 this->ensureRunsAndAA(); 2138 2139 // HACK -- we are devolving 3D into A8, need to copy the rest of the 3D 2140 // data into a temp block to support it better (ugh) 2141 2142 const void* src = mask->getAddr(clip.fLeft, clip.fTop); 2143 const size_t srcRB = mask->fRowBytes; 2144 const int width = clip.width(); 2145 MergeAAProc mergeProc = find_merge_aa_proc(mask->fFormat); 2146 2147 SkMask rowMask; 2148 rowMask.fFormat = SkMask::k3D_Format == mask->fFormat ? SkMask::kA8_Format : mask->fFormat; 2149 rowMask.fBounds.fLeft = clip.fLeft; 2150 rowMask.fBounds.fRight = clip.fRight; 2151 rowMask.fRowBytes = mask->fRowBytes; // doesn't matter, since our height==1 2152 rowMask.fImage = (uint8_t*)fScanlineScratch; 2153 2154 int y = clip.fTop; 2155 const int stopY = y + clip.height(); 2156 2157 do { 2158 int localStopY SK_INIT_TO_AVOID_WARNING; 2159 const uint8_t* row = fAAClip->findRow(y, &localStopY); 2160 // findRow returns last Y, not stop, so we add 1 2161 localStopY = SkMin32(localStopY + 1, stopY); 2162 2163 int initialCount; 2164 row = fAAClip->findX(row, clip.fLeft, &initialCount); 2165 do { 2166 mergeProc(src, width, row, initialCount, rowMask.fImage); 2167 rowMask.fBounds.fTop = y; 2168 rowMask.fBounds.fBottom = y + 1; 2169 fBlitter->blitMask(rowMask, rowMask.fBounds); 2170 src = (const void*)((const char*)src + srcRB); 2171 } while (++y < localStopY); 2172 } while (y < stopY); 2173} 2174 2175const SkBitmap* SkAAClipBlitter::justAnOpaqueColor(uint32_t* value) { 2176 return NULL; 2177} 2178