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