• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
Region()58 Region::Region() {
59     mStorage.add(Rect(0,0));
60 }
61 
Region(const Region & rhs)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 
Region(const Rect & rhs)70 Region::Region(const Rect& rhs) {
71     mStorage.add(rhs);
72 }
73 
~Region()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  */
reverseRectsResolvingJunctions(const Rect * begin,const Rect * end,Vector<Rect> & dst,int spanDirection)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  */
createTJunctionFreeRegion(const Region & r)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 
operator =(const Region & rhs)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 
makeBoundsSelf()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 
contains(const Point & point) const225 bool Region::contains(const Point& point) const {
226     return contains(point.x, point.y);
227 }
228 
contains(int x,int y) const229 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 
clear()241 void Region::clear()
242 {
243     mStorage.clear();
244     mStorage.add(Rect(0,0));
245 }
246 
set(const Rect & r)247 void Region::set(const Rect& r)
248 {
249     mStorage.clear();
250     mStorage.add(r);
251 }
252 
set(uint32_t w,uint32_t h)253 void Region::set(uint32_t w, uint32_t h)
254 {
255     mStorage.clear();
256     mStorage.add(Rect(w,h));
257 }
258 
isTriviallyEqual(const Region & region) const259 bool Region::isTriviallyEqual(const Region& region) const {
260     return begin() == region.begin();
261 }
262 
263 // ----------------------------------------------------------------------------
264 
addRectUnchecked(int l,int t,int r,int b)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 
orSelf(const Rect & r)274 Region& Region::orSelf(const Rect& r) {
275     return operationSelf(r, op_or);
276 }
xorSelf(const Rect & r)277 Region& Region::xorSelf(const Rect& r) {
278     return operationSelf(r, op_xor);
279 }
andSelf(const Rect & r)280 Region& Region::andSelf(const Rect& r) {
281     return operationSelf(r, op_and);
282 }
subtractSelf(const Rect & r)283 Region& Region::subtractSelf(const Rect& r) {
284     return operationSelf(r, op_nand);
285 }
operationSelf(const Rect & r,int op)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 
orSelf(const Region & rhs)294 Region& Region::orSelf(const Region& rhs) {
295     return operationSelf(rhs, op_or);
296 }
xorSelf(const Region & rhs)297 Region& Region::xorSelf(const Region& rhs) {
298     return operationSelf(rhs, op_xor);
299 }
andSelf(const Region & rhs)300 Region& Region::andSelf(const Region& rhs) {
301     return operationSelf(rhs, op_and);
302 }
subtractSelf(const Region & rhs)303 Region& Region::subtractSelf(const Region& rhs) {
304     return operationSelf(rhs, op_nand);
305 }
operationSelf(const Region & rhs,int op)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 
translateSelf(int x,int y)312 Region& Region::translateSelf(int x, int y) {
313     if (x|y) translate(*this, x, y);
314     return *this;
315 }
316 
317 // ----------------------------------------------------------------------------
318 
merge(const Rect & rhs) const319 const Region Region::merge(const Rect& rhs) const {
320     return operation(rhs, op_or);
321 }
mergeExclusive(const Rect & rhs) const322 const Region Region::mergeExclusive(const Rect& rhs) const {
323     return operation(rhs, op_xor);
324 }
intersect(const Rect & rhs) const325 const Region Region::intersect(const Rect& rhs) const {
326     return operation(rhs, op_and);
327 }
subtract(const Rect & rhs) const328 const Region Region::subtract(const Rect& rhs) const {
329     return operation(rhs, op_nand);
330 }
operation(const Rect & rhs,int op) const331 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 
merge(const Region & rhs) const339 const Region Region::merge(const Region& rhs) const {
340     return operation(rhs, op_or);
341 }
mergeExclusive(const Region & rhs) const342 const Region Region::mergeExclusive(const Region& rhs) const {
343     return operation(rhs, op_xor);
344 }
intersect(const Region & rhs) const345 const Region Region::intersect(const Region& rhs) const {
346     return operation(rhs, op_and);
347 }
subtract(const Region & rhs) const348 const Region Region::subtract(const Region& rhs) const {
349     return operation(rhs, op_nand);
350 }
operation(const Region & rhs,int op) const351 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 
translate(int x,int y) const357 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 
orSelf(const Region & rhs,int dx,int dy)365 Region& Region::orSelf(const Region& rhs, int dx, int dy) {
366     return operationSelf(rhs, dx, dy, op_or);
367 }
xorSelf(const Region & rhs,int dx,int dy)368 Region& Region::xorSelf(const Region& rhs, int dx, int dy) {
369     return operationSelf(rhs, dx, dy, op_xor);
370 }
andSelf(const Region & rhs,int dx,int dy)371 Region& Region::andSelf(const Region& rhs, int dx, int dy) {
372     return operationSelf(rhs, dx, dy, op_and);
373 }
subtractSelf(const Region & rhs,int dx,int dy)374 Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
375     return operationSelf(rhs, dx, dy, op_nand);
376 }
operationSelf(const Region & rhs,int dx,int dy,int op)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 
merge(const Region & rhs,int dx,int dy) const385 const Region Region::merge(const Region& rhs, int dx, int dy) const {
386     return operation(rhs, dx, dy, op_or);
387 }
mergeExclusive(const Region & rhs,int dx,int dy) const388 const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const {
389     return operation(rhs, dx, dy, op_xor);
390 }
intersect(const Region & rhs,int dx,int dy) const391 const Region Region::intersect(const Region& rhs, int dx, int dy) const {
392     return operation(rhs, dx, dy, op_and);
393 }
subtract(const Region & rhs,int dx,int dy) const394 const Region Region::subtract(const Region& rhs, int dx, int dy) const {
395     return operation(rhs, dx, dy, op_nand);
396 }
operation(const Region & rhs,int dx,int dy,int op) const397 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:
rasterizer(Region & reg)416     rasterizer(Region& reg)
417         : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() {
418         storage.clear();
419     }
420 
~rasterizer()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 
operator ()(const Rect & rect)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>
min(T rhs,T lhs)454     static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; }
455     template<typename T>
max(T rhs,T lhs)456     static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; }
flushSpan()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 
validate(const Region & reg,const char * name,bool silent)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 
boolean_operation(int op,Region & dst,const Region & lhs,const Region & rhs,int dx,int dy)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 
boolean_operation(int op,Region & dst,const Region & lhs,const Rect & rhs,int dx,int dy)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 
boolean_operation(int op,Region & dst,const Region & lhs,const Region & rhs)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 
boolean_operation(int op,Region & dst,const Region & lhs,const Rect & rhs)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 
translate(Region & reg,int dx,int dy)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 
translate(Region & dst,const Region & reg,int dx,int dy)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 
getFlattenedSize() const735 size_t Region::getFlattenedSize() const {
736     return mStorage.size() * sizeof(Rect);
737 }
738 
flatten(void * buffer,size_t size) const739 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 
unflatten(void const * buffer,size_t size)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 
begin() const779 Region::const_iterator Region::begin() const {
780     return mStorage.array();
781 }
782 
end() const783 Region::const_iterator Region::end() const {
784     size_t numRects = isRect() ? 1 : mStorage.size() - 1;
785     return mStorage.array() + numRects;
786 }
787 
getArray(size_t * count) const788 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 
getSharedBuffer(size_t * count) const795 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 
dump(String8 & out,const char * what,uint32_t flags) const809 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 
dump(const char * what,uint32_t flags) const829 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