SkRegion.cpp revision 1026ccf1d2de57ae6e7d2f30ea92c245942121d3
1/* 2 * Copyright 2006 The Android Open Source Project 3 * 4 * Use of this source code is governed by a BSD-style license that can be 5 * found in the LICENSE file. 6 */ 7 8 9#include "SkAtomics.h" 10#include "SkRegionPriv.h" 11#include "SkTemplates.h" 12#include "SkUtils.h" 13 14/* Region Layout 15 * 16 * TOP 17 * 18 * [ Bottom, X-Intervals, [Left, Right]..., X-Sentinel ] 19 * ... 20 * 21 * Y-Sentinel 22 */ 23 24SkDEBUGCODE(int32_t gRgnAllocCounter;) 25 26///////////////////////////////////////////////////////////////////////////////////////////////// 27 28/* Pass in the beginning with the intervals. 29 * We back up 1 to read the interval-count. 30 * Return the beginning of the next scanline (i.e. the next Y-value) 31 */ 32static SkRegion::RunType* skip_intervals(const SkRegion::RunType runs[]) { 33 int intervals = runs[-1]; 34#ifdef SK_DEBUG 35 if (intervals > 0) { 36 SkASSERT(runs[0] < runs[1]); 37 SkASSERT(runs[1] < SkRegion::kRunTypeSentinel); 38 } else { 39 SkASSERT(0 == intervals); 40 SkASSERT(SkRegion::kRunTypeSentinel == runs[0]); 41 } 42#endif 43 runs += intervals * 2 + 1; 44 return const_cast<SkRegion::RunType*>(runs); 45} 46 47bool SkRegion::RunsAreARect(const SkRegion::RunType runs[], int count, 48 SkIRect* bounds) { 49 assert_sentinel(runs[0], false); // top 50 SkASSERT(count >= kRectRegionRuns); 51 52 if (count == kRectRegionRuns) { 53 assert_sentinel(runs[1], false); // bottom 54 SkASSERT(1 == runs[2]); 55 assert_sentinel(runs[3], false); // left 56 assert_sentinel(runs[4], false); // right 57 assert_sentinel(runs[5], true); 58 assert_sentinel(runs[6], true); 59 60 SkASSERT(runs[0] < runs[1]); // valid height 61 SkASSERT(runs[3] < runs[4]); // valid width 62 63 bounds->set(runs[3], runs[0], runs[4], runs[1]); 64 return true; 65 } 66 return false; 67} 68 69////////////////////////////////////////////////////////////////////////// 70 71SkRegion::SkRegion() { 72 fBounds.set(0, 0, 0, 0); 73 fRunHead = SkRegion_gEmptyRunHeadPtr; 74} 75 76SkRegion::SkRegion(const SkRegion& src) { 77 fRunHead = SkRegion_gEmptyRunHeadPtr; // just need a value that won't trigger sk_free(fRunHead) 78 this->setRegion(src); 79} 80 81SkRegion::SkRegion(const SkIRect& rect) { 82 fRunHead = SkRegion_gEmptyRunHeadPtr; // just need a value that won't trigger sk_free(fRunHead) 83 this->setRect(rect); 84} 85 86SkRegion::~SkRegion() { 87 this->freeRuns(); 88} 89 90void SkRegion::freeRuns() { 91 if (this->isComplex()) { 92 SkASSERT(fRunHead->fRefCnt >= 1); 93 if (sk_atomic_dec(&fRunHead->fRefCnt) == 1) { 94 //SkASSERT(gRgnAllocCounter > 0); 95 //SkDEBUGCODE(sk_atomic_dec(&gRgnAllocCounter)); 96 //SkDEBUGF(("************** gRgnAllocCounter::free %d\n", gRgnAllocCounter)); 97 sk_free(fRunHead); 98 } 99 } 100} 101 102void SkRegion::allocateRuns(int count, int ySpanCount, int intervalCount) { 103 fRunHead = RunHead::Alloc(count, ySpanCount, intervalCount); 104} 105 106void SkRegion::allocateRuns(int count) { 107 fRunHead = RunHead::Alloc(count); 108} 109 110void SkRegion::allocateRuns(const RunHead& head) { 111 fRunHead = RunHead::Alloc(head.fRunCount, 112 head.getYSpanCount(), 113 head.getIntervalCount()); 114} 115 116SkRegion& SkRegion::operator=(const SkRegion& src) { 117 (void)this->setRegion(src); 118 return *this; 119} 120 121void SkRegion::swap(SkRegion& other) { 122 SkTSwap<SkIRect>(fBounds, other.fBounds); 123 SkTSwap<RunHead*>(fRunHead, other.fRunHead); 124} 125 126int SkRegion::computeRegionComplexity() const { 127 if (this->isEmpty()) { 128 return 0; 129 } else if (this->isRect()) { 130 return 1; 131 } 132 return fRunHead->getIntervalCount(); 133} 134 135bool SkRegion::setEmpty() { 136 this->freeRuns(); 137 fBounds.set(0, 0, 0, 0); 138 fRunHead = SkRegion_gEmptyRunHeadPtr; 139 return false; 140} 141 142bool SkRegion::setRect(int32_t left, int32_t top, 143 int32_t right, int32_t bottom) { 144 if (left >= right || top >= bottom) { 145 return this->setEmpty(); 146 } 147 this->freeRuns(); 148 fBounds.set(left, top, right, bottom); 149 fRunHead = SkRegion_gRectRunHeadPtr; 150 return true; 151} 152 153bool SkRegion::setRect(const SkIRect& r) { 154 return this->setRect(r.fLeft, r.fTop, r.fRight, r.fBottom); 155} 156 157bool SkRegion::setRegion(const SkRegion& src) { 158 if (this != &src) { 159 this->freeRuns(); 160 161 fBounds = src.fBounds; 162 fRunHead = src.fRunHead; 163 if (this->isComplex()) { 164 sk_atomic_inc(&fRunHead->fRefCnt); 165 } 166 } 167 return fRunHead != SkRegion_gEmptyRunHeadPtr; 168} 169 170bool SkRegion::op(const SkIRect& rect, const SkRegion& rgn, Op op) { 171 SkRegion tmp(rect); 172 173 return this->op(tmp, rgn, op); 174} 175 176bool SkRegion::op(const SkRegion& rgn, const SkIRect& rect, Op op) { 177 SkRegion tmp(rect); 178 179 return this->op(rgn, tmp, op); 180} 181 182/////////////////////////////////////////////////////////////////////////////// 183 184#ifdef SK_BUILD_FOR_ANDROID 185#include <stdio.h> 186char* 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*)sk_malloc_throw(max); 196 if (result == nullptr) { 197 return nullptr; 198 } 199 count = snprintf(result, max, "SkRegion("); 200 iter.reset(*this); 201 while (!iter.done()) { 202 const SkIRect& r = iter.rect(); 203 count += snprintf(result+count, max - count, 204 "(%d,%d,%d,%d)", r.fLeft, r.fTop, r.fRight, r.fBottom); 205 iter.next(); 206 } 207 count += snprintf(result+count, max - count, ")"); 208 return result; 209} 210#endif 211 212/////////////////////////////////////////////////////////////////////////////// 213 214int 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 228static bool isRunCountEmpty(int count) { 229 return count <= 2; 230} 231 232bool 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 300void 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 311bool 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 345static SkRegion::RunType scanline_bottom(const SkRegion::RunType runs[]) { 346 return runs[0]; 347} 348 349static 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 354static 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 369bool 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 393bool 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, nullptr); 412} 413 414const 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 434static 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 449bool 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 478bool 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, nullptr); 502} 503 504/////////////////////////////////////////////////////////////////////////////// 505 506bool 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 533void SkRegion::translate(int dx, int dy, SkRegion* dst) const { 534 SkDEBUGCODE(this->validate();) 535 536 if (nullptr == 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 588bool 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 // 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 608static 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 616struct 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 707static 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 741#pragma warning ( pop ) 742#endif 743 744static 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 754class RgnOper { 755public: 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 810private: 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 820static 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 941static 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 */ 953static 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 */ 960static 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 967static bool setEmptyCheck(SkRegion* result) { 968 return result ? result->setEmpty() : false; 969} 970 971static bool setRectCheck(SkRegion* result, const SkIRect& rect) { 972 return result ? result->setRect(rect) : !rect.isEmpty(); 973} 974 975static bool setRegionCheck(SkRegion* result, const SkRegion& rgn) { 976 return result ? result->setRegion(rgn) : !rgn.isEmpty(); 977} 978 979bool 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, nullptr == 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 1088bool 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 1097size_t SkRegion::writeToMemory(void* storage) const { 1098 if (nullptr == 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 1130size_t SkRegion::readFromMemory(const void* storage, size_t length) { 1131 SkRBuffer 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 intervalCount > 1) { 1142 tmp.allocateRuns(count, ySpanCount, intervalCount); 1143 buffer.read(tmp.fRunHead->writable_runs(), count * sizeof(RunType)); 1144 } 1145 } 1146 } 1147 size_t sizeRead = 0; 1148 if (buffer.isValid()) { 1149 this->swap(tmp); 1150 sizeRead = buffer.pos(); 1151 } 1152 return sizeRead; 1153} 1154 1155/////////////////////////////////////////////////////////////////////////////// 1156 1157const SkRegion& SkRegion::GetEmptyRegion() { 1158 static SkRegion gEmpty; 1159 return gEmpty; 1160} 1161 1162/////////////////////////////////////////////////////////////////////////////// 1163 1164#ifdef SK_DEBUG 1165 1166// Starts with first X-interval, and returns a ptr to the X-sentinel 1167static const SkRegion::RunType* skip_intervals_slow(const SkRegion::RunType runs[]) { 1168 // want to track that our intevals are all disjoint, such that 1169 // prev-right < next-left. We rely on this optimization in places such as 1170 // contains(). 1171 // 1172 SkRegion::RunType prevR = -SkRegion::kRunTypeSentinel; 1173 1174 while (runs[0] < SkRegion::kRunTypeSentinel) { 1175 SkASSERT(prevR < runs[0]); 1176 SkASSERT(runs[0] < runs[1]); 1177 SkASSERT(runs[1] < SkRegion::kRunTypeSentinel); 1178 prevR = runs[1]; 1179 runs += 2; 1180 } 1181 return runs; 1182} 1183 1184static void compute_bounds(const SkRegion::RunType runs[], 1185 SkIRect* bounds, int* ySpanCountPtr, 1186 int* intervalCountPtr) { 1187 assert_sentinel(runs[0], false); // top 1188 1189 int left = SK_MaxS32; 1190 int rite = SK_MinS32; 1191 int bot; 1192 int ySpanCount = 0; 1193 int intervalCount = 0; 1194 1195 bounds->fTop = *runs++; 1196 do { 1197 bot = *runs++; 1198 SkASSERT(SkRegion::kRunTypeSentinel > bot); 1199 1200 ySpanCount += 1; 1201 1202 runs += 1; // skip intervalCount for now 1203 if (*runs < SkRegion::kRunTypeSentinel) { 1204 if (left > *runs) { 1205 left = *runs; 1206 } 1207 1208 const SkRegion::RunType* prev = runs; 1209 runs = skip_intervals_slow(runs); 1210 int intervals = SkToInt((runs - prev) >> 1); 1211 SkASSERT(prev[-1] == intervals); 1212 intervalCount += intervals; 1213 1214 if (rite < runs[-1]) { 1215 rite = runs[-1]; 1216 } 1217 } else { 1218 SkASSERT(0 == runs[-1]); // no intervals 1219 } 1220 SkASSERT(SkRegion::kRunTypeSentinel == *runs); 1221 runs += 1; 1222 } while (SkRegion::kRunTypeSentinel != *runs); 1223 1224 bounds->fLeft = left; 1225 bounds->fRight = rite; 1226 bounds->fBottom = bot; 1227 *ySpanCountPtr = ySpanCount; 1228 *intervalCountPtr = intervalCount; 1229} 1230 1231void SkRegion::validate() const { 1232 if (this->isEmpty()) { 1233 // check for explicit empty (the zero rect), so we can compare rects to know when 1234 // two regions are equal (i.e. emptyRectA == emptyRectB) 1235 // this is stricter than just asserting fBounds.isEmpty() 1236 SkASSERT(fBounds.fLeft == 0 && fBounds.fTop == 0 && fBounds.fRight == 0 && fBounds.fBottom == 0); 1237 } else { 1238 SkASSERT(!fBounds.isEmpty()); 1239 if (!this->isRect()) { 1240 SkASSERT(fRunHead->fRefCnt >= 1); 1241 SkASSERT(fRunHead->fRunCount > kRectRegionRuns); 1242 1243 const RunType* run = fRunHead->readonly_runs(); 1244 1245 // check that our bounds match our runs 1246 { 1247 SkIRect bounds; 1248 int ySpanCount, intervalCount; 1249 compute_bounds(run, &bounds, &ySpanCount, &intervalCount); 1250 1251 SkASSERT(bounds == fBounds); 1252 SkASSERT(ySpanCount > 0); 1253 SkASSERT(fRunHead->getYSpanCount() == ySpanCount); 1254 // SkASSERT(intervalCount > 1); 1255 SkASSERT(fRunHead->getIntervalCount() == intervalCount); 1256 } 1257 } 1258 } 1259} 1260 1261void SkRegion::dump() const { 1262 if (this->isEmpty()) { 1263 SkDebugf(" rgn: empty\n"); 1264 } else { 1265 SkDebugf(" rgn: [%d %d %d %d]", fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom); 1266 if (this->isComplex()) { 1267 const RunType* runs = fRunHead->readonly_runs(); 1268 for (int i = 0; i < fRunHead->fRunCount; i++) 1269 SkDebugf(" %d", runs[i]); 1270 } 1271 SkDebugf("\n"); 1272 } 1273} 1274 1275#endif 1276 1277/////////////////////////////////////////////////////////////////////////////// 1278 1279SkRegion::Iterator::Iterator(const SkRegion& rgn) { 1280 this->reset(rgn); 1281} 1282 1283bool SkRegion::Iterator::rewind() { 1284 if (fRgn) { 1285 this->reset(*fRgn); 1286 return true; 1287 } 1288 return false; 1289} 1290 1291void SkRegion::Iterator::reset(const SkRegion& rgn) { 1292 fRgn = &rgn; 1293 if (rgn.isEmpty()) { 1294 fDone = true; 1295 } else { 1296 fDone = false; 1297 if (rgn.isRect()) { 1298 fRect = rgn.fBounds; 1299 fRuns = nullptr; 1300 } else { 1301 fRuns = rgn.fRunHead->readonly_runs(); 1302 fRect.set(fRuns[3], fRuns[0], fRuns[4], fRuns[1]); 1303 fRuns += 5; 1304 // Now fRuns points to the 2nd interval (or x-sentinel) 1305 } 1306 } 1307} 1308 1309void SkRegion::Iterator::next() { 1310 if (fDone) { 1311 return; 1312 } 1313 1314 if (fRuns == nullptr) { // rect case 1315 fDone = true; 1316 return; 1317 } 1318 1319 const RunType* runs = fRuns; 1320 1321 if (runs[0] < kRunTypeSentinel) { // valid X value 1322 fRect.fLeft = runs[0]; 1323 fRect.fRight = runs[1]; 1324 runs += 2; 1325 } else { // we're at the end of a line 1326 runs += 1; 1327 if (runs[0] < kRunTypeSentinel) { // valid Y value 1328 int intervals = runs[1]; 1329 if (0 == intervals) { // empty line 1330 fRect.fTop = runs[0]; 1331 runs += 3; 1332 } else { 1333 fRect.fTop = fRect.fBottom; 1334 } 1335 1336 fRect.fBottom = runs[0]; 1337 assert_sentinel(runs[2], false); 1338 assert_sentinel(runs[3], false); 1339 fRect.fLeft = runs[2]; 1340 fRect.fRight = runs[3]; 1341 runs += 4; 1342 } else { // end of rgn 1343 fDone = true; 1344 } 1345 } 1346 fRuns = runs; 1347} 1348 1349SkRegion::Cliperator::Cliperator(const SkRegion& rgn, const SkIRect& clip) 1350 : fIter(rgn), fClip(clip), fDone(true) { 1351 const SkIRect& r = fIter.rect(); 1352 1353 while (!fIter.done()) { 1354 if (r.fTop >= clip.fBottom) { 1355 break; 1356 } 1357 if (fRect.intersect(clip, r)) { 1358 fDone = false; 1359 break; 1360 } 1361 fIter.next(); 1362 } 1363} 1364 1365void SkRegion::Cliperator::next() { 1366 if (fDone) { 1367 return; 1368 } 1369 1370 const SkIRect& r = fIter.rect(); 1371 1372 fDone = true; 1373 fIter.next(); 1374 while (!fIter.done()) { 1375 if (r.fTop >= fClip.fBottom) { 1376 break; 1377 } 1378 if (fRect.intersect(fClip, r)) { 1379 fDone = false; 1380 break; 1381 } 1382 fIter.next(); 1383 } 1384} 1385 1386/////////////////////////////////////////////////////////////////////////////// 1387 1388SkRegion::Spanerator::Spanerator(const SkRegion& rgn, int y, int left, 1389 int right) { 1390 SkDEBUGCODE(rgn.validate();) 1391 1392 const SkIRect& r = rgn.getBounds(); 1393 1394 fDone = true; 1395 if (!rgn.isEmpty() && y >= r.fTop && y < r.fBottom && 1396 right > r.fLeft && left < r.fRight) { 1397 if (rgn.isRect()) { 1398 if (left < r.fLeft) { 1399 left = r.fLeft; 1400 } 1401 if (right > r.fRight) { 1402 right = r.fRight; 1403 } 1404 fLeft = left; 1405 fRight = right; 1406 fRuns = nullptr; // means we're a rect, not a rgn 1407 fDone = false; 1408 } else { 1409 const SkRegion::RunType* runs = rgn.fRunHead->findScanline(y); 1410 runs += 2; // skip Bottom and IntervalCount 1411 for (;;) { 1412 // runs[0..1] is to the right of the span, so we're done 1413 if (runs[0] >= right) { 1414 break; 1415 } 1416 // runs[0..1] is to the left of the span, so continue 1417 if (runs[1] <= left) { 1418 runs += 2; 1419 continue; 1420 } 1421 // runs[0..1] intersects the span 1422 fRuns = runs; 1423 fLeft = left; 1424 fRight = right; 1425 fDone = false; 1426 break; 1427 } 1428 } 1429 } 1430} 1431 1432bool SkRegion::Spanerator::next(int* left, int* right) { 1433 if (fDone) { 1434 return false; 1435 } 1436 1437 if (fRuns == nullptr) { // we're a rect 1438 fDone = true; // ok, now we're done 1439 if (left) { 1440 *left = fLeft; 1441 } 1442 if (right) { 1443 *right = fRight; 1444 } 1445 return true; // this interval is legal 1446 } 1447 1448 const SkRegion::RunType* runs = fRuns; 1449 1450 if (runs[0] >= fRight) { 1451 fDone = true; 1452 return false; 1453 } 1454 1455 SkASSERT(runs[1] > fLeft); 1456 1457 if (left) { 1458 *left = SkMax32(fLeft, runs[0]); 1459 } 1460 if (right) { 1461 *right = SkMin32(fRight, runs[1]); 1462 } 1463 fRuns = runs + 2; 1464 return true; 1465} 1466 1467/////////////////////////////////////////////////////////////////////////////// 1468 1469#ifdef SK_DEBUG 1470 1471bool SkRegion::debugSetRuns(const RunType runs[], int count) { 1472 // we need to make a copy, since the real method may modify the array, and 1473 // so it cannot be const. 1474 1475 SkAutoTArray<RunType> storage(count); 1476 memcpy(storage.get(), runs, count * sizeof(RunType)); 1477 return this->setRuns(storage.get(), count); 1478} 1479 1480#endif 1481