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/Point.h>
27 #include <ui/Rect.h>
28 #include <ui/Region.h>
29 #include <ui/RegionHelper.h>
30 
31 // ----------------------------------------------------------------------------
32 
33 // ### VALIDATE_REGIONS ###
34 // To enable VALIDATE_REGIONS traces, use the "libui-validate-regions-defaults"
35 // in Android.bp. Do not #define VALIDATE_REGIONS here as it requires extra libs.
36 
37 #define VALIDATE_WITH_CORECG    (false)
38 // ----------------------------------------------------------------------------
39 
40 #if defined(VALIDATE_REGIONS)
41 #include <utils/CallStack.h>
42 #endif
43 
44 #if VALIDATE_WITH_CORECG
45 #include <core/SkRegion.h>
46 #endif
47 
48 namespace android {
49 // ----------------------------------------------------------------------------
50 
51 using base::StringAppendF;
52 
53 enum {
54     op_nand = region_operator<Rect>::op_nand,
55     op_and  = region_operator<Rect>::op_and,
56     op_or   = region_operator<Rect>::op_or,
57     op_xor  = region_operator<Rect>::op_xor
58 };
59 
60 enum {
61     direction_LTR,
62     direction_RTL
63 };
64 
65 const Region Region::INVALID_REGION(Rect::INVALID_RECT);
66 
67 // ----------------------------------------------------------------------------
68 
Region()69 Region::Region() {
70     mStorage.push_back(Rect(0, 0));
71 }
72 
Region(const Region & rhs)73 Region::Region(const Region& rhs)
74 {
75     mStorage.clear();
76     mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
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.push_back(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,FatVector<Rect> & dst,int spanDirection)104 static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, FatVector<Rect>& dst,
105                                            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.push_back(*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.push_back(Rect(prev.right, top, right, bottom));
152                     right = prev.right;
153                 }
154 
155                 if (prev.left > left && prev.left < right) {
156                     dst.push_back(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.push_back(Rect(left, top, prev.left, bottom));
171                     left = prev.left;
172                 }
173 
174                 if (prev.right > left && prev.right < right) {
175                     dst.push_back(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.push_back(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     FatVector<Rect> reversed;
206     reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL);
207 
208     Region outputRegion;
209     reverseRectsResolvingJunctions(reversed.data(), reversed.data() + reversed.size(),
210                                    outputRegion.mStorage, direction_LTR);
211     outputRegion.mStorage.push_back(
212             r.getBounds()); // to make region valid, mStorage must end with bounds
213 
214 #if defined(VALIDATE_REGIONS)
215     validate(outputRegion, "T-Junction free region");
216 #endif
217 
218     return outputRegion;
219 }
220 
operator =(const Region & rhs)221 Region& Region::operator = (const Region& rhs)
222 {
223 #if defined(VALIDATE_REGIONS)
224     validate(*this, "this->operator=");
225     validate(rhs, "rhs.operator=");
226 #endif
227     if (this == &rhs) {
228         // Already equal to itself
229         return *this;
230     }
231 
232     mStorage.clear();
233     mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
234     return *this;
235 }
236 
makeBoundsSelf()237 Region& Region::makeBoundsSelf()
238 {
239     if (mStorage.size() >= 2) {
240         const Rect bounds(getBounds());
241         mStorage.clear();
242         mStorage.push_back(bounds);
243     }
244     return *this;
245 }
246 
contains(const Point & point) const247 bool Region::contains(const Point& point) const {
248     return contains(point.x, point.y);
249 }
250 
contains(int x,int y) const251 bool Region::contains(int x, int y) const {
252     const_iterator cur = begin();
253     const_iterator const tail = end();
254     while (cur != tail) {
255         if (y >= cur->top && y < cur->bottom && x >= cur->left && x < cur->right) {
256             return true;
257         }
258         cur++;
259     }
260     return false;
261 }
262 
clear()263 void Region::clear()
264 {
265     mStorage.clear();
266     mStorage.push_back(Rect(0, 0));
267 }
268 
set(const Rect & r)269 void Region::set(const Rect& r)
270 {
271     mStorage.clear();
272     mStorage.push_back(r);
273 }
274 
set(int32_t w,int32_t h)275 void Region::set(int32_t w, int32_t h)
276 {
277     mStorage.clear();
278     mStorage.push_back(Rect(w, h));
279 }
280 
set(uint32_t w,uint32_t h)281 void Region::set(uint32_t w, uint32_t h)
282 {
283     mStorage.clear();
284     mStorage.push_back(Rect(w, h));
285 }
286 
isTriviallyEqual(const Region & region) const287 bool Region::isTriviallyEqual(const Region& region) const {
288     return begin() == region.begin();
289 }
290 
hasSameRects(const Region & other) const291 bool Region::hasSameRects(const Region& other) const {
292     size_t thisRectCount = 0;
293     android::Rect const* thisRects = getArray(&thisRectCount);
294     size_t otherRectCount = 0;
295     android::Rect const* otherRects = other.getArray(&otherRectCount);
296 
297     if (thisRectCount != otherRectCount) return false;
298 
299     for (size_t i = 0; i < thisRectCount; i++) {
300         if (thisRects[i] != otherRects[i]) return false;
301     }
302     return true;
303 }
304 
305 // ----------------------------------------------------------------------------
306 
addRectUnchecked(int l,int t,int r,int b)307 void Region::addRectUnchecked(int l, int t, int r, int b)
308 {
309     Rect rect(l,t,r,b);
310     mStorage.insert(mStorage.end() - 1, rect);
311 }
312 
313 // ----------------------------------------------------------------------------
314 
orSelf(const Rect & r)315 Region& Region::orSelf(const Rect& r) {
316     if (isEmpty()) {
317         set(r);
318         return *this;
319     }
320     return operationSelf(r, op_or);
321 }
xorSelf(const Rect & r)322 Region& Region::xorSelf(const Rect& r) {
323     return operationSelf(r, op_xor);
324 }
andSelf(const Rect & r)325 Region& Region::andSelf(const Rect& r) {
326     return operationSelf(r, op_and);
327 }
subtractSelf(const Rect & r)328 Region& Region::subtractSelf(const Rect& r) {
329     return operationSelf(r, op_nand);
330 }
operationSelf(const Rect & r,uint32_t op)331 Region& Region::operationSelf(const Rect& r, uint32_t op) {
332     Region lhs(*this);
333     boolean_operation(op, *this, lhs, r);
334     return *this;
335 }
336 
337 // ----------------------------------------------------------------------------
338 
orSelf(const Region & rhs)339 Region& Region::orSelf(const Region& rhs) {
340     if (isEmpty()) {
341         *this = rhs;
342         return *this;
343     }
344     return operationSelf(rhs, op_or);
345 }
xorSelf(const Region & rhs)346 Region& Region::xorSelf(const Region& rhs) {
347     return operationSelf(rhs, op_xor);
348 }
andSelf(const Region & rhs)349 Region& Region::andSelf(const Region& rhs) {
350     return operationSelf(rhs, op_and);
351 }
subtractSelf(const Region & rhs)352 Region& Region::subtractSelf(const Region& rhs) {
353     return operationSelf(rhs, op_nand);
354 }
operationSelf(const Region & rhs,uint32_t op)355 Region& Region::operationSelf(const Region& rhs, uint32_t op) {
356     Region lhs(*this);
357     boolean_operation(op, *this, lhs, rhs);
358     return *this;
359 }
360 
translateSelf(int x,int y)361 Region& Region::translateSelf(int x, int y) {
362     if (x|y) translate(*this, x, y);
363     return *this;
364 }
365 
scaleSelf(float sx,float sy)366 Region& Region::scaleSelf(float sx, float sy) {
367     size_t count = mStorage.size();
368     Rect* rects = mStorage.data();
369     while (count) {
370         rects->left = static_cast<int32_t>(static_cast<float>(rects->left) * sx + 0.5f);
371         rects->right = static_cast<int32_t>(static_cast<float>(rects->right) * sx + 0.5f);
372         rects->top = static_cast<int32_t>(static_cast<float>(rects->top) * sy + 0.5f);
373         rects->bottom = static_cast<int32_t>(static_cast<float>(rects->bottom) * sy + 0.5f);
374         rects++;
375         count--;
376     }
377     return *this;
378 }
379 
380 // ----------------------------------------------------------------------------
381 
merge(const Rect & rhs) const382 const Region Region::merge(const Rect& rhs) const {
383     return operation(rhs, op_or);
384 }
mergeExclusive(const Rect & rhs) const385 const Region Region::mergeExclusive(const Rect& rhs) const {
386     return operation(rhs, op_xor);
387 }
intersect(const Rect & rhs) const388 const Region Region::intersect(const Rect& rhs) const {
389     return operation(rhs, op_and);
390 }
subtract(const Rect & rhs) const391 const Region Region::subtract(const Rect& rhs) const {
392     return operation(rhs, op_nand);
393 }
operation(const Rect & rhs,uint32_t op) const394 const Region Region::operation(const Rect& rhs, uint32_t op) const {
395     Region result;
396     boolean_operation(op, result, *this, rhs);
397     return result;
398 }
399 
400 // ----------------------------------------------------------------------------
401 
merge(const Region & rhs) const402 const Region Region::merge(const Region& rhs) const {
403     return operation(rhs, op_or);
404 }
mergeExclusive(const Region & rhs) const405 const Region Region::mergeExclusive(const Region& rhs) const {
406     return operation(rhs, op_xor);
407 }
intersect(const Region & rhs) const408 const Region Region::intersect(const Region& rhs) const {
409     return operation(rhs, op_and);
410 }
subtract(const Region & rhs) const411 const Region Region::subtract(const Region& rhs) const {
412     return operation(rhs, op_nand);
413 }
operation(const Region & rhs,uint32_t op) const414 const Region Region::operation(const Region& rhs, uint32_t op) const {
415     Region result;
416     boolean_operation(op, result, *this, rhs);
417     return result;
418 }
419 
translate(int x,int y) const420 const Region Region::translate(int x, int y) const {
421     Region result;
422     translate(result, *this, x, y);
423     return result;
424 }
425 
426 // ----------------------------------------------------------------------------
427 
orSelf(const Region & rhs,int dx,int dy)428 Region& Region::orSelf(const Region& rhs, int dx, int dy) {
429     return operationSelf(rhs, dx, dy, op_or);
430 }
xorSelf(const Region & rhs,int dx,int dy)431 Region& Region::xorSelf(const Region& rhs, int dx, int dy) {
432     return operationSelf(rhs, dx, dy, op_xor);
433 }
andSelf(const Region & rhs,int dx,int dy)434 Region& Region::andSelf(const Region& rhs, int dx, int dy) {
435     return operationSelf(rhs, dx, dy, op_and);
436 }
subtractSelf(const Region & rhs,int dx,int dy)437 Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
438     return operationSelf(rhs, dx, dy, op_nand);
439 }
operationSelf(const Region & rhs,int dx,int dy,uint32_t op)440 Region& Region::operationSelf(const Region& rhs, int dx, int dy, uint32_t op) {
441     Region lhs(*this);
442     boolean_operation(op, *this, lhs, rhs, dx, dy);
443     return *this;
444 }
445 
446 // ----------------------------------------------------------------------------
447 
merge(const Region & rhs,int dx,int dy) const448 const Region Region::merge(const Region& rhs, int dx, int dy) const {
449     return operation(rhs, dx, dy, op_or);
450 }
mergeExclusive(const Region & rhs,int dx,int dy) const451 const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const {
452     return operation(rhs, dx, dy, op_xor);
453 }
intersect(const Region & rhs,int dx,int dy) const454 const Region Region::intersect(const Region& rhs, int dx, int dy) const {
455     return operation(rhs, dx, dy, op_and);
456 }
subtract(const Region & rhs,int dx,int dy) const457 const Region Region::subtract(const Region& rhs, int dx, int dy) const {
458     return operation(rhs, dx, dy, op_nand);
459 }
operation(const Region & rhs,int dx,int dy,uint32_t op) const460 const Region Region::operation(const Region& rhs, int dx, int dy, uint32_t op) const {
461     Region result;
462     boolean_operation(op, result, *this, rhs, dx, dy);
463     return result;
464 }
465 
466 // ----------------------------------------------------------------------------
467 
468 // This is our region rasterizer, which merges rects and spans together
469 // to obtain an optimal region.
470 class Region::rasterizer : public region_operator<Rect>::region_rasterizer
471 {
472     Rect bounds;
473     FatVector<Rect>& storage;
474     Rect* head;
475     Rect* tail;
476     FatVector<Rect> span;
477     Rect* cur;
478 public:
rasterizer(Region & reg)479     explicit rasterizer(Region& reg)
480         : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() {
481         storage.clear();
482     }
483 
484     virtual ~rasterizer();
485 
486     virtual void operator()(const Rect& rect);
487 
488 private:
489     template<typename T>
min(T rhs,T lhs)490     static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; }
491     template<typename T>
max(T rhs,T lhs)492     static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; }
493 
494     void flushSpan();
495 };
496 
~rasterizer()497 Region::rasterizer::~rasterizer()
498 {
499     if (span.size()) {
500         flushSpan();
501     }
502     if (storage.size()) {
503         bounds.top = storage.front().top;
504         bounds.bottom = storage.back().bottom;
505         if (storage.size() == 1) {
506             storage.clear();
507         }
508     } else {
509         bounds.left  = 0;
510         bounds.right = 0;
511     }
512     storage.push_back(bounds);
513 }
514 
operator ()(const Rect & rect)515 void Region::rasterizer::operator()(const Rect& rect)
516 {
517     //ALOGD(">>> %3d, %3d, %3d, %3d",
518     //        rect.left, rect.top, rect.right, rect.bottom);
519     if (span.size()) {
520         if (cur->top != rect.top) {
521             flushSpan();
522         } else if (cur->right == rect.left) {
523             cur->right = rect.right;
524             return;
525         }
526     }
527     span.push_back(rect);
528     cur = span.data() + (span.size() - 1);
529 }
530 
flushSpan()531 void Region::rasterizer::flushSpan()
532 {
533     bool merge = false;
534     if (tail-head == ssize_t(span.size())) {
535         Rect const* p = span.data();
536         Rect const* q = head;
537         if (p->top == q->bottom) {
538             merge = true;
539             while (q != tail) {
540                 if ((p->left != q->left) || (p->right != q->right)) {
541                     merge = false;
542                     break;
543                 }
544                 p++;
545                 q++;
546             }
547         }
548     }
549     if (merge) {
550         const int bottom = span.front().bottom;
551         Rect* r = head;
552         while (r != tail) {
553             r->bottom = bottom;
554             r++;
555         }
556     } else {
557         bounds.left = min(span.front().left, bounds.left);
558         bounds.right = max(span.back().right, bounds.right);
559         storage.insert(storage.end(), span.begin(), span.end());
560         tail = storage.data() + storage.size();
561         head = tail - span.size();
562     }
563     span.clear();
564 }
565 
validate(const Region & reg,const char * name,bool silent)566 bool Region::validate(const Region& reg, const char* name, bool silent)
567 {
568     if (reg.mStorage.empty()) {
569         ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name);
570         // return immediately as the code below assumes mStorage is non-empty
571         return false;
572     }
573 
574     bool result = true;
575     const_iterator cur = reg.begin();
576     const_iterator const tail = reg.end();
577     const_iterator prev = cur;
578     Rect b(*prev);
579     while (cur != tail) {
580         if (cur->isValid() == false) {
581             // We allow this particular flavor of invalid Rect, since it is used
582             // as a signal value in various parts of the system
583             if (*cur != Rect::INVALID_RECT) {
584                 ALOGE_IF(!silent, "%s: region contains an invalid Rect", name);
585                 result = false;
586             }
587         }
588         if (cur->right > region_operator<Rect>::max_value) {
589             ALOGE_IF(!silent, "%s: rect->right > max_value", name);
590             result = false;
591         }
592         if (cur->bottom > region_operator<Rect>::max_value) {
593             ALOGE_IF(!silent, "%s: rect->right > max_value", name);
594             result = false;
595         }
596         if (prev != cur) {
597             b.left   = b.left   < cur->left   ? b.left   : cur->left;
598             b.top    = b.top    < cur->top    ? b.top    : cur->top;
599             b.right  = b.right  > cur->right  ? b.right  : cur->right;
600             b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
601             if ((*prev < *cur) == false) {
602                 ALOGE_IF(!silent, "%s: region's Rects not sorted", name);
603                 result = false;
604             }
605             if (cur->top == prev->top) {
606                 if (cur->bottom != prev->bottom) {
607                     ALOGE_IF(!silent, "%s: invalid span %p", name, cur);
608                     result = false;
609                 } else if (cur->left < prev->right) {
610                     ALOGE_IF(!silent,
611                             "%s: spans overlap horizontally prev=%p, cur=%p",
612                             name, prev, cur);
613                     result = false;
614                 }
615             } else if (cur->top < prev->bottom) {
616                 ALOGE_IF(!silent,
617                         "%s: spans overlap vertically prev=%p, cur=%p",
618                         name, prev, cur);
619                 result = false;
620             }
621             prev = cur;
622         }
623         cur++;
624     }
625     if (b != reg.getBounds()) {
626         result = false;
627         ALOGE_IF(!silent,
628                 "%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
629                 b.left, b.top, b.right, b.bottom,
630                 reg.getBounds().left, reg.getBounds().top,
631                 reg.getBounds().right, reg.getBounds().bottom);
632     }
633     if (reg.mStorage.size() == 2) {
634         result = false;
635         ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name);
636     }
637 #if defined(VALIDATE_REGIONS)
638     if (result == false && !silent) {
639         reg.dump(name);
640         CallStack stack(LOG_TAG);
641     }
642 #endif
643     return result;
644 }
645 
boolean_operation(uint32_t op,Region & dst,const Region & lhs,const Region & rhs,int dx,int dy)646 void Region::boolean_operation(uint32_t op, Region& dst,
647         const Region& lhs,
648         const Region& rhs, int dx, int dy)
649 {
650 #if defined(VALIDATE_REGIONS)
651     validate(lhs, "boolean_operation (before): lhs");
652     validate(rhs, "boolean_operation (before): rhs");
653     validate(dst, "boolean_operation (before): dst");
654 #endif
655 
656     size_t lhs_count;
657     Rect const * const lhs_rects = lhs.getArray(&lhs_count);
658 
659     size_t rhs_count;
660     Rect const * const rhs_rects = rhs.getArray(&rhs_count);
661 
662     region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
663     region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy);
664     region_operator<Rect> operation(op, lhs_region, rhs_region);
665     { // scope for rasterizer (dtor has side effects)
666         rasterizer r(dst);
667         operation(r);
668     }
669 
670 #if defined(VALIDATE_REGIONS)
671     validate(lhs, "boolean_operation: lhs");
672     validate(rhs, "boolean_operation: rhs");
673     validate(dst, "boolean_operation: dst");
674 #endif
675 
676 #if VALIDATE_WITH_CORECG
677     SkRegion sk_lhs;
678     SkRegion sk_rhs;
679     SkRegion sk_dst;
680 
681     for (size_t i=0 ; i<lhs_count ; i++)
682         sk_lhs.op(
683                 lhs_rects[i].left   + dx,
684                 lhs_rects[i].top    + dy,
685                 lhs_rects[i].right  + dx,
686                 lhs_rects[i].bottom + dy,
687                 SkRegion::kUnion_Op);
688 
689     for (size_t i=0 ; i<rhs_count ; i++)
690         sk_rhs.op(
691                 rhs_rects[i].left   + dx,
692                 rhs_rects[i].top    + dy,
693                 rhs_rects[i].right  + dx,
694                 rhs_rects[i].bottom + dy,
695                 SkRegion::kUnion_Op);
696 
697     const char* name = "---";
698     SkRegion::Op sk_op;
699     switch (op) {
700         case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
701         case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break;
702         case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
703         case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
704     }
705     sk_dst.op(sk_lhs, sk_rhs, sk_op);
706 
707     if (sk_dst.empty() && dst.empty()) return;
708 
709     bool same = true;
710     Region::const_iterator head = dst.begin();
711     Region::const_iterator const tail = dst.end();
712     SkRegion::Iterator it(sk_dst);
713     while (!it.done()) {
714         if (head != tail) {
715             if (
716                     head->left != it.rect().fLeft ||
717                     head->top != it.rect().fTop ||
718                     head->right != it.rect().fRight ||
719                     head->bottom != it.rect().fBottom
720             ) {
721                 same = false;
722                 break;
723             }
724         } else {
725             same = false;
726             break;
727         }
728         head++;
729         it.next();
730     }
731 
732     if (head != tail) {
733         same = false;
734     }
735 
736     if(!same) {
737         ALOGD("---\nregion boolean %s failed", name);
738         lhs.dump("lhs");
739         rhs.dump("rhs");
740         dst.dump("dst");
741         ALOGD("should be");
742         SkRegion::Iterator it(sk_dst);
743         while (!it.done()) {
744             ALOGD("    [%3d, %3d, %3d, %3d]",
745                 it.rect().fLeft,
746                 it.rect().fTop,
747                 it.rect().fRight,
748                 it.rect().fBottom);
749             it.next();
750         }
751     }
752 #endif
753 }
754 
boolean_operation(uint32_t op,Region & dst,const Region & lhs,const Rect & rhs,int dx,int dy)755 void Region::boolean_operation(uint32_t op, Region& dst,
756         const Region& lhs,
757         const Rect& rhs, int dx, int dy)
758 {
759     // We allow this particular flavor of invalid Rect, since it is used as a
760     // signal value in various parts of the system
761     if (!rhs.isValid() && rhs != Rect::INVALID_RECT) {
762         ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}",
763                 op, rhs.left, rhs.top, rhs.right, rhs.bottom);
764         return;
765     }
766 
767 #if VALIDATE_WITH_CORECG || defined(VALIDATE_REGIONS)
768     boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
769 #else
770     size_t lhs_count;
771     Rect const * const lhs_rects = lhs.getArray(&lhs_count);
772 
773     region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
774     region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy);
775     region_operator<Rect> operation(op, lhs_region, rhs_region);
776     { // scope for rasterizer (dtor has side effects)
777         rasterizer r(dst);
778         operation(r);
779     }
780 
781 #endif
782 }
783 
boolean_operation(uint32_t op,Region & dst,const Region & lhs,const Region & rhs)784 void Region::boolean_operation(uint32_t op, Region& dst,
785         const Region& lhs, const Region& rhs)
786 {
787     boolean_operation(op, dst, lhs, rhs, 0, 0);
788 }
789 
boolean_operation(uint32_t op,Region & dst,const Region & lhs,const Rect & rhs)790 void Region::boolean_operation(uint32_t op, Region& dst,
791         const Region& lhs, const Rect& rhs)
792 {
793     boolean_operation(op, dst, lhs, rhs, 0, 0);
794 }
795 
translate(Region & reg,int dx,int dy)796 void Region::translate(Region& reg, int dx, int dy)
797 {
798     if ((dx || dy) && !reg.isEmpty()) {
799 #if defined(VALIDATE_REGIONS)
800         validate(reg, "translate (before)");
801 #endif
802         size_t count = reg.mStorage.size();
803         Rect* rects = reg.mStorage.data();
804         while (count) {
805             rects->offsetBy(dx, dy);
806             rects++;
807             count--;
808         }
809 #if defined(VALIDATE_REGIONS)
810         validate(reg, "translate (after)");
811 #endif
812     }
813 }
814 
translate(Region & dst,const Region & reg,int dx,int dy)815 void Region::translate(Region& dst, const Region& reg, int dx, int dy)
816 {
817     dst = reg;
818     translate(dst, dx, dy);
819 }
820 
821 // ----------------------------------------------------------------------------
822 
getFlattenedSize() const823 size_t Region::getFlattenedSize() const {
824     return sizeof(uint32_t) + mStorage.size() * sizeof(Rect);
825 }
826 
flatten(void * buffer,size_t size) const827 status_t Region::flatten(void* buffer, size_t size) const {
828 #if defined(VALIDATE_REGIONS)
829     validate(*this, "Region::flatten");
830 #endif
831     if (size < getFlattenedSize()) {
832         return NO_MEMORY;
833     }
834     // Cast to uint32_t since the size of a size_t can vary between 32- and
835     // 64-bit processes
836     FlattenableUtils::write(buffer, size, static_cast<uint32_t>(mStorage.size()));
837     for (auto rect : mStorage) {
838         status_t result = rect.flatten(buffer, size);
839         if (result != NO_ERROR) {
840             return result;
841         }
842         FlattenableUtils::advance(buffer, size, sizeof(rect));
843     }
844     return NO_ERROR;
845 }
846 
unflatten(void const * buffer,size_t size)847 status_t Region::unflatten(void const* buffer, size_t size) {
848     if (size < sizeof(uint32_t)) {
849         return NO_MEMORY;
850     }
851 
852     uint32_t numRects = 0;
853     FlattenableUtils::read(buffer, size, numRects);
854     if (size < numRects * sizeof(Rect)) {
855         return NO_MEMORY;
856     }
857 
858     if (numRects > (UINT32_MAX / sizeof(Rect))) {
859         android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, nullptr, 0);
860         return NO_MEMORY;
861     }
862 
863     Region result;
864     result.mStorage.clear();
865     for (size_t r = 0; r < numRects; ++r) {
866         Rect rect(Rect::EMPTY_RECT);
867         status_t status = rect.unflatten(buffer, size);
868         if (status != NO_ERROR) {
869             return status;
870         }
871         FlattenableUtils::advance(buffer, size, sizeof(rect));
872         result.mStorage.push_back(rect);
873     }
874 
875 #if defined(VALIDATE_REGIONS)
876     validate(result, "Region::unflatten");
877 #endif
878 
879     if (!result.validate(result, "Region::unflatten", true)) {
880         ALOGE("Region::unflatten() failed, invalid region");
881         return BAD_VALUE;
882     }
883     mStorage.clear();
884     mStorage.insert(mStorage.begin(), result.mStorage.begin(), result.mStorage.end());
885     return NO_ERROR;
886 }
887 
888 // ----------------------------------------------------------------------------
889 
begin() const890 Region::const_iterator Region::begin() const {
891     return mStorage.data();
892 }
893 
end() const894 Region::const_iterator Region::end() const {
895     // Workaround for b/77643177
896     // mStorage should never be empty, but somehow it is and it's causing
897     // an abort in ubsan
898     if (mStorage.empty()) return mStorage.data();
899 
900     size_t numRects = isRect() ? 1 : mStorage.size() - 1;
901     return mStorage.data() + numRects;
902 }
903 
getArray(size_t * count) const904 Rect const* Region::getArray(size_t* count) const {
905     if (count) *count = static_cast<size_t>(end() - begin());
906     return begin();
907 }
908 
909 // ----------------------------------------------------------------------------
910 
dump(std::string & out,const char * what,uint32_t) const911 void Region::dump(std::string& out, const char* what, uint32_t /* flags */) const {
912     const_iterator head = begin();
913     const_iterator const tail = end();
914 
915     StringAppendF(&out, "  Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail - head);
916     while (head != tail) {
917         StringAppendF(&out, "    [%3d, %3d, %3d, %3d]\n", head->left, head->top, head->right,
918                       head->bottom);
919         ++head;
920     }
921 }
922 
dump(const char * what,uint32_t) const923 void Region::dump(const char* what, uint32_t /* flags */) const
924 {
925     const_iterator head = begin();
926     const_iterator const tail = end();
927     ALOGD("  Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail-head);
928     while (head != tail) {
929         ALOGD("    [%3d, %3d, %3d, %3d]\n",
930                 head->left, head->top, head->right, head->bottom);
931         head++;
932     }
933 }
934 
935 // ----------------------------------------------------------------------------
936 
937 }; // namespace android
938