1 2 /* 3 * Copyright 2006 The Android Open Source Project 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 10 #include "SkRegionPriv.h" 11 #include "SkTemplates.h" 12 #include "SkThread.h" 13 #include "SkUtils.h" 14 15 /* Region Layout 16 * 17 * TOP 18 * 19 * [ Bottom, X-Intervals, [Left, Right]..., X-Sentinel ] 20 * ... 21 * 22 * Y-Sentinel 23 */ 24 25 SkDEBUGCODE(int32_t gRgnAllocCounter;) 26 27 ///////////////////////////////////////////////////////////////////////////////////////////////// 28 29 /* Pass in the beginning with the intervals. 30 * We back up 1 to read the interval-count. 31 * Return the beginning of the next scanline (i.e. the next Y-value) 32 */ 33 static SkRegion::RunType* skip_intervals(const SkRegion::RunType runs[]) { 34 int intervals = runs[-1]; 35 #ifdef SK_DEBUG 36 if (intervals > 0) { 37 SkASSERT(runs[0] < runs[1]); 38 SkASSERT(runs[1] < SkRegion::kRunTypeSentinel); 39 } else { 40 SkASSERT(0 == intervals); 41 SkASSERT(SkRegion::kRunTypeSentinel == runs[0]); 42 } 43 #endif 44 runs += intervals * 2 + 1; 45 return const_cast<SkRegion::RunType*>(runs); 46 } 47 48 bool SkRegion::RunsAreARect(const SkRegion::RunType runs[], int count, 49 SkIRect* bounds) { 50 assert_sentinel(runs[0], false); // top 51 SkASSERT(count >= kRectRegionRuns); 52 53 if (count == kRectRegionRuns) { 54 assert_sentinel(runs[1], false); // bottom 55 SkASSERT(1 == runs[2]); 56 assert_sentinel(runs[3], false); // left 57 assert_sentinel(runs[4], false); // right 58 assert_sentinel(runs[5], true); 59 assert_sentinel(runs[6], true); 60 61 SkASSERT(runs[0] < runs[1]); // valid height 62 SkASSERT(runs[3] < runs[4]); // valid width 63 64 bounds->set(runs[3], runs[0], runs[4], runs[1]); 65 return true; 66 } 67 return false; 68 } 69 70 ////////////////////////////////////////////////////////////////////////// 71 72 SkRegion::SkRegion() { 73 fBounds.set(0, 0, 0, 0); 74 fRunHead = SkRegion_gEmptyRunHeadPtr; 75 } 76 77 SkRegion::SkRegion(const SkRegion& src) { 78 fRunHead = SkRegion_gEmptyRunHeadPtr; // just need a value that won't trigger sk_free(fRunHead) 79 this->setRegion(src); 80 } 81 82 SkRegion::SkRegion(const SkIRect& rect) { 83 fRunHead = SkRegion_gEmptyRunHeadPtr; // just need a value that won't trigger sk_free(fRunHead) 84 this->setRect(rect); 85 } 86 87 SkRegion::~SkRegion() { 88 this->freeRuns(); 89 } 90 91 void SkRegion::freeRuns() { 92 if (this->isComplex()) { 93 SkASSERT(fRunHead->fRefCnt >= 1); 94 if (sk_atomic_dec(&fRunHead->fRefCnt) == 1) { 95 //SkASSERT(gRgnAllocCounter > 0); 96 //SkDEBUGCODE(sk_atomic_dec(&gRgnAllocCounter)); 97 //SkDEBUGF(("************** gRgnAllocCounter::free %d\n", gRgnAllocCounter)); 98 sk_free(fRunHead); 99 } 100 } 101 } 102 103 void SkRegion::allocateRuns(int count, int ySpanCount, int intervalCount) { 104 fRunHead = RunHead::Alloc(count, ySpanCount, intervalCount); 105 } 106 107 void SkRegion::allocateRuns(int count) { 108 fRunHead = RunHead::Alloc(count); 109 } 110 111 void SkRegion::allocateRuns(const RunHead& head) { 112 fRunHead = RunHead::Alloc(head.fRunCount, 113 head.getYSpanCount(), 114 head.getIntervalCount()); 115 } 116 117 SkRegion& SkRegion::operator=(const SkRegion& src) { 118 (void)this->setRegion(src); 119 return *this; 120 } 121 122 void SkRegion::swap(SkRegion& other) { 123 SkTSwap<SkIRect>(fBounds, other.fBounds); 124 SkTSwap<RunHead*>(fRunHead, other.fRunHead); 125 } 126 127 int SkRegion::computeRegionComplexity() const { 128 if (this->isEmpty()) { 129 return 0; 130 } else if (this->isRect()) { 131 return 1; 132 } 133 return fRunHead->getIntervalCount(); 134 } 135 136 bool SkRegion::setEmpty() { 137 this->freeRuns(); 138 fBounds.set(0, 0, 0, 0); 139 fRunHead = SkRegion_gEmptyRunHeadPtr; 140 return false; 141 } 142 143 bool SkRegion::setRect(int32_t left, int32_t top, 144 int32_t right, int32_t bottom) { 145 if (left >= right || top >= bottom) { 146 return this->setEmpty(); 147 } 148 this->freeRuns(); 149 fBounds.set(left, top, right, bottom); 150 fRunHead = SkRegion_gRectRunHeadPtr; 151 return true; 152 } 153 154 bool SkRegion::setRect(const SkIRect& r) { 155 return this->setRect(r.fLeft, r.fTop, r.fRight, r.fBottom); 156 } 157 158 bool SkRegion::setRegion(const SkRegion& src) { 159 if (this != &src) { 160 this->freeRuns(); 161 162 fBounds = src.fBounds; 163 fRunHead = src.fRunHead; 164 if (this->isComplex()) { 165 sk_atomic_inc(&fRunHead->fRefCnt); 166 } 167 } 168 return fRunHead != SkRegion_gEmptyRunHeadPtr; 169 } 170 171 bool SkRegion::op(const SkIRect& rect, const SkRegion& rgn, Op op) { 172 SkRegion tmp(rect); 173 174 return this->op(tmp, rgn, op); 175 } 176 177 bool SkRegion::op(const SkRegion& rgn, const SkIRect& rect, Op op) { 178 SkRegion tmp(rect); 179 180 return this->op(rgn, tmp, op); 181 } 182 183 /////////////////////////////////////////////////////////////////////////////// 184 185 #ifdef SK_BUILD_FOR_ANDROID 186 char* SkRegion::toString() { 187 Iterator iter(*this); 188 int count = 0; 189 while (!iter.done()) { 190 count++; 191 iter.next(); 192 } 193 // 4 ints, up to 10 digits each plus sign, 3 commas, '(', ')', SkRegion() and '\0' 194 const int max = (count*((11*4)+5))+11+1; 195 char* result = (char*)malloc(max); 196 if (result == NULL) { 197 return NULL; 198 } 199 count = sprintf(result, "SkRegion("); 200 iter.reset(*this); 201 while (!iter.done()) { 202 const SkIRect& r = iter.rect(); 203 count += sprintf(result+count, "(%d,%d,%d,%d)", r.fLeft, r.fTop, r.fRight, r.fBottom); 204 iter.next(); 205 } 206 count += sprintf(result+count, ")"); 207 return result; 208 } 209 #endif 210 211 /////////////////////////////////////////////////////////////////////////////// 212 213 int SkRegion::count_runtype_values(int* itop, int* ibot) const { 214 if (this == NULL) { 215 *itop = SK_MinS32; 216 *ibot = SK_MaxS32; 217 return 0; 218 } 219 220 int maxT; 221 222 if (this->isRect()) { 223 maxT = 2; 224 } else { 225 SkASSERT(this->isComplex()); 226 maxT = fRunHead->getIntervalCount() * 2; 227 } 228 *itop = fBounds.fTop; 229 *ibot = fBounds.fBottom; 230 return maxT; 231 } 232 233 static bool isRunCountEmpty(int count) { 234 return count <= 2; 235 } 236 237 bool SkRegion::setRuns(RunType runs[], int count) { 238 SkDEBUGCODE(this->validate();) 239 SkASSERT(count > 0); 240 241 if (isRunCountEmpty(count)) { 242 // SkDEBUGF(("setRuns: empty\n")); 243 assert_sentinel(runs[count-1], true); 244 return this->setEmpty(); 245 } 246 247 // trim off any empty spans from the top and bottom 248 // weird I should need this, perhaps op() could be smarter... 249 if (count > kRectRegionRuns) { 250 RunType* stop = runs + count; 251 assert_sentinel(runs[0], false); // top 252 assert_sentinel(runs[1], false); // bottom 253 // runs[2] is uncomputed intervalCount 254 255 if (runs[3] == SkRegion::kRunTypeSentinel) { // should be first left... 256 runs += 3; // skip empty initial span 257 runs[0] = runs[-2]; // set new top to prev bottom 258 assert_sentinel(runs[1], false); // bot: a sentinal would mean two in a row 259 assert_sentinel(runs[2], false); // intervalcount 260 assert_sentinel(runs[3], false); // left 261 assert_sentinel(runs[4], false); // right 262 } 263 264 assert_sentinel(stop[-1], true); 265 assert_sentinel(stop[-2], true); 266 267 // now check for a trailing empty span 268 if (stop[-5] == SkRegion::kRunTypeSentinel) { // eek, stop[-4] was a bottom with no x-runs 269 stop[-4] = SkRegion::kRunTypeSentinel; // kill empty last span 270 stop -= 3; 271 assert_sentinel(stop[-1], true); // last y-sentinel 272 assert_sentinel(stop[-2], true); // last x-sentinel 273 assert_sentinel(stop[-3], false); // last right 274 assert_sentinel(stop[-4], false); // last left 275 assert_sentinel(stop[-5], false); // last interval-count 276 assert_sentinel(stop[-6], false); // last bottom 277 } 278 count = (int)(stop - runs); 279 } 280 281 SkASSERT(count >= kRectRegionRuns); 282 283 if (SkRegion::RunsAreARect(runs, count, &fBounds)) { 284 return this->setRect(fBounds); 285 } 286 287 // if we get here, we need to become a complex region 288 289 if (!this->isComplex() || fRunHead->fRunCount != count) { 290 this->freeRuns(); 291 this->allocateRuns(count); 292 } 293 294 // must call this before we can write directly into runs() 295 // in case we are sharing the buffer with another region (copy on write) 296 fRunHead = fRunHead->ensureWritable(); 297 memcpy(fRunHead->writable_runs(), runs, count * sizeof(RunType)); 298 fRunHead->computeRunBounds(&fBounds); 299 300 SkDEBUGCODE(this->validate();) 301 302 return true; 303 } 304 305 void SkRegion::BuildRectRuns(const SkIRect& bounds, 306 RunType runs[kRectRegionRuns]) { 307 runs[0] = bounds.fTop; 308 runs[1] = bounds.fBottom; 309 runs[2] = 1; // 1 interval for this scanline 310 runs[3] = bounds.fLeft; 311 runs[4] = bounds.fRight; 312 runs[5] = kRunTypeSentinel; 313 runs[6] = kRunTypeSentinel; 314 } 315 316 bool SkRegion::contains(int32_t x, int32_t y) const { 317 SkDEBUGCODE(this->validate();) 318 319 if (!fBounds.contains(x, y)) { 320 return false; 321 } 322 if (this->isRect()) { 323 return true; 324 } 325 SkASSERT(this->isComplex()); 326 327 const RunType* runs = fRunHead->findScanline(y); 328 329 // Skip the Bottom and IntervalCount 330 runs += 2; 331 332 // Just walk this scanline, checking each interval. The X-sentinel will 333 // appear as a left-inteval (runs[0]) and should abort the search. 334 // 335 // We could do a bsearch, using interval-count (runs[1]), but need to time 336 // when that would be worthwhile. 337 // 338 for (;;) { 339 if (x < runs[0]) { 340 break; 341 } 342 if (x < runs[1]) { 343 return true; 344 } 345 runs += 2; 346 } 347 return false; 348 } 349 350 static SkRegion::RunType scanline_bottom(const SkRegion::RunType runs[]) { 351 return runs[0]; 352 } 353 354 static const SkRegion::RunType* scanline_next(const SkRegion::RunType runs[]) { 355 // skip [B N [L R]... S] 356 return runs + 2 + runs[1] * 2 + 1; 357 } 358 359 static bool scanline_contains(const SkRegion::RunType runs[], 360 SkRegion::RunType L, SkRegion::RunType R) { 361 runs += 2; // skip Bottom and IntervalCount 362 for (;;) { 363 if (L < runs[0]) { 364 break; 365 } 366 if (R <= runs[1]) { 367 return true; 368 } 369 runs += 2; 370 } 371 return false; 372 } 373 374 bool SkRegion::contains(const SkIRect& r) const { 375 SkDEBUGCODE(this->validate();) 376 377 if (!fBounds.contains(r)) { 378 return false; 379 } 380 if (this->isRect()) { 381 return true; 382 } 383 SkASSERT(this->isComplex()); 384 385 const RunType* scanline = fRunHead->findScanline(r.fTop); 386 for (;;) { 387 if (!scanline_contains(scanline, r.fLeft, r.fRight)) { 388 return false; 389 } 390 if (r.fBottom <= scanline_bottom(scanline)) { 391 break; 392 } 393 scanline = scanline_next(scanline); 394 } 395 return true; 396 } 397 398 bool SkRegion::contains(const SkRegion& rgn) const { 399 SkDEBUGCODE(this->validate();) 400 SkDEBUGCODE(rgn.validate();) 401 402 if (this->isEmpty() || rgn.isEmpty() || !fBounds.contains(rgn.fBounds)) { 403 return false; 404 } 405 if (this->isRect()) { 406 return true; 407 } 408 if (rgn.isRect()) { 409 return this->contains(rgn.getBounds()); 410 } 411 412 /* 413 * A contains B is equivalent to 414 * B - A == 0 415 */ 416 return !Oper(rgn, *this, kDifference_Op, NULL); 417 } 418 419 const SkRegion::RunType* SkRegion::getRuns(RunType tmpStorage[], 420 int* intervals) const { 421 SkASSERT(tmpStorage && intervals); 422 const RunType* runs = tmpStorage; 423 424 if (this->isEmpty()) { 425 tmpStorage[0] = kRunTypeSentinel; 426 *intervals = 0; 427 } else if (this->isRect()) { 428 BuildRectRuns(fBounds, tmpStorage); 429 *intervals = 1; 430 } else { 431 runs = fRunHead->readonly_runs(); 432 *intervals = fRunHead->getIntervalCount(); 433 } 434 return runs; 435 } 436 437 /////////////////////////////////////////////////////////////////////////////// 438 439 static bool scanline_intersects(const SkRegion::RunType runs[], 440 SkRegion::RunType L, SkRegion::RunType R) { 441 runs += 2; // skip Bottom and IntervalCount 442 for (;;) { 443 if (R <= runs[0]) { 444 break; 445 } 446 if (L < runs[1]) { 447 return true; 448 } 449 runs += 2; 450 } 451 return false; 452 } 453 454 bool SkRegion::intersects(const SkIRect& r) const { 455 SkDEBUGCODE(this->validate();) 456 457 if (this->isEmpty() || r.isEmpty()) { 458 return false; 459 } 460 461 SkIRect sect; 462 if (!sect.intersect(fBounds, r)) { 463 return false; 464 } 465 if (this->isRect()) { 466 return true; 467 } 468 SkASSERT(this->isComplex()); 469 470 const RunType* scanline = fRunHead->findScanline(sect.fTop); 471 for (;;) { 472 if (scanline_intersects(scanline, sect.fLeft, sect.fRight)) { 473 return true; 474 } 475 if (sect.fBottom <= scanline_bottom(scanline)) { 476 break; 477 } 478 scanline = scanline_next(scanline); 479 } 480 return false; 481 } 482 483 bool SkRegion::intersects(const SkRegion& rgn) const { 484 if (this->isEmpty() || rgn.isEmpty()) { 485 return false; 486 } 487 488 if (!SkIRect::Intersects(fBounds, rgn.fBounds)) { 489 return false; 490 } 491 492 bool weAreARect = this->isRect(); 493 bool theyAreARect = rgn.isRect(); 494 495 if (weAreARect && theyAreARect) { 496 return true; 497 } 498 if (weAreARect) { 499 return rgn.intersects(this->getBounds()); 500 } 501 if (theyAreARect) { 502 return this->intersects(rgn.getBounds()); 503 } 504 505 // both of us are complex 506 return Oper(*this, rgn, kIntersect_Op, NULL); 507 } 508 509 /////////////////////////////////////////////////////////////////////////////// 510 511 bool SkRegion::operator==(const SkRegion& b) const { 512 SkDEBUGCODE(validate();) 513 SkDEBUGCODE(b.validate();) 514 515 if (this == &b) { 516 return true; 517 } 518 if (fBounds != b.fBounds) { 519 return false; 520 } 521 522 const SkRegion::RunHead* ah = fRunHead; 523 const SkRegion::RunHead* bh = b.fRunHead; 524 525 // this catches empties and rects being equal 526 if (ah == bh) { 527 return true; 528 } 529 // now we insist that both are complex (but different ptrs) 530 if (!this->isComplex() || !b.isComplex()) { 531 return false; 532 } 533 return ah->fRunCount == bh->fRunCount && 534 !memcmp(ah->readonly_runs(), bh->readonly_runs(), 535 ah->fRunCount * sizeof(SkRegion::RunType)); 536 } 537 538 void SkRegion::translate(int dx, int dy, SkRegion* dst) const { 539 SkDEBUGCODE(this->validate();) 540 541 if (NULL == dst) { 542 return; 543 } 544 if (this->isEmpty()) { 545 dst->setEmpty(); 546 } else if (this->isRect()) { 547 dst->setRect(fBounds.fLeft + dx, fBounds.fTop + dy, 548 fBounds.fRight + dx, fBounds.fBottom + dy); 549 } else { 550 if (this == dst) { 551 dst->fRunHead = dst->fRunHead->ensureWritable(); 552 } else { 553 SkRegion tmp; 554 tmp.allocateRuns(*fRunHead); 555 tmp.fBounds = fBounds; 556 dst->swap(tmp); 557 } 558 559 dst->fBounds.offset(dx, dy); 560 561 const RunType* sruns = fRunHead->readonly_runs(); 562 RunType* druns = dst->fRunHead->writable_runs(); 563 564 *druns++ = (SkRegion::RunType)(*sruns++ + dy); // top 565 for (;;) { 566 int bottom = *sruns++; 567 if (bottom == kRunTypeSentinel) { 568 break; 569 } 570 *druns++ = (SkRegion::RunType)(bottom + dy); // bottom; 571 *druns++ = *sruns++; // copy intervalCount; 572 for (;;) { 573 int x = *sruns++; 574 if (x == kRunTypeSentinel) { 575 break; 576 } 577 *druns++ = (SkRegion::RunType)(x + dx); 578 *druns++ = (SkRegion::RunType)(*sruns++ + dx); 579 } 580 *druns++ = kRunTypeSentinel; // x sentinel 581 } 582 *druns++ = kRunTypeSentinel; // y sentinel 583 584 SkASSERT(sruns - fRunHead->readonly_runs() == fRunHead->fRunCount); 585 SkASSERT(druns - dst->fRunHead->readonly_runs() == dst->fRunHead->fRunCount); 586 } 587 588 SkDEBUGCODE(this->validate();) 589 } 590 591 /////////////////////////////////////////////////////////////////////////////// 592 593 bool SkRegion::setRects(const SkIRect rects[], int count) { 594 if (0 == count) { 595 this->setEmpty(); 596 } else { 597 this->setRect(rects[0]); 598 for (int i = 1; i < count; i++) { 599 this->op(rects[i], kUnion_Op); 600 } 601 } 602 return !this->isEmpty(); 603 } 604 605 /////////////////////////////////////////////////////////////////////////////// 606 607 #if defined _WIN32 && _MSC_VER >= 1300 // disable warning : local variable used without having been initialized 608 #pragma warning ( push ) 609 #pragma warning ( disable : 4701 ) 610 #endif 611 612 #ifdef SK_DEBUG 613 static void assert_valid_pair(int left, int rite) 614 { 615 SkASSERT(left == SkRegion::kRunTypeSentinel || left < rite); 616 } 617 #else 618 #define assert_valid_pair(left, rite) 619 #endif 620 621 struct spanRec { 622 const SkRegion::RunType* fA_runs; 623 const SkRegion::RunType* fB_runs; 624 int fA_left, fA_rite, fB_left, fB_rite; 625 int fLeft, fRite, fInside; 626 627 void init(const SkRegion::RunType a_runs[], 628 const SkRegion::RunType b_runs[]) { 629 fA_left = *a_runs++; 630 fA_rite = *a_runs++; 631 fB_left = *b_runs++; 632 fB_rite = *b_runs++; 633 634 fA_runs = a_runs; 635 fB_runs = b_runs; 636 } 637 638 bool done() const { 639 SkASSERT(fA_left <= SkRegion::kRunTypeSentinel); 640 SkASSERT(fB_left <= SkRegion::kRunTypeSentinel); 641 return fA_left == SkRegion::kRunTypeSentinel && 642 fB_left == SkRegion::kRunTypeSentinel; 643 } 644 645 void next() { 646 assert_valid_pair(fA_left, fA_rite); 647 assert_valid_pair(fB_left, fB_rite); 648 649 int inside, left, rite SK_INIT_TO_AVOID_WARNING; 650 bool a_flush = false; 651 bool b_flush = false; 652 653 int a_left = fA_left; 654 int a_rite = fA_rite; 655 int b_left = fB_left; 656 int b_rite = fB_rite; 657 658 if (a_left < b_left) { 659 inside = 1; 660 left = a_left; 661 if (a_rite <= b_left) { // [...] <...> 662 rite = a_rite; 663 a_flush = true; 664 } else { // [...<..]...> or [...<...>...] 665 rite = a_left = b_left; 666 } 667 } else if (b_left < a_left) { 668 inside = 2; 669 left = b_left; 670 if (b_rite <= a_left) { // [...] <...> 671 rite = b_rite; 672 b_flush = true; 673 } else { // [...<..]...> or [...<...>...] 674 rite = b_left = a_left; 675 } 676 } else { // a_left == b_left 677 inside = 3; 678 left = a_left; // or b_left 679 if (a_rite <= b_rite) { 680 rite = b_left = a_rite; 681 a_flush = true; 682 } 683 if (b_rite <= a_rite) { 684 rite = a_left = b_rite; 685 b_flush = true; 686 } 687 } 688 689 if (a_flush) { 690 a_left = *fA_runs++; 691 a_rite = *fA_runs++; 692 } 693 if (b_flush) { 694 b_left = *fB_runs++; 695 b_rite = *fB_runs++; 696 } 697 698 SkASSERT(left <= rite); 699 700 // now update our state 701 fA_left = a_left; 702 fA_rite = a_rite; 703 fB_left = b_left; 704 fB_rite = b_rite; 705 706 fLeft = left; 707 fRite = rite; 708 fInside = inside; 709 } 710 }; 711 712 static SkRegion::RunType* operate_on_span(const SkRegion::RunType a_runs[], 713 const SkRegion::RunType b_runs[], 714 SkRegion::RunType dst[], 715 int min, int max) { 716 spanRec rec; 717 bool firstInterval = true; 718 719 rec.init(a_runs, b_runs); 720 721 while (!rec.done()) { 722 rec.next(); 723 724 int left = rec.fLeft; 725 int rite = rec.fRite; 726 727 // add left,rite to our dst buffer (checking for coincidence 728 if ((unsigned)(rec.fInside - min) <= (unsigned)(max - min) && 729 left < rite) { // skip if equal 730 if (firstInterval || dst[-1] < left) { 731 *dst++ = (SkRegion::RunType)(left); 732 *dst++ = (SkRegion::RunType)(rite); 733 firstInterval = false; 734 } else { 735 // update the right edge 736 dst[-1] = (SkRegion::RunType)(rite); 737 } 738 } 739 } 740 741 *dst++ = SkRegion::kRunTypeSentinel; 742 return dst; 743 } 744 745 #if defined _WIN32 && _MSC_VER >= 1300 746 #pragma warning ( pop ) 747 #endif 748 749 static const struct { 750 uint8_t fMin; 751 uint8_t fMax; 752 } gOpMinMax[] = { 753 { 1, 1 }, // Difference 754 { 3, 3 }, // Intersection 755 { 1, 3 }, // Union 756 { 1, 2 } // XOR 757 }; 758 759 class RgnOper { 760 public: 761 RgnOper(int top, SkRegion::RunType dst[], SkRegion::Op op) { 762 // need to ensure that the op enum lines up with our minmax array 763 SkASSERT(SkRegion::kDifference_Op == 0); 764 SkASSERT(SkRegion::kIntersect_Op == 1); 765 SkASSERT(SkRegion::kUnion_Op == 2); 766 SkASSERT(SkRegion::kXOR_Op == 3); 767 SkASSERT((unsigned)op <= 3); 768 769 fStartDst = dst; 770 fPrevDst = dst + 1; 771 fPrevLen = 0; // will never match a length from operate_on_span 772 fTop = (SkRegion::RunType)(top); // just a first guess, we might update this 773 774 fMin = gOpMinMax[op].fMin; 775 fMax = gOpMinMax[op].fMax; 776 } 777 778 void addSpan(int bottom, const SkRegion::RunType a_runs[], 779 const SkRegion::RunType b_runs[]) { 780 // skip X values and slots for the next Y+intervalCount 781 SkRegion::RunType* start = fPrevDst + fPrevLen + 2; 782 // start points to beginning of dst interval 783 SkRegion::RunType* stop = operate_on_span(a_runs, b_runs, start, fMin, fMax); 784 size_t len = stop - start; 785 SkASSERT(len >= 1 && (len & 1) == 1); 786 SkASSERT(SkRegion::kRunTypeSentinel == stop[-1]); 787 788 if (fPrevLen == len && 789 (1 == len || !memcmp(fPrevDst, start, 790 (len - 1) * sizeof(SkRegion::RunType)))) { 791 // update Y value 792 fPrevDst[-2] = (SkRegion::RunType)(bottom); 793 } else { // accept the new span 794 if (len == 1 && fPrevLen == 0) { 795 fTop = (SkRegion::RunType)(bottom); // just update our bottom 796 } else { 797 start[-2] = (SkRegion::RunType)(bottom); 798 start[-1] = len >> 1; 799 fPrevDst = start; 800 fPrevLen = len; 801 } 802 } 803 } 804 805 int flush() { 806 fStartDst[0] = fTop; 807 fPrevDst[fPrevLen] = SkRegion::kRunTypeSentinel; 808 return (int)(fPrevDst - fStartDst + fPrevLen + 1); 809 } 810 811 bool isEmpty() const { return 0 == fPrevLen; } 812 813 uint8_t fMin, fMax; 814 815 private: 816 SkRegion::RunType* fStartDst; 817 SkRegion::RunType* fPrevDst; 818 size_t fPrevLen; 819 SkRegion::RunType fTop; 820 }; 821 822 // want a unique value to signal that we exited due to quickExit 823 #define QUICK_EXIT_TRUE_COUNT (-1) 824 825 static int operate(const SkRegion::RunType a_runs[], 826 const SkRegion::RunType b_runs[], 827 SkRegion::RunType dst[], 828 SkRegion::Op op, 829 bool quickExit) { 830 const SkRegion::RunType gEmptyScanline[] = { 831 0, // dummy bottom value 832 0, // zero intervals 833 SkRegion::kRunTypeSentinel, 834 // just need a 2nd value, since spanRec.init() reads 2 values, even 835 // though if the first value is the sentinel, it ignores the 2nd value. 836 // w/o the 2nd value here, we might read uninitialized memory. 837 // This happens when we are using gSentinel, which is pointing at 838 // our sentinel value. 839 0 840 }; 841 const SkRegion::RunType* const gSentinel = &gEmptyScanline[2]; 842 843 int a_top = *a_runs++; 844 int a_bot = *a_runs++; 845 int b_top = *b_runs++; 846 int b_bot = *b_runs++; 847 848 a_runs += 1; // skip the intervalCount; 849 b_runs += 1; // skip the intervalCount; 850 851 // Now a_runs and b_runs to their intervals (or sentinel) 852 853 assert_sentinel(a_top, false); 854 assert_sentinel(a_bot, false); 855 assert_sentinel(b_top, false); 856 assert_sentinel(b_bot, false); 857 858 RgnOper oper(SkMin32(a_top, b_top), dst, op); 859 860 int prevBot = SkRegion::kRunTypeSentinel; // so we fail the first test 861 862 while (a_bot < SkRegion::kRunTypeSentinel || 863 b_bot < SkRegion::kRunTypeSentinel) { 864 int top, bot SK_INIT_TO_AVOID_WARNING; 865 const SkRegion::RunType* run0 = gSentinel; 866 const SkRegion::RunType* run1 = gSentinel; 867 bool a_flush = false; 868 bool b_flush = false; 869 870 if (a_top < b_top) { 871 top = a_top; 872 run0 = a_runs; 873 if (a_bot <= b_top) { // [...] <...> 874 bot = a_bot; 875 a_flush = true; 876 } else { // [...<..]...> or [...<...>...] 877 bot = a_top = b_top; 878 } 879 } else if (b_top < a_top) { 880 top = b_top; 881 run1 = b_runs; 882 if (b_bot <= a_top) { // [...] <...> 883 bot = b_bot; 884 b_flush = true; 885 } else { // [...<..]...> or [...<...>...] 886 bot = b_top = a_top; 887 } 888 } else { // a_top == b_top 889 top = a_top; // or b_top 890 run0 = a_runs; 891 run1 = b_runs; 892 if (a_bot <= b_bot) { 893 bot = b_top = a_bot; 894 a_flush = true; 895 } 896 if (b_bot <= a_bot) { 897 bot = a_top = b_bot; 898 b_flush = true; 899 } 900 } 901 902 if (top > prevBot) { 903 oper.addSpan(top, gSentinel, gSentinel); 904 } 905 oper.addSpan(bot, run0, run1); 906 907 if (quickExit && !oper.isEmpty()) { 908 return QUICK_EXIT_TRUE_COUNT; 909 } 910 911 if (a_flush) { 912 a_runs = skip_intervals(a_runs); 913 a_top = a_bot; 914 a_bot = *a_runs++; 915 a_runs += 1; // skip uninitialized intervalCount 916 if (a_bot == SkRegion::kRunTypeSentinel) { 917 a_top = a_bot; 918 } 919 } 920 if (b_flush) { 921 b_runs = skip_intervals(b_runs); 922 b_top = b_bot; 923 b_bot = *b_runs++; 924 b_runs += 1; // skip uninitialized intervalCount 925 if (b_bot == SkRegion::kRunTypeSentinel) { 926 b_top = b_bot; 927 } 928 } 929 930 prevBot = bot; 931 } 932 return oper.flush(); 933 } 934 935 /////////////////////////////////////////////////////////////////////////////// 936 937 /* Given count RunTypes in a complex region, return the worst case number of 938 logical intervals that represents (i.e. number of rects that would be 939 returned from the iterator). 940 941 We could just return count/2, since there must be at least 2 values per 942 interval, but we can first trim off the const overhead of the initial TOP 943 value, plus the final BOTTOM + 2 sentinels. 944 */ 945 #if 0 // UNUSED 946 static int count_to_intervals(int count) { 947 SkASSERT(count >= 6); // a single rect is 6 values 948 return (count - 4) >> 1; 949 } 950 #endif 951 952 /* Given a number of intervals, what is the worst case representation of that 953 many intervals? 954 955 Worst case (from a storage perspective), is a vertical stack of single 956 intervals: TOP + N * (BOTTOM INTERVALCOUNT LEFT RIGHT SENTINEL) + SENTINEL 957 */ 958 static int intervals_to_count(int intervals) { 959 return 1 + intervals * 5 + 1; 960 } 961 962 /* Given the intervalCounts of RunTypes in two regions, return the worst-case number 963 of RunTypes need to store the result after a region-op. 964 */ 965 static int compute_worst_case_count(int a_intervals, int b_intervals) { 966 // Our heuristic worst case is ai * (bi + 1) + bi * (ai + 1) 967 int intervals = 2 * a_intervals * b_intervals + a_intervals + b_intervals; 968 // convert back to number of RunType values 969 return intervals_to_count(intervals); 970 } 971 972 static bool setEmptyCheck(SkRegion* result) { 973 return result ? result->setEmpty() : false; 974 } 975 976 static bool setRectCheck(SkRegion* result, const SkIRect& rect) { 977 return result ? result->setRect(rect) : !rect.isEmpty(); 978 } 979 980 static bool setRegionCheck(SkRegion* result, const SkRegion& rgn) { 981 return result ? result->setRegion(rgn) : !rgn.isEmpty(); 982 } 983 984 bool SkRegion::Oper(const SkRegion& rgnaOrig, const SkRegion& rgnbOrig, Op op, 985 SkRegion* result) { 986 SkASSERT((unsigned)op < kOpCount); 987 988 if (kReplace_Op == op) { 989 return setRegionCheck(result, rgnbOrig); 990 } 991 992 // swith to using pointers, so we can swap them as needed 993 const SkRegion* rgna = &rgnaOrig; 994 const SkRegion* rgnb = &rgnbOrig; 995 // after this point, do not refer to rgnaOrig or rgnbOrig!!! 996 997 // collaps difference and reverse-difference into just difference 998 if (kReverseDifference_Op == op) { 999 SkTSwap<const SkRegion*>(rgna, rgnb); 1000 op = kDifference_Op; 1001 } 1002 1003 SkIRect bounds; 1004 bool a_empty = rgna->isEmpty(); 1005 bool b_empty = rgnb->isEmpty(); 1006 bool a_rect = rgna->isRect(); 1007 bool b_rect = rgnb->isRect(); 1008 1009 switch (op) { 1010 case kDifference_Op: 1011 if (a_empty) { 1012 return setEmptyCheck(result); 1013 } 1014 if (b_empty || !SkIRect::IntersectsNoEmptyCheck(rgna->fBounds, 1015 rgnb->fBounds)) { 1016 return setRegionCheck(result, *rgna); 1017 } 1018 if (b_rect && rgnb->fBounds.containsNoEmptyCheck(rgna->fBounds)) { 1019 return setEmptyCheck(result); 1020 } 1021 break; 1022 1023 case kIntersect_Op: 1024 if ((a_empty | b_empty) 1025 || !bounds.intersect(rgna->fBounds, rgnb->fBounds)) { 1026 return setEmptyCheck(result); 1027 } 1028 if (a_rect & b_rect) { 1029 return setRectCheck(result, bounds); 1030 } 1031 if (a_rect && rgna->fBounds.contains(rgnb->fBounds)) { 1032 return setRegionCheck(result, *rgnb); 1033 } 1034 if (b_rect && rgnb->fBounds.contains(rgna->fBounds)) { 1035 return setRegionCheck(result, *rgna); 1036 } 1037 break; 1038 1039 case kUnion_Op: 1040 if (a_empty) { 1041 return setRegionCheck(result, *rgnb); 1042 } 1043 if (b_empty) { 1044 return setRegionCheck(result, *rgna); 1045 } 1046 if (a_rect && rgna->fBounds.contains(rgnb->fBounds)) { 1047 return setRegionCheck(result, *rgna); 1048 } 1049 if (b_rect && rgnb->fBounds.contains(rgna->fBounds)) { 1050 return setRegionCheck(result, *rgnb); 1051 } 1052 break; 1053 1054 case kXOR_Op: 1055 if (a_empty) { 1056 return setRegionCheck(result, *rgnb); 1057 } 1058 if (b_empty) { 1059 return setRegionCheck(result, *rgna); 1060 } 1061 break; 1062 default: 1063 SkDEBUGFAIL("unknown region op"); 1064 return false; 1065 } 1066 1067 RunType tmpA[kRectRegionRuns]; 1068 RunType tmpB[kRectRegionRuns]; 1069 1070 int a_intervals, b_intervals; 1071 const RunType* a_runs = rgna->getRuns(tmpA, &a_intervals); 1072 const RunType* b_runs = rgnb->getRuns(tmpB, &b_intervals); 1073 1074 int dstCount = compute_worst_case_count(a_intervals, b_intervals); 1075 SkAutoSTMalloc<256, RunType> array(dstCount); 1076 1077 #ifdef SK_DEBUG 1078 // Sometimes helpful to seed everything with a known value when debugging 1079 // sk_memset32((uint32_t*)array.get(), 0x7FFFFFFF, dstCount); 1080 #endif 1081 1082 int count = operate(a_runs, b_runs, array.get(), op, NULL == result); 1083 SkASSERT(count <= dstCount); 1084 1085 if (result) { 1086 SkASSERT(count >= 0); 1087 return result->setRuns(array.get(), count); 1088 } else { 1089 return (QUICK_EXIT_TRUE_COUNT == count) || !isRunCountEmpty(count); 1090 } 1091 } 1092 1093 bool SkRegion::op(const SkRegion& rgna, const SkRegion& rgnb, Op op) { 1094 SkDEBUGCODE(this->validate();) 1095 return SkRegion::Oper(rgna, rgnb, op, this); 1096 } 1097 1098 /////////////////////////////////////////////////////////////////////////////// 1099 1100 #include "SkBuffer.h" 1101 1102 uint32_t SkRegion::writeToMemory(void* storage) const { 1103 if (NULL == storage) { 1104 uint32_t size = sizeof(int32_t); // -1 (empty), 0 (rect), runCount 1105 if (!this->isEmpty()) { 1106 size += sizeof(fBounds); 1107 if (this->isComplex()) { 1108 size += 2 * sizeof(int32_t); // ySpanCount + intervalCount 1109 size += fRunHead->fRunCount * sizeof(RunType); 1110 } 1111 } 1112 return size; 1113 } 1114 1115 SkWBuffer buffer(storage); 1116 1117 if (this->isEmpty()) { 1118 buffer.write32(-1); 1119 } else { 1120 bool isRect = this->isRect(); 1121 1122 buffer.write32(isRect ? 0 : fRunHead->fRunCount); 1123 buffer.write(&fBounds, sizeof(fBounds)); 1124 1125 if (!isRect) { 1126 buffer.write32(fRunHead->getYSpanCount()); 1127 buffer.write32(fRunHead->getIntervalCount()); 1128 buffer.write(fRunHead->readonly_runs(), 1129 fRunHead->fRunCount * sizeof(RunType)); 1130 } 1131 } 1132 return buffer.pos(); 1133 } 1134 1135 uint32_t SkRegion::readFromMemory(const void* storage) { 1136 SkRBuffer buffer(storage); 1137 SkRegion tmp; 1138 int32_t count; 1139 1140 count = buffer.readS32(); 1141 if (count >= 0) { 1142 buffer.read(&tmp.fBounds, sizeof(tmp.fBounds)); 1143 if (count == 0) { 1144 tmp.fRunHead = SkRegion_gRectRunHeadPtr; 1145 } else { 1146 int32_t ySpanCount = buffer.readS32(); 1147 int32_t intervalCount = buffer.readS32(); 1148 tmp.allocateRuns(count, ySpanCount, intervalCount); 1149 buffer.read(tmp.fRunHead->writable_runs(), count * sizeof(RunType)); 1150 } 1151 } 1152 this->swap(tmp); 1153 return buffer.pos(); 1154 } 1155 1156 /////////////////////////////////////////////////////////////////////////////// 1157 1158 const SkRegion& SkRegion::GetEmptyRegion() { 1159 static SkRegion gEmpty; 1160 return gEmpty; 1161 } 1162 1163 /////////////////////////////////////////////////////////////////////////////// 1164 1165 #ifdef SK_DEBUG 1166 1167 // Starts with first X-interval, and returns a ptr to the X-sentinel 1168 static const SkRegion::RunType* skip_intervals_slow(const SkRegion::RunType runs[]) { 1169 // want to track that our intevals are all disjoint, such that 1170 // prev-right < next-left. We rely on this optimization in places such as 1171 // contains(). 1172 // 1173 SkRegion::RunType prevR = -SkRegion::kRunTypeSentinel; 1174 1175 while (runs[0] < SkRegion::kRunTypeSentinel) { 1176 SkASSERT(prevR < runs[0]); 1177 SkASSERT(runs[0] < runs[1]); 1178 SkASSERT(runs[1] < SkRegion::kRunTypeSentinel); 1179 prevR = runs[1]; 1180 runs += 2; 1181 } 1182 return runs; 1183 } 1184 1185 static void compute_bounds(const SkRegion::RunType runs[], 1186 SkIRect* bounds, int* ySpanCountPtr, 1187 int* intervalCountPtr) { 1188 assert_sentinel(runs[0], false); // top 1189 1190 int left = SK_MaxS32; 1191 int rite = SK_MinS32; 1192 int bot; 1193 int ySpanCount = 0; 1194 int intervalCount = 0; 1195 1196 bounds->fTop = *runs++; 1197 do { 1198 bot = *runs++; 1199 SkASSERT(SkRegion::kRunTypeSentinel > bot); 1200 1201 ySpanCount += 1; 1202 1203 runs += 1; // skip intervalCount for now 1204 if (*runs < SkRegion::kRunTypeSentinel) { 1205 if (left > *runs) { 1206 left = *runs; 1207 } 1208 1209 const SkRegion::RunType* prev = runs; 1210 runs = skip_intervals_slow(runs); 1211 int intervals = (runs - prev) >> 1; 1212 SkASSERT(prev[-1] == intervals); 1213 intervalCount += intervals; 1214 1215 if (rite < runs[-1]) { 1216 rite = runs[-1]; 1217 } 1218 } else { 1219 SkASSERT(0 == runs[-1]); // no intervals 1220 } 1221 SkASSERT(SkRegion::kRunTypeSentinel == *runs); 1222 runs += 1; 1223 } while (SkRegion::kRunTypeSentinel != *runs); 1224 1225 bounds->fLeft = left; 1226 bounds->fRight = rite; 1227 bounds->fBottom = bot; 1228 *ySpanCountPtr = ySpanCount; 1229 *intervalCountPtr = intervalCount; 1230 } 1231 1232 void SkRegion::validate() const { 1233 if (this->isEmpty()) { 1234 // check for explicit empty (the zero rect), so we can compare rects to know when 1235 // two regions are equal (i.e. emptyRectA == emptyRectB) 1236 // this is stricter than just asserting fBounds.isEmpty() 1237 SkASSERT(fBounds.fLeft == 0 && fBounds.fTop == 0 && fBounds.fRight == 0 && fBounds.fBottom == 0); 1238 } else { 1239 SkASSERT(!fBounds.isEmpty()); 1240 if (!this->isRect()) { 1241 SkASSERT(fRunHead->fRefCnt >= 1); 1242 SkASSERT(fRunHead->fRunCount > kRectRegionRuns); 1243 1244 const RunType* run = fRunHead->readonly_runs(); 1245 1246 // check that our bounds match our runs 1247 { 1248 SkIRect bounds; 1249 int ySpanCount, intervalCount; 1250 compute_bounds(run, &bounds, &ySpanCount, &intervalCount); 1251 1252 SkASSERT(bounds == fBounds); 1253 SkASSERT(ySpanCount > 0); 1254 SkASSERT(fRunHead->getYSpanCount() == ySpanCount); 1255 // SkASSERT(intervalCount > 1); 1256 SkASSERT(fRunHead->getIntervalCount() == intervalCount); 1257 } 1258 } 1259 } 1260 } 1261 1262 void SkRegion::dump() const { 1263 if (this->isEmpty()) { 1264 SkDebugf(" rgn: empty\n"); 1265 } else { 1266 SkDebugf(" rgn: [%d %d %d %d]", fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom); 1267 if (this->isComplex()) { 1268 const RunType* runs = fRunHead->readonly_runs(); 1269 for (int i = 0; i < fRunHead->fRunCount; i++) 1270 SkDebugf(" %d", runs[i]); 1271 } 1272 SkDebugf("\n"); 1273 } 1274 } 1275 1276 #endif 1277 1278 /////////////////////////////////////////////////////////////////////////////// 1279 1280 SkRegion::Iterator::Iterator(const SkRegion& rgn) { 1281 this->reset(rgn); 1282 } 1283 1284 bool SkRegion::Iterator::rewind() { 1285 if (fRgn) { 1286 this->reset(*fRgn); 1287 return true; 1288 } 1289 return false; 1290 } 1291 1292 void SkRegion::Iterator::reset(const SkRegion& rgn) { 1293 fRgn = &rgn; 1294 if (rgn.isEmpty()) { 1295 fDone = true; 1296 } else { 1297 fDone = false; 1298 if (rgn.isRect()) { 1299 fRect = rgn.fBounds; 1300 fRuns = NULL; 1301 } else { 1302 fRuns = rgn.fRunHead->readonly_runs(); 1303 fRect.set(fRuns[3], fRuns[0], fRuns[4], fRuns[1]); 1304 fRuns += 5; 1305 // Now fRuns points to the 2nd interval (or x-sentinel) 1306 } 1307 } 1308 } 1309 1310 void SkRegion::Iterator::next() { 1311 if (fDone) { 1312 return; 1313 } 1314 1315 if (fRuns == NULL) { // rect case 1316 fDone = true; 1317 return; 1318 } 1319 1320 const RunType* runs = fRuns; 1321 1322 if (runs[0] < kRunTypeSentinel) { // valid X value 1323 fRect.fLeft = runs[0]; 1324 fRect.fRight = runs[1]; 1325 runs += 2; 1326 } else { // we're at the end of a line 1327 runs += 1; 1328 if (runs[0] < kRunTypeSentinel) { // valid Y value 1329 int intervals = runs[1]; 1330 if (0 == intervals) { // empty line 1331 fRect.fTop = runs[0]; 1332 runs += 3; 1333 } else { 1334 fRect.fTop = fRect.fBottom; 1335 } 1336 1337 fRect.fBottom = runs[0]; 1338 assert_sentinel(runs[2], false); 1339 assert_sentinel(runs[3], false); 1340 fRect.fLeft = runs[2]; 1341 fRect.fRight = runs[3]; 1342 runs += 4; 1343 } else { // end of rgn 1344 fDone = true; 1345 } 1346 } 1347 fRuns = runs; 1348 } 1349 1350 SkRegion::Cliperator::Cliperator(const SkRegion& rgn, const SkIRect& clip) 1351 : fIter(rgn), fClip(clip), fDone(true) { 1352 const SkIRect& r = fIter.rect(); 1353 1354 while (!fIter.done()) { 1355 if (r.fTop >= clip.fBottom) { 1356 break; 1357 } 1358 if (fRect.intersect(clip, r)) { 1359 fDone = false; 1360 break; 1361 } 1362 fIter.next(); 1363 } 1364 } 1365 1366 void SkRegion::Cliperator::next() { 1367 if (fDone) { 1368 return; 1369 } 1370 1371 const SkIRect& r = fIter.rect(); 1372 1373 fDone = true; 1374 fIter.next(); 1375 while (!fIter.done()) { 1376 if (r.fTop >= fClip.fBottom) { 1377 break; 1378 } 1379 if (fRect.intersect(fClip, r)) { 1380 fDone = false; 1381 break; 1382 } 1383 fIter.next(); 1384 } 1385 } 1386 1387 /////////////////////////////////////////////////////////////////////////////// 1388 1389 SkRegion::Spanerator::Spanerator(const SkRegion& rgn, int y, int left, 1390 int right) { 1391 SkDEBUGCODE(rgn.validate();) 1392 1393 const SkIRect& r = rgn.getBounds(); 1394 1395 fDone = true; 1396 if (!rgn.isEmpty() && y >= r.fTop && y < r.fBottom && 1397 right > r.fLeft && left < r.fRight) { 1398 if (rgn.isRect()) { 1399 if (left < r.fLeft) { 1400 left = r.fLeft; 1401 } 1402 if (right > r.fRight) { 1403 right = r.fRight; 1404 } 1405 fLeft = left; 1406 fRight = right; 1407 fRuns = NULL; // means we're a rect, not a rgn 1408 fDone = false; 1409 } else { 1410 const SkRegion::RunType* runs = rgn.fRunHead->findScanline(y); 1411 runs += 2; // skip Bottom and IntervalCount 1412 for (;;) { 1413 // runs[0..1] is to the right of the span, so we're done 1414 if (runs[0] >= right) { 1415 break; 1416 } 1417 // runs[0..1] is to the left of the span, so continue 1418 if (runs[1] <= left) { 1419 runs += 2; 1420 continue; 1421 } 1422 // runs[0..1] intersects the span 1423 fRuns = runs; 1424 fLeft = left; 1425 fRight = right; 1426 fDone = false; 1427 break; 1428 } 1429 } 1430 } 1431 } 1432 1433 bool SkRegion::Spanerator::next(int* left, int* right) { 1434 if (fDone) { 1435 return false; 1436 } 1437 1438 if (fRuns == NULL) { // we're a rect 1439 fDone = true; // ok, now we're done 1440 if (left) { 1441 *left = fLeft; 1442 } 1443 if (right) { 1444 *right = fRight; 1445 } 1446 return true; // this interval is legal 1447 } 1448 1449 const SkRegion::RunType* runs = fRuns; 1450 1451 if (runs[0] >= fRight) { 1452 fDone = true; 1453 return false; 1454 } 1455 1456 SkASSERT(runs[1] > fLeft); 1457 1458 if (left) { 1459 *left = SkMax32(fLeft, runs[0]); 1460 } 1461 if (right) { 1462 *right = SkMin32(fRight, runs[1]); 1463 } 1464 fRuns = runs + 2; 1465 return true; 1466 } 1467 1468 /////////////////////////////////////////////////////////////////////////////// 1469 1470 #ifdef SK_DEBUG 1471 1472 bool SkRegion::debugSetRuns(const RunType runs[], int count) { 1473 // we need to make a copy, since the real method may modify the array, and 1474 // so it cannot be const. 1475 1476 SkAutoTArray<RunType> storage(count); 1477 memcpy(storage.get(), runs, count * sizeof(RunType)); 1478 return this->setRuns(storage.get(), count); 1479 } 1480 1481 #endif 1482