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