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