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