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