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