Region.cpp revision fe4966d59b31ae6fd6dd4d81dd73d2f4f7be33fe
1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "Region"
18
19#include <inttypes.h>
20#include <limits.h>
21
22#include <utils/Log.h>
23#include <utils/String8.h>
24#include <utils/CallStack.h>
25
26#include <ui/Rect.h>
27#include <ui/Region.h>
28#include <ui/Point.h>
29
30#include <private/ui/RegionHelper.h>
31
32// ----------------------------------------------------------------------------
33#define VALIDATE_REGIONS        (false)
34#define VALIDATE_WITH_CORECG    (false)
35// ----------------------------------------------------------------------------
36
37#if VALIDATE_WITH_CORECG
38#include <core/SkRegion.h>
39#endif
40
41namespace android {
42// ----------------------------------------------------------------------------
43
44enum {
45    op_nand = region_operator<Rect>::op_nand,
46    op_and  = region_operator<Rect>::op_and,
47    op_or   = region_operator<Rect>::op_or,
48    op_xor  = region_operator<Rect>::op_xor
49};
50
51enum {
52    direction_LTR,
53    direction_RTL
54};
55
56// ----------------------------------------------------------------------------
57
58Region::Region() {
59    mStorage.add(Rect(0,0));
60}
61
62Region::Region(const Region& rhs)
63    : mStorage(rhs.mStorage)
64{
65#if VALIDATE_REGIONS
66    validate(rhs, "rhs copy-ctor");
67#endif
68}
69
70Region::Region(const Rect& rhs) {
71    mStorage.add(rhs);
72}
73
74Region::~Region()
75{
76}
77
78/**
79 * Copy rects from the src vector into the dst vector, resolving vertical T-Junctions along the way
80 *
81 * First pass through, divideSpanRTL will be set because the 'previous span' (indexing into the dst
82 * vector) will be reversed. Each rectangle in the original list, starting from the bottom, will be
83 * compared with the span directly below, and subdivided as needed to resolve T-junctions.
84 *
85 * The resulting temporary vector will be a completely reversed copy of the original, without any
86 * bottom-up T-junctions.
87 *
88 * Second pass through, divideSpanRTL will be false since the previous span will index into the
89 * final, correctly ordered region buffer. Each rectangle will be compared with the span directly
90 * above it, and subdivided to resolve any remaining T-junctions.
91 */
92static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end,
93        Vector<Rect>& dst, int spanDirection) {
94    dst.clear();
95
96    const Rect* current = end - 1;
97    int lastTop = current->top;
98
99    // add first span immediately
100    do {
101        dst.add(*current);
102        current--;
103    } while (current->top == lastTop && current >= begin);
104
105    int beginLastSpan = -1;
106    int endLastSpan = -1;
107    int top = -1;
108    int bottom = -1;
109
110    // for all other spans, split if a t-junction exists in the span directly above
111    while (current >= begin) {
112        if (current->top != (current + 1)->top) {
113            // new span
114            if ((spanDirection == direction_RTL && current->bottom != (current + 1)->top) ||
115                    (spanDirection == direction_LTR && current->top != (current + 1)->bottom)) {
116                // previous span not directly adjacent, don't check for T junctions
117                beginLastSpan = INT_MAX;
118            } else {
119                beginLastSpan = endLastSpan + 1;
120            }
121            endLastSpan = static_cast<int>(dst.size()) - 1;
122
123            top = current->top;
124            bottom = current->bottom;
125        }
126        int left = current->left;
127        int right = current->right;
128
129        for (int prevIndex = beginLastSpan; prevIndex <= endLastSpan; prevIndex++) {
130            // prevIndex can't be -1 here because if endLastSpan is set to a
131            // value greater than -1 (allowing the loop to execute),
132            // beginLastSpan (and therefore prevIndex) will also be increased
133            const Rect* prev = &dst[static_cast<size_t>(prevIndex)];
134
135            if (spanDirection == direction_RTL) {
136                // iterating over previous span RTL, quit if it's too far left
137                if (prev->right <= left) break;
138
139                if (prev->right > left && prev->right < right) {
140                    dst.add(Rect(prev->right, top, right, bottom));
141                    right = prev->right;
142                }
143
144                if (prev->left > left && prev->left < right) {
145                    dst.add(Rect(prev->left, top, right, bottom));
146                    right = prev->left;
147                }
148
149                // if an entry in the previous span is too far right, nothing further left in the
150                // current span will need it
151                if (prev->left >= right) {
152                    beginLastSpan = prevIndex;
153                }
154            } else {
155                // iterating over previous span LTR, quit if it's too far right
156                if (prev->left >= right) break;
157
158                if (prev->left > left && prev->left < right) {
159                    dst.add(Rect(left, top, prev->left, bottom));
160                    left = prev->left;
161                }
162
163                if (prev->right > left && prev->right < right) {
164                    dst.add(Rect(left, top, prev->right, bottom));
165                    left = prev->right;
166                }
167                // if an entry in the previous span is too far left, nothing further right in the
168                // current span will need it
169                if (prev->right <= left) {
170                    beginLastSpan = prevIndex;
171                }
172            }
173        }
174
175        if (left < right) {
176            dst.add(Rect(left, top, right, bottom));
177        }
178
179        current--;
180    }
181}
182
183/**
184 * Creates a new region with the same data as the argument, but divides rectangles as necessary to
185 * remove T-Junctions
186 *
187 * Note: the output will not necessarily be a very efficient representation of the region, since it
188 * may be that a triangle-based approach would generate significantly simpler geometry
189 */
190Region Region::createTJunctionFreeRegion(const Region& r) {
191    if (r.isEmpty()) return r;
192    if (r.isRect()) return r;
193
194    Vector<Rect> reversed;
195    reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL);
196
197    Region outputRegion;
198    reverseRectsResolvingJunctions(reversed.begin(), reversed.end(),
199            outputRegion.mStorage, direction_LTR);
200    outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds
201
202#if VALIDATE_REGIONS
203    validate(outputRegion, "T-Junction free region");
204#endif
205
206    return outputRegion;
207}
208
209Region& Region::operator = (const Region& rhs)
210{
211#if VALIDATE_REGIONS
212    validate(*this, "this->operator=");
213    validate(rhs, "rhs.operator=");
214#endif
215    mStorage = rhs.mStorage;
216    return *this;
217}
218
219Region& Region::makeBoundsSelf()
220{
221    if (mStorage.size() >= 2) {
222        const Rect bounds(getBounds());
223        mStorage.clear();
224        mStorage.add(bounds);
225    }
226    return *this;
227}
228
229bool Region::contains(const Point& point) const {
230    return contains(point.x, point.y);
231}
232
233bool Region::contains(int x, int y) const {
234    const_iterator cur = begin();
235    const_iterator const tail = end();
236    while (cur != tail) {
237        if (y >= cur->top && y < cur->bottom && x >= cur->left && x < cur->right) {
238            return true;
239        }
240        cur++;
241    }
242    return false;
243}
244
245void Region::clear()
246{
247    mStorage.clear();
248    mStorage.add(Rect(0,0));
249}
250
251void Region::set(const Rect& r)
252{
253    mStorage.clear();
254    mStorage.add(r);
255}
256
257void Region::set(int32_t w, int32_t h)
258{
259    mStorage.clear();
260    mStorage.add(Rect(w, h));
261}
262
263void Region::set(uint32_t w, uint32_t h)
264{
265    mStorage.clear();
266    mStorage.add(Rect(w, h));
267}
268
269bool Region::isTriviallyEqual(const Region& region) const {
270    return begin() == region.begin();
271}
272
273// ----------------------------------------------------------------------------
274
275void Region::addRectUnchecked(int l, int t, int r, int b)
276{
277    Rect rect(l,t,r,b);
278    size_t where = mStorage.size() - 1;
279    mStorage.insertAt(rect, where, 1);
280}
281
282// ----------------------------------------------------------------------------
283
284Region& Region::orSelf(const Rect& r) {
285    return operationSelf(r, op_or);
286}
287Region& Region::xorSelf(const Rect& r) {
288    return operationSelf(r, op_xor);
289}
290Region& Region::andSelf(const Rect& r) {
291    return operationSelf(r, op_and);
292}
293Region& Region::subtractSelf(const Rect& r) {
294    return operationSelf(r, op_nand);
295}
296Region& Region::operationSelf(const Rect& r, int op) {
297    Region lhs(*this);
298    boolean_operation(op, *this, lhs, r);
299    return *this;
300}
301
302// ----------------------------------------------------------------------------
303
304Region& Region::orSelf(const Region& rhs) {
305    return operationSelf(rhs, op_or);
306}
307Region& Region::xorSelf(const Region& rhs) {
308    return operationSelf(rhs, op_xor);
309}
310Region& Region::andSelf(const Region& rhs) {
311    return operationSelf(rhs, op_and);
312}
313Region& Region::subtractSelf(const Region& rhs) {
314    return operationSelf(rhs, op_nand);
315}
316Region& Region::operationSelf(const Region& rhs, int op) {
317    Region lhs(*this);
318    boolean_operation(op, *this, lhs, rhs);
319    return *this;
320}
321
322Region& Region::translateSelf(int x, int y) {
323    if (x|y) translate(*this, x, y);
324    return *this;
325}
326
327// ----------------------------------------------------------------------------
328
329const Region Region::merge(const Rect& rhs) const {
330    return operation(rhs, op_or);
331}
332const Region Region::mergeExclusive(const Rect& rhs) const {
333    return operation(rhs, op_xor);
334}
335const Region Region::intersect(const Rect& rhs) const {
336    return operation(rhs, op_and);
337}
338const Region Region::subtract(const Rect& rhs) const {
339    return operation(rhs, op_nand);
340}
341const Region Region::operation(const Rect& rhs, int op) const {
342    Region result;
343    boolean_operation(op, result, *this, rhs);
344    return result;
345}
346
347// ----------------------------------------------------------------------------
348
349const Region Region::merge(const Region& rhs) const {
350    return operation(rhs, op_or);
351}
352const Region Region::mergeExclusive(const Region& rhs) const {
353    return operation(rhs, op_xor);
354}
355const Region Region::intersect(const Region& rhs) const {
356    return operation(rhs, op_and);
357}
358const Region Region::subtract(const Region& rhs) const {
359    return operation(rhs, op_nand);
360}
361const Region Region::operation(const Region& rhs, int op) const {
362    Region result;
363    boolean_operation(op, result, *this, rhs);
364    return result;
365}
366
367const Region Region::translate(int x, int y) const {
368    Region result;
369    translate(result, *this, x, y);
370    return result;
371}
372
373// ----------------------------------------------------------------------------
374
375Region& Region::orSelf(const Region& rhs, int dx, int dy) {
376    return operationSelf(rhs, dx, dy, op_or);
377}
378Region& Region::xorSelf(const Region& rhs, int dx, int dy) {
379    return operationSelf(rhs, dx, dy, op_xor);
380}
381Region& Region::andSelf(const Region& rhs, int dx, int dy) {
382    return operationSelf(rhs, dx, dy, op_and);
383}
384Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
385    return operationSelf(rhs, dx, dy, op_nand);
386}
387Region& Region::operationSelf(const Region& rhs, int dx, int dy, int op) {
388    Region lhs(*this);
389    boolean_operation(op, *this, lhs, rhs, dx, dy);
390    return *this;
391}
392
393// ----------------------------------------------------------------------------
394
395const Region Region::merge(const Region& rhs, int dx, int dy) const {
396    return operation(rhs, dx, dy, op_or);
397}
398const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const {
399    return operation(rhs, dx, dy, op_xor);
400}
401const Region Region::intersect(const Region& rhs, int dx, int dy) const {
402    return operation(rhs, dx, dy, op_and);
403}
404const Region Region::subtract(const Region& rhs, int dx, int dy) const {
405    return operation(rhs, dx, dy, op_nand);
406}
407const Region Region::operation(const Region& rhs, int dx, int dy, int op) const {
408    Region result;
409    boolean_operation(op, result, *this, rhs, dx, dy);
410    return result;
411}
412
413// ----------------------------------------------------------------------------
414
415// This is our region rasterizer, which merges rects and spans together
416// to obtain an optimal region.
417class Region::rasterizer : public region_operator<Rect>::region_rasterizer
418{
419    Rect bounds;
420    Vector<Rect>& storage;
421    Rect* head;
422    Rect* tail;
423    Vector<Rect> span;
424    Rect* cur;
425public:
426    rasterizer(Region& reg)
427        : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() {
428        storage.clear();
429    }
430
431    virtual ~rasterizer();
432
433    virtual void operator()(const Rect& rect);
434
435private:
436    template<typename T>
437    static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; }
438    template<typename T>
439    static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; }
440
441    void flushSpan();
442};
443
444Region::rasterizer::~rasterizer()
445{
446    if (span.size()) {
447        flushSpan();
448    }
449    if (storage.size()) {
450        bounds.top = storage.itemAt(0).top;
451        bounds.bottom = storage.top().bottom;
452        if (storage.size() == 1) {
453            storage.clear();
454        }
455    } else {
456        bounds.left  = 0;
457        bounds.right = 0;
458    }
459    storage.add(bounds);
460}
461
462void Region::rasterizer::operator()(const Rect& rect)
463{
464    //ALOGD(">>> %3d, %3d, %3d, %3d",
465    //        rect.left, rect.top, rect.right, rect.bottom);
466    if (span.size()) {
467        if (cur->top != rect.top) {
468            flushSpan();
469        } else if (cur->right == rect.left) {
470            cur->right = rect.right;
471            return;
472        }
473    }
474    span.add(rect);
475    cur = span.editArray() + (span.size() - 1);
476}
477
478void Region::rasterizer::flushSpan()
479{
480    bool merge = false;
481    if (tail-head == ssize_t(span.size())) {
482        Rect const* p = span.editArray();
483        Rect const* q = head;
484        if (p->top == q->bottom) {
485            merge = true;
486            while (q != tail) {
487                if ((p->left != q->left) || (p->right != q->right)) {
488                    merge = false;
489                    break;
490                }
491                p++, q++;
492            }
493        }
494    }
495    if (merge) {
496        const int bottom = span[0].bottom;
497        Rect* r = head;
498        while (r != tail) {
499            r->bottom = bottom;
500            r++;
501        }
502    } else {
503        bounds.left = min(span.itemAt(0).left, bounds.left);
504        bounds.right = max(span.top().right, bounds.right);
505        storage.appendVector(span);
506        tail = storage.editArray() + storage.size();
507        head = tail - span.size();
508    }
509    span.clear();
510}
511
512bool Region::validate(const Region& reg, const char* name, bool silent)
513{
514    bool result = true;
515    const_iterator cur = reg.begin();
516    const_iterator const tail = reg.end();
517    const_iterator prev = cur;
518    Rect b(*prev);
519    while (cur != tail) {
520        if (cur->isValid() == false) {
521            ALOGE_IF(!silent, "%s: region contains an invalid Rect", name);
522            result = false;
523        }
524        if (cur->right > region_operator<Rect>::max_value) {
525            ALOGE_IF(!silent, "%s: rect->right > max_value", name);
526            result = false;
527        }
528        if (cur->bottom > region_operator<Rect>::max_value) {
529            ALOGE_IF(!silent, "%s: rect->right > max_value", name);
530            result = false;
531        }
532        if (prev != cur) {
533            b.left   = b.left   < cur->left   ? b.left   : cur->left;
534            b.top    = b.top    < cur->top    ? b.top    : cur->top;
535            b.right  = b.right  > cur->right  ? b.right  : cur->right;
536            b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
537            if ((*prev < *cur) == false) {
538                ALOGE_IF(!silent, "%s: region's Rects not sorted", name);
539                result = false;
540            }
541            if (cur->top == prev->top) {
542                if (cur->bottom != prev->bottom) {
543                    ALOGE_IF(!silent, "%s: invalid span %p", name, cur);
544                    result = false;
545                } else if (cur->left < prev->right) {
546                    ALOGE_IF(!silent,
547                            "%s: spans overlap horizontally prev=%p, cur=%p",
548                            name, prev, cur);
549                    result = false;
550                }
551            } else if (cur->top < prev->bottom) {
552                ALOGE_IF(!silent,
553                        "%s: spans overlap vertically prev=%p, cur=%p",
554                        name, prev, cur);
555                result = false;
556            }
557            prev = cur;
558        }
559        cur++;
560    }
561    if (b != reg.getBounds()) {
562        result = false;
563        ALOGE_IF(!silent,
564                "%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
565                b.left, b.top, b.right, b.bottom,
566                reg.getBounds().left, reg.getBounds().top,
567                reg.getBounds().right, reg.getBounds().bottom);
568    }
569    if (reg.mStorage.size() == 2) {
570        result = false;
571        ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name);
572    }
573    if (result == false && !silent) {
574        reg.dump(name);
575        CallStack stack(LOG_TAG);
576    }
577    return result;
578}
579
580void Region::boolean_operation(int op, Region& dst,
581        const Region& lhs,
582        const Region& rhs, int dx, int dy)
583{
584#if VALIDATE_REGIONS
585    validate(lhs, "boolean_operation (before): lhs");
586    validate(rhs, "boolean_operation (before): rhs");
587    validate(dst, "boolean_operation (before): dst");
588#endif
589
590    size_t lhs_count;
591    Rect const * const lhs_rects = lhs.getArray(&lhs_count);
592
593    size_t rhs_count;
594    Rect const * const rhs_rects = rhs.getArray(&rhs_count);
595
596    region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
597    region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy);
598    region_operator<Rect> operation(op, lhs_region, rhs_region);
599    { // scope for rasterizer (dtor has side effects)
600        rasterizer r(dst);
601        operation(r);
602    }
603
604#if VALIDATE_REGIONS
605    validate(lhs, "boolean_operation: lhs");
606    validate(rhs, "boolean_operation: rhs");
607    validate(dst, "boolean_operation: dst");
608#endif
609
610#if VALIDATE_WITH_CORECG
611    SkRegion sk_lhs;
612    SkRegion sk_rhs;
613    SkRegion sk_dst;
614
615    for (size_t i=0 ; i<lhs_count ; i++)
616        sk_lhs.op(
617                lhs_rects[i].left   + dx,
618                lhs_rects[i].top    + dy,
619                lhs_rects[i].right  + dx,
620                lhs_rects[i].bottom + dy,
621                SkRegion::kUnion_Op);
622
623    for (size_t i=0 ; i<rhs_count ; i++)
624        sk_rhs.op(
625                rhs_rects[i].left   + dx,
626                rhs_rects[i].top    + dy,
627                rhs_rects[i].right  + dx,
628                rhs_rects[i].bottom + dy,
629                SkRegion::kUnion_Op);
630
631    const char* name = "---";
632    SkRegion::Op sk_op;
633    switch (op) {
634        case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
635        case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break;
636        case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
637        case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
638    }
639    sk_dst.op(sk_lhs, sk_rhs, sk_op);
640
641    if (sk_dst.isEmpty() && dst.isEmpty())
642        return;
643
644    bool same = true;
645    Region::const_iterator head = dst.begin();
646    Region::const_iterator const tail = dst.end();
647    SkRegion::Iterator it(sk_dst);
648    while (!it.done()) {
649        if (head != tail) {
650            if (
651                    head->left != it.rect().fLeft ||
652                    head->top != it.rect().fTop ||
653                    head->right != it.rect().fRight ||
654                    head->bottom != it.rect().fBottom
655            ) {
656                same = false;
657                break;
658            }
659        } else {
660            same = false;
661            break;
662        }
663        head++;
664        it.next();
665    }
666
667    if (head != tail) {
668        same = false;
669    }
670
671    if(!same) {
672        ALOGD("---\nregion boolean %s failed", name);
673        lhs.dump("lhs");
674        rhs.dump("rhs");
675        dst.dump("dst");
676        ALOGD("should be");
677        SkRegion::Iterator it(sk_dst);
678        while (!it.done()) {
679            ALOGD("    [%3d, %3d, %3d, %3d]",
680                it.rect().fLeft,
681                it.rect().fTop,
682                it.rect().fRight,
683                it.rect().fBottom);
684            it.next();
685        }
686    }
687#endif
688}
689
690void Region::boolean_operation(int op, Region& dst,
691        const Region& lhs,
692        const Rect& rhs, int dx, int dy)
693{
694    if (!rhs.isValid()) {
695        ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}",
696                op, rhs.left, rhs.top, rhs.right, rhs.bottom);
697        return;
698    }
699
700#if VALIDATE_WITH_CORECG || VALIDATE_REGIONS
701    boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
702#else
703    size_t lhs_count;
704    Rect const * const lhs_rects = lhs.getArray(&lhs_count);
705
706    region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
707    region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy);
708    region_operator<Rect> operation(op, lhs_region, rhs_region);
709    { // scope for rasterizer (dtor has side effects)
710        rasterizer r(dst);
711        operation(r);
712    }
713
714#endif
715}
716
717void Region::boolean_operation(int op, Region& dst,
718        const Region& lhs, const Region& rhs)
719{
720    boolean_operation(op, dst, lhs, rhs, 0, 0);
721}
722
723void Region::boolean_operation(int op, Region& dst,
724        const Region& lhs, const Rect& rhs)
725{
726    boolean_operation(op, dst, lhs, rhs, 0, 0);
727}
728
729void Region::translate(Region& reg, int dx, int dy)
730{
731    if ((dx || dy) && !reg.isEmpty()) {
732#if VALIDATE_REGIONS
733        validate(reg, "translate (before)");
734#endif
735        size_t count = reg.mStorage.size();
736        Rect* rects = reg.mStorage.editArray();
737        while (count) {
738            rects->offsetBy(dx, dy);
739            rects++;
740            count--;
741        }
742#if VALIDATE_REGIONS
743        validate(reg, "translate (after)");
744#endif
745    }
746}
747
748void Region::translate(Region& dst, const Region& reg, int dx, int dy)
749{
750    dst = reg;
751    translate(dst, dx, dy);
752}
753
754// ----------------------------------------------------------------------------
755
756size_t Region::getFlattenedSize() const {
757    return mStorage.size() * sizeof(Rect);
758}
759
760status_t Region::flatten(void* buffer, size_t size) const {
761#if VALIDATE_REGIONS
762    validate(*this, "Region::flatten");
763#endif
764    if (size < mStorage.size() * sizeof(Rect)) {
765        return NO_MEMORY;
766    }
767    Rect* rects = reinterpret_cast<Rect*>(buffer);
768    memcpy(rects, mStorage.array(), mStorage.size() * sizeof(Rect));
769    return NO_ERROR;
770}
771
772status_t Region::unflatten(void const* buffer, size_t size) {
773    Region result;
774    if (size >= sizeof(Rect)) {
775        Rect const* rects = reinterpret_cast<Rect const*>(buffer);
776        size_t count = size / sizeof(Rect);
777        if (count > 0) {
778            result.mStorage.clear();
779            ssize_t err = result.mStorage.insertAt(0, count);
780            if (err < 0) {
781                return status_t(err);
782            }
783            memcpy(result.mStorage.editArray(), rects, count*sizeof(Rect));
784        }
785    }
786#if VALIDATE_REGIONS
787    validate(result, "Region::unflatten");
788#endif
789
790    if (!result.validate(result, "Region::unflatten", true)) {
791        ALOGE("Region::unflatten() failed, invalid region");
792        return BAD_VALUE;
793    }
794    mStorage = result.mStorage;
795    return NO_ERROR;
796}
797
798// ----------------------------------------------------------------------------
799
800Region::const_iterator Region::begin() const {
801    return mStorage.array();
802}
803
804Region::const_iterator Region::end() const {
805    size_t numRects = isRect() ? 1 : mStorage.size() - 1;
806    return mStorage.array() + numRects;
807}
808
809Rect const* Region::getArray(size_t* count) const {
810    if (count) *count = static_cast<size_t>(end() - begin());
811    return begin();
812}
813
814SharedBuffer const* Region::getSharedBuffer(size_t* count) const {
815    // We can get to the SharedBuffer of a Vector<Rect> because Rect has
816    // a trivial destructor.
817    SharedBuffer const* sb = SharedBuffer::bufferFromData(mStorage.array());
818    if (count) {
819        size_t numRects = isRect() ? 1 : mStorage.size() - 1;
820        count[0] = numRects;
821    }
822    sb->acquire();
823    return sb;
824}
825
826// ----------------------------------------------------------------------------
827
828void Region::dump(String8& out, const char* what, uint32_t /* flags */) const
829{
830    const_iterator head = begin();
831    const_iterator const tail = end();
832
833    out.appendFormat("  Region %s (this=%p, count=%" PRIdPTR ")\n",
834            what, this, tail - head);
835    while (head != tail) {
836        out.appendFormat("    [%3d, %3d, %3d, %3d]\n", head->left, head->top,
837                head->right, head->bottom);
838        ++head;
839    }
840}
841
842void Region::dump(const char* what, uint32_t /* flags */) const
843{
844    const_iterator head = begin();
845    const_iterator const tail = end();
846    ALOGD("  Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail-head);
847    while (head != tail) {
848        ALOGD("    [%3d, %3d, %3d, %3d]\n",
849                head->left, head->top, head->right, head->bottom);
850        head++;
851    }
852}
853
854// ----------------------------------------------------------------------------
855
856}; // namespace android
857