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