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