Region.cpp revision d31824004277f554000417cea349d69f18655e95
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
263bool Region::isTriviallyEqual(const Region& region) const {
264    return begin() == region.begin();
265}
266
267// ----------------------------------------------------------------------------
268
269void Region::addRectUnchecked(int l, int t, int r, int b)
270{
271    Rect rect(l,t,r,b);
272    size_t where = mStorage.size() - 1;
273    mStorage.insertAt(rect, where, 1);
274}
275
276// ----------------------------------------------------------------------------
277
278Region& Region::orSelf(const Rect& r) {
279    return operationSelf(r, op_or);
280}
281Region& Region::xorSelf(const Rect& r) {
282    return operationSelf(r, op_xor);
283}
284Region& Region::andSelf(const Rect& r) {
285    return operationSelf(r, op_and);
286}
287Region& Region::subtractSelf(const Rect& r) {
288    return operationSelf(r, op_nand);
289}
290Region& Region::operationSelf(const Rect& r, int op) {
291    Region lhs(*this);
292    boolean_operation(op, *this, lhs, r);
293    return *this;
294}
295
296// ----------------------------------------------------------------------------
297
298Region& Region::orSelf(const Region& rhs) {
299    return operationSelf(rhs, op_or);
300}
301Region& Region::xorSelf(const Region& rhs) {
302    return operationSelf(rhs, op_xor);
303}
304Region& Region::andSelf(const Region& rhs) {
305    return operationSelf(rhs, op_and);
306}
307Region& Region::subtractSelf(const Region& rhs) {
308    return operationSelf(rhs, op_nand);
309}
310Region& Region::operationSelf(const Region& rhs, int op) {
311    Region lhs(*this);
312    boolean_operation(op, *this, lhs, rhs);
313    return *this;
314}
315
316Region& Region::translateSelf(int x, int y) {
317    if (x|y) translate(*this, x, y);
318    return *this;
319}
320
321// ----------------------------------------------------------------------------
322
323const Region Region::merge(const Rect& rhs) const {
324    return operation(rhs, op_or);
325}
326const Region Region::mergeExclusive(const Rect& rhs) const {
327    return operation(rhs, op_xor);
328}
329const Region Region::intersect(const Rect& rhs) const {
330    return operation(rhs, op_and);
331}
332const Region Region::subtract(const Rect& rhs) const {
333    return operation(rhs, op_nand);
334}
335const Region Region::operation(const Rect& rhs, int op) const {
336    Region result;
337    boolean_operation(op, result, *this, rhs);
338    return result;
339}
340
341// ----------------------------------------------------------------------------
342
343const Region Region::merge(const Region& rhs) const {
344    return operation(rhs, op_or);
345}
346const Region Region::mergeExclusive(const Region& rhs) const {
347    return operation(rhs, op_xor);
348}
349const Region Region::intersect(const Region& rhs) const {
350    return operation(rhs, op_and);
351}
352const Region Region::subtract(const Region& rhs) const {
353    return operation(rhs, op_nand);
354}
355const Region Region::operation(const Region& rhs, int op) const {
356    Region result;
357    boolean_operation(op, result, *this, rhs);
358    return result;
359}
360
361const Region Region::translate(int x, int y) const {
362    Region result;
363    translate(result, *this, x, y);
364    return result;
365}
366
367// ----------------------------------------------------------------------------
368
369Region& Region::orSelf(const Region& rhs, int dx, int dy) {
370    return operationSelf(rhs, dx, dy, op_or);
371}
372Region& Region::xorSelf(const Region& rhs, int dx, int dy) {
373    return operationSelf(rhs, dx, dy, op_xor);
374}
375Region& Region::andSelf(const Region& rhs, int dx, int dy) {
376    return operationSelf(rhs, dx, dy, op_and);
377}
378Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
379    return operationSelf(rhs, dx, dy, op_nand);
380}
381Region& Region::operationSelf(const Region& rhs, int dx, int dy, int op) {
382    Region lhs(*this);
383    boolean_operation(op, *this, lhs, rhs, dx, dy);
384    return *this;
385}
386
387// ----------------------------------------------------------------------------
388
389const Region Region::merge(const Region& rhs, int dx, int dy) const {
390    return operation(rhs, dx, dy, op_or);
391}
392const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const {
393    return operation(rhs, dx, dy, op_xor);
394}
395const Region Region::intersect(const Region& rhs, int dx, int dy) const {
396    return operation(rhs, dx, dy, op_and);
397}
398const Region Region::subtract(const Region& rhs, int dx, int dy) const {
399    return operation(rhs, dx, dy, op_nand);
400}
401const Region Region::operation(const Region& rhs, int dx, int dy, int op) const {
402    Region result;
403    boolean_operation(op, result, *this, rhs, dx, dy);
404    return result;
405}
406
407// ----------------------------------------------------------------------------
408
409// This is our region rasterizer, which merges rects and spans together
410// to obtain an optimal region.
411class Region::rasterizer : public region_operator<Rect>::region_rasterizer
412{
413    Rect bounds;
414    Vector<Rect>& storage;
415    Rect* head;
416    Rect* tail;
417    Vector<Rect> span;
418    Rect* cur;
419public:
420    rasterizer(Region& reg)
421        : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() {
422        storage.clear();
423    }
424
425    virtual ~rasterizer();
426
427    virtual void operator()(const Rect& rect);
428
429private:
430    template<typename T>
431    static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; }
432    template<typename T>
433    static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; }
434
435    void flushSpan();
436};
437
438Region::rasterizer::~rasterizer()
439{
440    if (span.size()) {
441        flushSpan();
442    }
443    if (storage.size()) {
444        bounds.top = storage.itemAt(0).top;
445        bounds.bottom = storage.top().bottom;
446        if (storage.size() == 1) {
447            storage.clear();
448        }
449    } else {
450        bounds.left  = 0;
451        bounds.right = 0;
452    }
453    storage.add(bounds);
454}
455
456void Region::rasterizer::operator()(const Rect& rect)
457{
458    //ALOGD(">>> %3d, %3d, %3d, %3d",
459    //        rect.left, rect.top, rect.right, rect.bottom);
460    if (span.size()) {
461        if (cur->top != rect.top) {
462            flushSpan();
463        } else if (cur->right == rect.left) {
464            cur->right = rect.right;
465            return;
466        }
467    }
468    span.add(rect);
469    cur = span.editArray() + (span.size() - 1);
470}
471
472void Region::rasterizer::flushSpan()
473{
474    bool merge = false;
475    if (tail-head == ssize_t(span.size())) {
476        Rect const* p = span.editArray();
477        Rect const* q = head;
478        if (p->top == q->bottom) {
479            merge = true;
480            while (q != tail) {
481                if ((p->left != q->left) || (p->right != q->right)) {
482                    merge = false;
483                    break;
484                }
485                p++, q++;
486            }
487        }
488    }
489    if (merge) {
490        const int bottom = span[0].bottom;
491        Rect* r = head;
492        while (r != tail) {
493            r->bottom = bottom;
494            r++;
495        }
496    } else {
497        bounds.left = min(span.itemAt(0).left, bounds.left);
498        bounds.right = max(span.top().right, bounds.right);
499        storage.appendVector(span);
500        tail = storage.editArray() + storage.size();
501        head = tail - span.size();
502    }
503    span.clear();
504}
505
506bool Region::validate(const Region& reg, const char* name, bool silent)
507{
508    bool result = true;
509    const_iterator cur = reg.begin();
510    const_iterator const tail = reg.end();
511    const_iterator prev = cur;
512    Rect b(*prev);
513    while (cur != tail) {
514        if (cur->isValid() == false) {
515            ALOGE_IF(!silent, "%s: region contains an invalid Rect", name);
516            result = false;
517        }
518        if (cur->right > region_operator<Rect>::max_value) {
519            ALOGE_IF(!silent, "%s: rect->right > max_value", name);
520            result = false;
521        }
522        if (cur->bottom > region_operator<Rect>::max_value) {
523            ALOGE_IF(!silent, "%s: rect->right > max_value", name);
524            result = false;
525        }
526        if (prev != cur) {
527            b.left   = b.left   < cur->left   ? b.left   : cur->left;
528            b.top    = b.top    < cur->top    ? b.top    : cur->top;
529            b.right  = b.right  > cur->right  ? b.right  : cur->right;
530            b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
531            if ((*prev < *cur) == false) {
532                ALOGE_IF(!silent, "%s: region's Rects not sorted", name);
533                result = false;
534            }
535            if (cur->top == prev->top) {
536                if (cur->bottom != prev->bottom) {
537                    ALOGE_IF(!silent, "%s: invalid span %p", name, cur);
538                    result = false;
539                } else if (cur->left < prev->right) {
540                    ALOGE_IF(!silent,
541                            "%s: spans overlap horizontally prev=%p, cur=%p",
542                            name, prev, cur);
543                    result = false;
544                }
545            } else if (cur->top < prev->bottom) {
546                ALOGE_IF(!silent,
547                        "%s: spans overlap vertically prev=%p, cur=%p",
548                        name, prev, cur);
549                result = false;
550            }
551            prev = cur;
552        }
553        cur++;
554    }
555    if (b != reg.getBounds()) {
556        result = false;
557        ALOGE_IF(!silent,
558                "%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
559                b.left, b.top, b.right, b.bottom,
560                reg.getBounds().left, reg.getBounds().top,
561                reg.getBounds().right, reg.getBounds().bottom);
562    }
563    if (reg.mStorage.size() == 2) {
564        result = false;
565        ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name);
566    }
567    if (result == false && !silent) {
568        reg.dump(name);
569        CallStack stack(LOG_TAG);
570    }
571    return result;
572}
573
574void Region::boolean_operation(int op, Region& dst,
575        const Region& lhs,
576        const Region& rhs, int dx, int dy)
577{
578#if VALIDATE_REGIONS
579    validate(lhs, "boolean_operation (before): lhs");
580    validate(rhs, "boolean_operation (before): rhs");
581    validate(dst, "boolean_operation (before): dst");
582#endif
583
584    size_t lhs_count;
585    Rect const * const lhs_rects = lhs.getArray(&lhs_count);
586
587    size_t rhs_count;
588    Rect const * const rhs_rects = rhs.getArray(&rhs_count);
589
590    region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
591    region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy);
592    region_operator<Rect> operation(op, lhs_region, rhs_region);
593    { // scope for rasterizer (dtor has side effects)
594        rasterizer r(dst);
595        operation(r);
596    }
597
598#if VALIDATE_REGIONS
599    validate(lhs, "boolean_operation: lhs");
600    validate(rhs, "boolean_operation: rhs");
601    validate(dst, "boolean_operation: dst");
602#endif
603
604#if VALIDATE_WITH_CORECG
605    SkRegion sk_lhs;
606    SkRegion sk_rhs;
607    SkRegion sk_dst;
608
609    for (size_t i=0 ; i<lhs_count ; i++)
610        sk_lhs.op(
611                lhs_rects[i].left   + dx,
612                lhs_rects[i].top    + dy,
613                lhs_rects[i].right  + dx,
614                lhs_rects[i].bottom + dy,
615                SkRegion::kUnion_Op);
616
617    for (size_t i=0 ; i<rhs_count ; i++)
618        sk_rhs.op(
619                rhs_rects[i].left   + dx,
620                rhs_rects[i].top    + dy,
621                rhs_rects[i].right  + dx,
622                rhs_rects[i].bottom + dy,
623                SkRegion::kUnion_Op);
624
625    const char* name = "---";
626    SkRegion::Op sk_op;
627    switch (op) {
628        case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
629        case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break;
630        case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
631        case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
632    }
633    sk_dst.op(sk_lhs, sk_rhs, sk_op);
634
635    if (sk_dst.isEmpty() && dst.isEmpty())
636        return;
637
638    bool same = true;
639    Region::const_iterator head = dst.begin();
640    Region::const_iterator const tail = dst.end();
641    SkRegion::Iterator it(sk_dst);
642    while (!it.done()) {
643        if (head != tail) {
644            if (
645                    head->left != it.rect().fLeft ||
646                    head->top != it.rect().fTop ||
647                    head->right != it.rect().fRight ||
648                    head->bottom != it.rect().fBottom
649            ) {
650                same = false;
651                break;
652            }
653        } else {
654            same = false;
655            break;
656        }
657        head++;
658        it.next();
659    }
660
661    if (head != tail) {
662        same = false;
663    }
664
665    if(!same) {
666        ALOGD("---\nregion boolean %s failed", name);
667        lhs.dump("lhs");
668        rhs.dump("rhs");
669        dst.dump("dst");
670        ALOGD("should be");
671        SkRegion::Iterator it(sk_dst);
672        while (!it.done()) {
673            ALOGD("    [%3d, %3d, %3d, %3d]",
674                it.rect().fLeft,
675                it.rect().fTop,
676                it.rect().fRight,
677                it.rect().fBottom);
678            it.next();
679        }
680    }
681#endif
682}
683
684void Region::boolean_operation(int op, Region& dst,
685        const Region& lhs,
686        const Rect& rhs, int dx, int dy)
687{
688    if (!rhs.isValid()) {
689        ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}",
690                op, rhs.left, rhs.top, rhs.right, rhs.bottom);
691        return;
692    }
693
694#if VALIDATE_WITH_CORECG || VALIDATE_REGIONS
695    boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
696#else
697    size_t lhs_count;
698    Rect const * const lhs_rects = lhs.getArray(&lhs_count);
699
700    region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
701    region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy);
702    region_operator<Rect> operation(op, lhs_region, rhs_region);
703    { // scope for rasterizer (dtor has side effects)
704        rasterizer r(dst);
705        operation(r);
706    }
707
708#endif
709}
710
711void Region::boolean_operation(int op, Region& dst,
712        const Region& lhs, const Region& rhs)
713{
714    boolean_operation(op, dst, lhs, rhs, 0, 0);
715}
716
717void Region::boolean_operation(int op, Region& dst,
718        const Region& lhs, const Rect& rhs)
719{
720    boolean_operation(op, dst, lhs, rhs, 0, 0);
721}
722
723void Region::translate(Region& reg, int dx, int dy)
724{
725    if ((dx || dy) && !reg.isEmpty()) {
726#if VALIDATE_REGIONS
727        validate(reg, "translate (before)");
728#endif
729        size_t count = reg.mStorage.size();
730        Rect* rects = reg.mStorage.editArray();
731        while (count) {
732            rects->offsetBy(dx, dy);
733            rects++;
734            count--;
735        }
736#if VALIDATE_REGIONS
737        validate(reg, "translate (after)");
738#endif
739    }
740}
741
742void Region::translate(Region& dst, const Region& reg, int dx, int dy)
743{
744    dst = reg;
745    translate(dst, dx, dy);
746}
747
748// ----------------------------------------------------------------------------
749
750size_t Region::getFlattenedSize() const {
751    return mStorage.size() * sizeof(Rect);
752}
753
754status_t Region::flatten(void* buffer, size_t size) const {
755#if VALIDATE_REGIONS
756    validate(*this, "Region::flatten");
757#endif
758    if (size < mStorage.size() * sizeof(Rect)) {
759        return NO_MEMORY;
760    }
761    Rect* rects = reinterpret_cast<Rect*>(buffer);
762    memcpy(rects, mStorage.array(), mStorage.size() * sizeof(Rect));
763    return NO_ERROR;
764}
765
766status_t Region::unflatten(void const* buffer, size_t size) {
767    Region result;
768    if (size >= sizeof(Rect)) {
769        Rect const* rects = reinterpret_cast<Rect const*>(buffer);
770        size_t count = size / sizeof(Rect);
771        if (count > 0) {
772            result.mStorage.clear();
773            ssize_t err = result.mStorage.insertAt(0, count);
774            if (err < 0) {
775                return status_t(err);
776            }
777            memcpy(result.mStorage.editArray(), rects, count*sizeof(Rect));
778        }
779    }
780#if VALIDATE_REGIONS
781    validate(result, "Region::unflatten");
782#endif
783
784    if (!result.validate(result, "Region::unflatten", true)) {
785        ALOGE("Region::unflatten() failed, invalid region");
786        return BAD_VALUE;
787    }
788    mStorage = result.mStorage;
789    return NO_ERROR;
790}
791
792// ----------------------------------------------------------------------------
793
794Region::const_iterator Region::begin() const {
795    return mStorage.array();
796}
797
798Region::const_iterator Region::end() const {
799    size_t numRects = isRect() ? 1 : mStorage.size() - 1;
800    return mStorage.array() + numRects;
801}
802
803Rect const* Region::getArray(size_t* count) const {
804    if (count) *count = static_cast<size_t>(end() - begin());
805    return begin();
806}
807
808SharedBuffer const* Region::getSharedBuffer(size_t* count) const {
809    // We can get to the SharedBuffer of a Vector<Rect> because Rect has
810    // a trivial destructor.
811    SharedBuffer const* sb = SharedBuffer::bufferFromData(mStorage.array());
812    if (count) {
813        size_t numRects = isRect() ? 1 : mStorage.size() - 1;
814        count[0] = numRects;
815    }
816    sb->acquire();
817    return sb;
818}
819
820// ----------------------------------------------------------------------------
821
822void Region::dump(String8& out, const char* what, uint32_t /* flags */) const
823{
824    const_iterator head = begin();
825    const_iterator const tail = end();
826
827    out.appendFormat("  Region %s (this=%p, count=%" PRIdPTR ")\n",
828            what, this, tail - head);
829    while (head != tail) {
830        out.appendFormat("    [%3d, %3d, %3d, %3d]\n", head->left, head->top,
831                head->right, head->bottom);
832        ++head;
833    }
834}
835
836void Region::dump(const char* what, uint32_t /* flags */) const
837{
838    const_iterator head = begin();
839    const_iterator const tail = end();
840    ALOGD("  Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail-head);
841    while (head != tail) {
842        ALOGD("    [%3d, %3d, %3d, %3d]\n",
843                head->left, head->top, head->right, head->bottom);
844        head++;
845    }
846}
847
848// ----------------------------------------------------------------------------
849
850}; // namespace android
851