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