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