SkRegion.cpp revision 12a23866fe18e800da1d361d000a359ea36696eb
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
1103uint32_t SkRegion::writeToMemory(void* storage) const {
1104    if (NULL == storage) {
1105        uint32_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
1136uint32_t SkRegion::readFromMemory(const void* storage) {
1137    SkRBuffer   buffer(storage);
1138    SkRegion    tmp;
1139    int32_t     count;
1140
1141    count = buffer.readS32();
1142    if (count >= 0) {
1143        buffer.read(&tmp.fBounds, sizeof(tmp.fBounds));
1144        if (count == 0) {
1145            tmp.fRunHead = SkRegion_gRectRunHeadPtr;
1146        } else {
1147            int32_t ySpanCount = buffer.readS32();
1148            int32_t intervalCount = buffer.readS32();
1149            tmp.allocateRuns(count, ySpanCount, intervalCount);
1150            buffer.read(tmp.fRunHead->writable_runs(), count * sizeof(RunType));
1151        }
1152    }
1153    this->swap(tmp);
1154    return buffer.pos();
1155}
1156
1157///////////////////////////////////////////////////////////////////////////////
1158
1159const SkRegion& SkRegion::GetEmptyRegion() {
1160    static SkRegion gEmpty;
1161    return gEmpty;
1162}
1163
1164///////////////////////////////////////////////////////////////////////////////
1165
1166#ifdef SK_DEBUG
1167
1168// Starts with first X-interval, and returns a ptr to the X-sentinel
1169static const SkRegion::RunType* skip_intervals_slow(const SkRegion::RunType runs[]) {
1170    // want to track that our intevals are all disjoint, such that
1171    // prev-right < next-left. We rely on this optimization in places such as
1172    // contains().
1173    //
1174    SkRegion::RunType prevR = -SkRegion::kRunTypeSentinel;
1175
1176    while (runs[0] < SkRegion::kRunTypeSentinel) {
1177        SkASSERT(prevR < runs[0]);
1178        SkASSERT(runs[0] < runs[1]);
1179        SkASSERT(runs[1] < SkRegion::kRunTypeSentinel);
1180        prevR = runs[1];
1181        runs += 2;
1182    }
1183    return runs;
1184}
1185
1186static void compute_bounds(const SkRegion::RunType runs[],
1187                           SkIRect* bounds, int* ySpanCountPtr,
1188                           int* intervalCountPtr) {
1189    assert_sentinel(runs[0], false);    // top
1190
1191    int left = SK_MaxS32;
1192    int rite = SK_MinS32;
1193    int bot;
1194    int ySpanCount = 0;
1195    int intervalCount = 0;
1196
1197    bounds->fTop = *runs++;
1198    do {
1199        bot = *runs++;
1200        SkASSERT(SkRegion::kRunTypeSentinel > bot);
1201
1202        ySpanCount += 1;
1203
1204        runs += 1;  // skip intervalCount for now
1205        if (*runs < SkRegion::kRunTypeSentinel) {
1206            if (left > *runs) {
1207                left = *runs;
1208            }
1209
1210            const SkRegion::RunType* prev = runs;
1211            runs = skip_intervals_slow(runs);
1212            int intervals = (runs - prev) >> 1;
1213            SkASSERT(prev[-1] == intervals);
1214            intervalCount += intervals;
1215
1216            if (rite < runs[-1]) {
1217                rite = runs[-1];
1218            }
1219        } else {
1220            SkASSERT(0 == runs[-1]);    // no intervals
1221        }
1222        SkASSERT(SkRegion::kRunTypeSentinel == *runs);
1223        runs += 1;
1224    } while (SkRegion::kRunTypeSentinel != *runs);
1225
1226    bounds->fLeft = left;
1227    bounds->fRight = rite;
1228    bounds->fBottom = bot;
1229    *ySpanCountPtr = ySpanCount;
1230    *intervalCountPtr = intervalCount;
1231}
1232
1233void SkRegion::validate() const {
1234    if (this->isEmpty()) {
1235        // check for explicit empty (the zero rect), so we can compare rects to know when
1236        // two regions are equal (i.e. emptyRectA == emptyRectB)
1237        // this is stricter than just asserting fBounds.isEmpty()
1238        SkASSERT(fBounds.fLeft == 0 && fBounds.fTop == 0 && fBounds.fRight == 0 && fBounds.fBottom == 0);
1239    } else {
1240        SkASSERT(!fBounds.isEmpty());
1241        if (!this->isRect()) {
1242            SkASSERT(fRunHead->fRefCnt >= 1);
1243            SkASSERT(fRunHead->fRunCount > kRectRegionRuns);
1244
1245            const RunType* run = fRunHead->readonly_runs();
1246
1247            // check that our bounds match our runs
1248            {
1249                SkIRect bounds;
1250                int ySpanCount, intervalCount;
1251                compute_bounds(run, &bounds, &ySpanCount, &intervalCount);
1252
1253                SkASSERT(bounds == fBounds);
1254                SkASSERT(ySpanCount > 0);
1255                SkASSERT(fRunHead->getYSpanCount() == ySpanCount);
1256           //     SkASSERT(intervalCount > 1);
1257                SkASSERT(fRunHead->getIntervalCount() == intervalCount);
1258            }
1259        }
1260    }
1261}
1262
1263void SkRegion::dump() const {
1264    if (this->isEmpty()) {
1265        SkDebugf("  rgn: empty\n");
1266    } else {
1267        SkDebugf("  rgn: [%d %d %d %d]", fBounds.fLeft, fBounds.fTop, fBounds.fRight, fBounds.fBottom);
1268        if (this->isComplex()) {
1269            const RunType* runs = fRunHead->readonly_runs();
1270            for (int i = 0; i < fRunHead->fRunCount; i++)
1271                SkDebugf(" %d", runs[i]);
1272        }
1273        SkDebugf("\n");
1274    }
1275}
1276
1277#endif
1278
1279///////////////////////////////////////////////////////////////////////////////
1280
1281SkRegion::Iterator::Iterator(const SkRegion& rgn) {
1282    this->reset(rgn);
1283}
1284
1285bool SkRegion::Iterator::rewind() {
1286    if (fRgn) {
1287        this->reset(*fRgn);
1288        return true;
1289    }
1290    return false;
1291}
1292
1293void SkRegion::Iterator::reset(const SkRegion& rgn) {
1294    fRgn = &rgn;
1295    if (rgn.isEmpty()) {
1296        fDone = true;
1297    } else {
1298        fDone = false;
1299        if (rgn.isRect()) {
1300            fRect = rgn.fBounds;
1301            fRuns = NULL;
1302        } else {
1303            fRuns = rgn.fRunHead->readonly_runs();
1304            fRect.set(fRuns[3], fRuns[0], fRuns[4], fRuns[1]);
1305            fRuns += 5;
1306            // Now fRuns points to the 2nd interval (or x-sentinel)
1307        }
1308    }
1309}
1310
1311void SkRegion::Iterator::next() {
1312    if (fDone) {
1313        return;
1314    }
1315
1316    if (fRuns == NULL) {   // rect case
1317        fDone = true;
1318        return;
1319    }
1320
1321    const RunType* runs = fRuns;
1322
1323    if (runs[0] < kRunTypeSentinel) { // valid X value
1324        fRect.fLeft = runs[0];
1325        fRect.fRight = runs[1];
1326        runs += 2;
1327    } else {    // we're at the end of a line
1328        runs += 1;
1329        if (runs[0] < kRunTypeSentinel) { // valid Y value
1330            int intervals = runs[1];
1331            if (0 == intervals) {    // empty line
1332                fRect.fTop = runs[0];
1333                runs += 3;
1334            } else {
1335                fRect.fTop = fRect.fBottom;
1336            }
1337
1338            fRect.fBottom = runs[0];
1339            assert_sentinel(runs[2], false);
1340            assert_sentinel(runs[3], false);
1341            fRect.fLeft = runs[2];
1342            fRect.fRight = runs[3];
1343            runs += 4;
1344        } else {    // end of rgn
1345            fDone = true;
1346        }
1347    }
1348    fRuns = runs;
1349}
1350
1351SkRegion::Cliperator::Cliperator(const SkRegion& rgn, const SkIRect& clip)
1352        : fIter(rgn), fClip(clip), fDone(true) {
1353    const SkIRect& r = fIter.rect();
1354
1355    while (!fIter.done()) {
1356        if (r.fTop >= clip.fBottom) {
1357            break;
1358        }
1359        if (fRect.intersect(clip, r)) {
1360            fDone = false;
1361            break;
1362        }
1363        fIter.next();
1364    }
1365}
1366
1367void SkRegion::Cliperator::next() {
1368    if (fDone) {
1369        return;
1370    }
1371
1372    const SkIRect& r = fIter.rect();
1373
1374    fDone = true;
1375    fIter.next();
1376    while (!fIter.done()) {
1377        if (r.fTop >= fClip.fBottom) {
1378            break;
1379        }
1380        if (fRect.intersect(fClip, r)) {
1381            fDone = false;
1382            break;
1383        }
1384        fIter.next();
1385    }
1386}
1387
1388///////////////////////////////////////////////////////////////////////////////
1389
1390SkRegion::Spanerator::Spanerator(const SkRegion& rgn, int y, int left,
1391                                 int right) {
1392    SkDEBUGCODE(rgn.validate();)
1393
1394    const SkIRect& r = rgn.getBounds();
1395
1396    fDone = true;
1397    if (!rgn.isEmpty() && y >= r.fTop && y < r.fBottom &&
1398            right > r.fLeft && left < r.fRight) {
1399        if (rgn.isRect()) {
1400            if (left < r.fLeft) {
1401                left = r.fLeft;
1402            }
1403            if (right > r.fRight) {
1404                right = r.fRight;
1405            }
1406            fLeft = left;
1407            fRight = right;
1408            fRuns = NULL;    // means we're a rect, not a rgn
1409            fDone = false;
1410        } else {
1411            const SkRegion::RunType* runs = rgn.fRunHead->findScanline(y);
1412            runs += 2;  // skip Bottom and IntervalCount
1413            for (;;) {
1414                // runs[0..1] is to the right of the span, so we're done
1415                if (runs[0] >= right) {
1416                    break;
1417                }
1418                // runs[0..1] is to the left of the span, so continue
1419                if (runs[1] <= left) {
1420                    runs += 2;
1421                    continue;
1422                }
1423                // runs[0..1] intersects the span
1424                fRuns = runs;
1425                fLeft = left;
1426                fRight = right;
1427                fDone = false;
1428                break;
1429            }
1430        }
1431    }
1432}
1433
1434bool SkRegion::Spanerator::next(int* left, int* right) {
1435    if (fDone) {
1436        return false;
1437    }
1438
1439    if (fRuns == NULL) {   // we're a rect
1440        fDone = true;   // ok, now we're done
1441        if (left) {
1442            *left = fLeft;
1443        }
1444        if (right) {
1445            *right = fRight;
1446        }
1447        return true;    // this interval is legal
1448    }
1449
1450    const SkRegion::RunType* runs = fRuns;
1451
1452    if (runs[0] >= fRight) {
1453        fDone = true;
1454        return false;
1455    }
1456
1457    SkASSERT(runs[1] > fLeft);
1458
1459    if (left) {
1460        *left = SkMax32(fLeft, runs[0]);
1461    }
1462    if (right) {
1463        *right = SkMin32(fRight, runs[1]);
1464    }
1465    fRuns = runs + 2;
1466    return true;
1467}
1468
1469///////////////////////////////////////////////////////////////////////////////
1470
1471#ifdef SK_DEBUG
1472
1473bool SkRegion::debugSetRuns(const RunType runs[], int count) {
1474    // we need to make a copy, since the real method may modify the array, and
1475    // so it cannot be const.
1476
1477    SkAutoTArray<RunType> storage(count);
1478    memcpy(storage.get(), runs, count * sizeof(RunType));
1479    return this->setRuns(storage.get(), count);
1480}
1481
1482#endif
1483