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