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
24 #include <ui/Rect.h>
25 #include <ui/Region.h>
26 #include <ui/Point.h>
27
28 #include <private/ui/RegionHelper.h>
29
30 // ----------------------------------------------------------------------------
31 #define VALIDATE_REGIONS (false)
32 #define VALIDATE_WITH_CORECG (false)
33 // ----------------------------------------------------------------------------
34
35 #if VALIDATE_WITH_CORECG
36 #include <core/SkRegion.h>
37 #endif
38
39 namespace android {
40 // ----------------------------------------------------------------------------
41
42 enum {
43 op_nand = region_operator<Rect>::op_nand,
44 op_and = region_operator<Rect>::op_and,
45 op_or = region_operator<Rect>::op_or,
46 op_xor = region_operator<Rect>::op_xor
47 };
48
49 // ----------------------------------------------------------------------------
50
Region()51 Region::Region()
52 : mBounds(0,0)
53 {
54 }
55
Region(const Region & rhs)56 Region::Region(const Region& rhs)
57 : mBounds(rhs.mBounds), mStorage(rhs.mStorage)
58 {
59 }
60
Region(const Rect & rhs)61 Region::Region(const Rect& rhs)
62 : mBounds(rhs)
63 {
64 }
65
Region(const void * buffer)66 Region::Region(const void* buffer)
67 {
68 status_t err = read(buffer);
69 LOGE_IF(err<0, "error %s reading Region from buffer", strerror(err));
70 }
71
~Region()72 Region::~Region()
73 {
74 }
75
operator =(const Region & rhs)76 Region& Region::operator = (const Region& rhs)
77 {
78 #if VALIDATE_REGIONS
79 validate(rhs, "operator=");
80 #endif
81 mBounds = rhs.mBounds;
82 mStorage = rhs.mStorage;
83 return *this;
84 }
85
makeBoundsSelf()86 Region& Region::makeBoundsSelf()
87 {
88 mStorage.clear();
89 return *this;
90 }
91
clear()92 void Region::clear()
93 {
94 mBounds.clear();
95 mStorage.clear();
96 }
97
set(const Rect & r)98 void Region::set(const Rect& r)
99 {
100 mBounds = r;
101 mStorage.clear();
102 }
103
set(uint32_t w,uint32_t h)104 void Region::set(uint32_t w, uint32_t h)
105 {
106 mBounds = Rect(int(w), int(h));
107 mStorage.clear();
108 }
109
110 // ----------------------------------------------------------------------------
111
addRectUnchecked(int l,int t,int r,int b)112 void Region::addRectUnchecked(int l, int t, int r, int b)
113 {
114 mStorage.add(Rect(l,t,r,b));
115 #if VALIDATE_REGIONS
116 validate(*this, "addRectUnchecked");
117 #endif
118 }
119
120 // ----------------------------------------------------------------------------
121
orSelf(const Rect & r)122 Region& Region::orSelf(const Rect& r) {
123 return operationSelf(r, op_or);
124 }
andSelf(const Rect & r)125 Region& Region::andSelf(const Rect& r) {
126 return operationSelf(r, op_and);
127 }
subtractSelf(const Rect & r)128 Region& Region::subtractSelf(const Rect& r) {
129 return operationSelf(r, op_nand);
130 }
operationSelf(const Rect & r,int op)131 Region& Region::operationSelf(const Rect& r, int op) {
132 Region lhs(*this);
133 boolean_operation(op, *this, lhs, r);
134 return *this;
135 }
136
137 // ----------------------------------------------------------------------------
138
orSelf(const Region & rhs)139 Region& Region::orSelf(const Region& rhs) {
140 return operationSelf(rhs, op_or);
141 }
andSelf(const Region & rhs)142 Region& Region::andSelf(const Region& rhs) {
143 return operationSelf(rhs, op_and);
144 }
subtractSelf(const Region & rhs)145 Region& Region::subtractSelf(const Region& rhs) {
146 return operationSelf(rhs, op_nand);
147 }
operationSelf(const Region & rhs,int op)148 Region& Region::operationSelf(const Region& rhs, int op) {
149 Region lhs(*this);
150 boolean_operation(op, *this, lhs, rhs);
151 return *this;
152 }
153
translateSelf(int x,int y)154 Region& Region::translateSelf(int x, int y) {
155 if (x|y) translate(*this, x, y);
156 return *this;
157 }
158
159 // ----------------------------------------------------------------------------
160
merge(const Rect & rhs) const161 const Region Region::merge(const Rect& rhs) const {
162 return operation(rhs, op_or);
163 }
intersect(const Rect & rhs) const164 const Region Region::intersect(const Rect& rhs) const {
165 return operation(rhs, op_and);
166 }
subtract(const Rect & rhs) const167 const Region Region::subtract(const Rect& rhs) const {
168 return operation(rhs, op_nand);
169 }
operation(const Rect & rhs,int op) const170 const Region Region::operation(const Rect& rhs, int op) const {
171 Region result;
172 boolean_operation(op, result, *this, rhs);
173 return result;
174 }
175
176 // ----------------------------------------------------------------------------
177
merge(const Region & rhs) const178 const Region Region::merge(const Region& rhs) const {
179 return operation(rhs, op_or);
180 }
intersect(const Region & rhs) const181 const Region Region::intersect(const Region& rhs) const {
182 return operation(rhs, op_and);
183 }
subtract(const Region & rhs) const184 const Region Region::subtract(const Region& rhs) const {
185 return operation(rhs, op_nand);
186 }
operation(const Region & rhs,int op) const187 const Region Region::operation(const Region& rhs, int op) const {
188 Region result;
189 boolean_operation(op, result, *this, rhs);
190 return result;
191 }
192
translate(int x,int y) const193 const Region Region::translate(int x, int y) const {
194 Region result;
195 translate(result, *this, x, y);
196 return result;
197 }
198
199 // ----------------------------------------------------------------------------
200
orSelf(const Region & rhs,int dx,int dy)201 Region& Region::orSelf(const Region& rhs, int dx, int dy) {
202 return operationSelf(rhs, dx, dy, op_or);
203 }
andSelf(const Region & rhs,int dx,int dy)204 Region& Region::andSelf(const Region& rhs, int dx, int dy) {
205 return operationSelf(rhs, dx, dy, op_and);
206 }
subtractSelf(const Region & rhs,int dx,int dy)207 Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
208 return operationSelf(rhs, dx, dy, op_nand);
209 }
operationSelf(const Region & rhs,int dx,int dy,int op)210 Region& Region::operationSelf(const Region& rhs, int dx, int dy, int op) {
211 Region lhs(*this);
212 boolean_operation(op, *this, lhs, rhs, dx, dy);
213 return *this;
214 }
215
216 // ----------------------------------------------------------------------------
217
merge(const Region & rhs,int dx,int dy) const218 const Region Region::merge(const Region& rhs, int dx, int dy) const {
219 return operation(rhs, dx, dy, op_or);
220 }
intersect(const Region & rhs,int dx,int dy) const221 const Region Region::intersect(const Region& rhs, int dx, int dy) const {
222 return operation(rhs, dx, dy, op_and);
223 }
subtract(const Region & rhs,int dx,int dy) const224 const Region Region::subtract(const Region& rhs, int dx, int dy) const {
225 return operation(rhs, dx, dy, op_nand);
226 }
operation(const Region & rhs,int dx,int dy,int op) const227 const Region Region::operation(const Region& rhs, int dx, int dy, int op) const {
228 Region result;
229 boolean_operation(op, result, *this, rhs, dx, dy);
230 return result;
231 }
232
233 // ----------------------------------------------------------------------------
234
235 // This is our region rasterizer, which merges rects and spans together
236 // to obtain an optimal region.
237 class Region::rasterizer : public region_operator<Rect>::region_rasterizer
238 {
239 Rect& bounds;
240 Vector<Rect>& storage;
241 Rect* head;
242 Rect* tail;
243 Vector<Rect> span;
244 Rect* cur;
245 public:
rasterizer(Region & reg)246 rasterizer(Region& reg)
247 : bounds(reg.mBounds), storage(reg.mStorage), head(), tail(), cur() {
248 bounds.top = bounds.bottom = 0;
249 bounds.left = INT_MAX;
250 bounds.right = INT_MIN;
251 storage.clear();
252 }
253
~rasterizer()254 ~rasterizer() {
255 if (span.size()) {
256 flushSpan();
257 }
258 if (storage.size()) {
259 bounds.top = storage.itemAt(0).top;
260 bounds.bottom = storage.top().bottom;
261 if (storage.size() == 1) {
262 storage.clear();
263 }
264 } else {
265 bounds.left = 0;
266 bounds.right = 0;
267 }
268 }
269
operator ()(const Rect & rect)270 virtual void operator()(const Rect& rect) {
271 //LOGD(">>> %3d, %3d, %3d, %3d",
272 // rect.left, rect.top, rect.right, rect.bottom);
273 if (span.size()) {
274 if (cur->top != rect.top) {
275 flushSpan();
276 } else if (cur->right == rect.left) {
277 cur->right = rect.right;
278 return;
279 }
280 }
281 span.add(rect);
282 cur = span.editArray() + (span.size() - 1);
283 }
284 private:
285 template<typename T>
min(T rhs,T lhs)286 static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; }
287 template<typename T>
max(T rhs,T lhs)288 static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; }
flushSpan()289 void flushSpan() {
290 bool merge = false;
291 if (tail-head == ssize_t(span.size())) {
292 Rect const* p = span.editArray();
293 Rect const* q = head;
294 if (p->top == q->bottom) {
295 merge = true;
296 while (q != tail) {
297 if ((p->left != q->left) || (p->right != q->right)) {
298 merge = false;
299 break;
300 }
301 p++, q++;
302 }
303 }
304 }
305 if (merge) {
306 const int bottom = span[0].bottom;
307 Rect* r = head;
308 while (r != tail) {
309 r->bottom = bottom;
310 r++;
311 }
312 } else {
313 bounds.left = min(span.itemAt(0).left, bounds.left);
314 bounds.right = max(span.top().right, bounds.right);
315 storage.appendVector(span);
316 tail = storage.editArray() + storage.size();
317 head = tail - span.size();
318 }
319 span.clear();
320 }
321 };
322
validate(const Region & reg,const char * name)323 bool Region::validate(const Region& reg, const char* name)
324 {
325 bool result = true;
326 const_iterator cur = reg.begin();
327 const_iterator const tail = reg.end();
328 const_iterator prev = cur++;
329 Rect b(*prev);
330 while (cur != tail) {
331 b.left = b.left < cur->left ? b.left : cur->left;
332 b.top = b.top < cur->top ? b.top : cur->top;
333 b.right = b.right > cur->right ? b.right : cur->right;
334 b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
335 if (cur->top == prev->top) {
336 if (cur->bottom != prev->bottom) {
337 LOGE("%s: invalid span %p", name, cur);
338 result = false;
339 } else if (cur->left < prev->right) {
340 LOGE("%s: spans overlap horizontally prev=%p, cur=%p",
341 name, prev, cur);
342 result = false;
343 }
344 } else if (cur->top < prev->bottom) {
345 LOGE("%s: spans overlap vertically prev=%p, cur=%p",
346 name, prev, cur);
347 result = false;
348 }
349 prev = cur;
350 cur++;
351 }
352 if (b != reg.getBounds()) {
353 result = false;
354 LOGE("%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
355 b.left, b.top, b.right, b.bottom,
356 reg.getBounds().left, reg.getBounds().top,
357 reg.getBounds().right, reg.getBounds().bottom);
358 }
359 if (result == false) {
360 reg.dump(name);
361 }
362 return result;
363 }
364
boolean_operation(int op,Region & dst,const Region & lhs,const Region & rhs,int dx,int dy)365 void Region::boolean_operation(int op, Region& dst,
366 const Region& lhs,
367 const Region& rhs, int dx, int dy)
368 {
369 size_t lhs_count;
370 Rect const * const lhs_rects = lhs.getArray(&lhs_count);
371
372 size_t rhs_count;
373 Rect const * const rhs_rects = rhs.getArray(&rhs_count);
374
375 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
376 region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy);
377 region_operator<Rect> operation(op, lhs_region, rhs_region);
378 { // scope for rasterizer (dtor has side effects)
379 rasterizer r(dst);
380 operation(r);
381 }
382
383 #if VALIDATE_REGIONS
384 validate(lhs, "boolean_operation: lhs");
385 validate(rhs, "boolean_operation: rhs");
386 validate(dst, "boolean_operation: dst");
387 #endif
388
389 #if VALIDATE_WITH_CORECG
390 SkRegion sk_lhs;
391 SkRegion sk_rhs;
392 SkRegion sk_dst;
393
394 for (size_t i=0 ; i<lhs_count ; i++)
395 sk_lhs.op(
396 lhs_rects[i].left + dx,
397 lhs_rects[i].top + dy,
398 lhs_rects[i].right + dx,
399 lhs_rects[i].bottom + dy,
400 SkRegion::kUnion_Op);
401
402 for (size_t i=0 ; i<rhs_count ; i++)
403 sk_rhs.op(
404 rhs_rects[i].left + dx,
405 rhs_rects[i].top + dy,
406 rhs_rects[i].right + dx,
407 rhs_rects[i].bottom + dy,
408 SkRegion::kUnion_Op);
409
410 const char* name = "---";
411 SkRegion::Op sk_op;
412 switch (op) {
413 case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
414 case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
415 case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
416 }
417 sk_dst.op(sk_lhs, sk_rhs, sk_op);
418
419 if (sk_dst.isEmpty() && dst.isEmpty())
420 return;
421
422 bool same = true;
423 Region::const_iterator head = dst.begin();
424 Region::const_iterator const tail = dst.end();
425 SkRegion::Iterator it(sk_dst);
426 while (!it.done()) {
427 if (head != tail) {
428 if (
429 head->left != it.rect().fLeft ||
430 head->top != it.rect().fTop ||
431 head->right != it.rect().fRight ||
432 head->bottom != it.rect().fBottom
433 ) {
434 same = false;
435 break;
436 }
437 } else {
438 same = false;
439 break;
440 }
441 head++;
442 it.next();
443 }
444
445 if (head != tail) {
446 same = false;
447 }
448
449 if(!same) {
450 LOGD("---\nregion boolean %s failed", name);
451 lhs.dump("lhs");
452 rhs.dump("rhs");
453 dst.dump("dst");
454 LOGD("should be");
455 SkRegion::Iterator it(sk_dst);
456 while (!it.done()) {
457 LOGD(" [%3d, %3d, %3d, %3d]",
458 it.rect().fLeft,
459 it.rect().fTop,
460 it.rect().fRight,
461 it.rect().fBottom);
462 it.next();
463 }
464 }
465 #endif
466 }
467
boolean_operation(int op,Region & dst,const Region & lhs,const Rect & rhs,int dx,int dy)468 void Region::boolean_operation(int op, Region& dst,
469 const Region& lhs,
470 const Rect& rhs, int dx, int dy)
471 {
472 #if VALIDATE_WITH_CORECG || VALIDATE_REGIONS
473 boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
474 #else
475 size_t lhs_count;
476 Rect const * const lhs_rects = lhs.getArray(&lhs_count);
477
478 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
479 region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy);
480 region_operator<Rect> operation(op, lhs_region, rhs_region);
481 { // scope for rasterizer (dtor has side effects)
482 rasterizer r(dst);
483 operation(r);
484 }
485
486 #endif
487 }
488
boolean_operation(int op,Region & dst,const Region & lhs,const Region & rhs)489 void Region::boolean_operation(int op, Region& dst,
490 const Region& lhs, const Region& rhs)
491 {
492 boolean_operation(op, dst, lhs, rhs, 0, 0);
493 }
494
boolean_operation(int op,Region & dst,const Region & lhs,const Rect & rhs)495 void Region::boolean_operation(int op, Region& dst,
496 const Region& lhs, const Rect& rhs)
497 {
498 boolean_operation(op, dst, lhs, rhs, 0, 0);
499 }
500
translate(Region & reg,int dx,int dy)501 void Region::translate(Region& reg, int dx, int dy)
502 {
503 if (!reg.isEmpty()) {
504 #if VALIDATE_REGIONS
505 validate(reg, "translate (before)");
506 #endif
507 reg.mBounds.translate(dx, dy);
508 size_t count = reg.mStorage.size();
509 Rect* rects = reg.mStorage.editArray();
510 while (count) {
511 rects->translate(dx, dy);
512 rects++;
513 count--;
514 }
515 #if VALIDATE_REGIONS
516 validate(reg, "translate (after)");
517 #endif
518 }
519 }
520
translate(Region & dst,const Region & reg,int dx,int dy)521 void Region::translate(Region& dst, const Region& reg, int dx, int dy)
522 {
523 dst = reg;
524 translate(dst, dx, dy);
525 }
526
527 // ----------------------------------------------------------------------------
528
write(void * buffer,size_t size) const529 ssize_t Region::write(void* buffer, size_t size) const
530 {
531 #if VALIDATE_REGIONS
532 validate(*this, "write(buffer)");
533 #endif
534 const size_t count = mStorage.size();
535 const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
536 if (buffer != NULL) {
537 if (sizeNeeded > size) return NO_MEMORY;
538 int32_t* const p = static_cast<int32_t*>(buffer);
539 *p = count;
540 memcpy(p+1, &mBounds, sizeof(Rect));
541 if (count) {
542 memcpy(p+5, mStorage.array(), count*sizeof(Rect));
543 }
544 }
545 return ssize_t(sizeNeeded);
546 }
547
read(const void * buffer)548 ssize_t Region::read(const void* buffer)
549 {
550 int32_t const* const p = static_cast<int32_t const*>(buffer);
551 const size_t count = *p;
552 memcpy(&mBounds, p+1, sizeof(Rect));
553 mStorage.clear();
554 if (count) {
555 mStorage.insertAt(0, count);
556 memcpy(mStorage.editArray(), p+5, count*sizeof(Rect));
557 }
558 #if VALIDATE_REGIONS
559 validate(*this, "read(buffer)");
560 #endif
561 return ssize_t(sizeof(int32_t) + (1+count)*sizeof(Rect));
562 }
563
writeEmpty(void * buffer,size_t size)564 ssize_t Region::writeEmpty(void* buffer, size_t size)
565 {
566 const size_t sizeNeeded = sizeof(int32_t) + sizeof(Rect);
567 if (sizeNeeded > size) return NO_MEMORY;
568 int32_t* const p = static_cast<int32_t*>(buffer);
569 memset(p, 0, sizeNeeded);
570 return ssize_t(sizeNeeded);
571 }
572
isEmpty(void * buffer)573 bool Region::isEmpty(void* buffer)
574 {
575 int32_t const* const p = static_cast<int32_t const*>(buffer);
576 Rect const* const b = reinterpret_cast<Rect const *>(p+1);
577 return b->isEmpty();
578 }
579
580 // ----------------------------------------------------------------------------
581
begin() const582 Region::const_iterator Region::begin() const {
583 return isRect() ? &mBounds : mStorage.array();
584 }
585
end() const586 Region::const_iterator Region::end() const {
587 return isRect() ? ((&mBounds) + 1) : (mStorage.array() + mStorage.size());
588 }
589
getArray(size_t * count) const590 Rect const* Region::getArray(size_t* count) const {
591 const_iterator const b(begin());
592 const_iterator const e(end());
593 if (count) *count = e-b;
594 return b;
595 }
596
getRects(Vector<Rect> & rectList) const597 size_t Region::getRects(Vector<Rect>& rectList) const
598 {
599 rectList = mStorage;
600 if (rectList.isEmpty()) {
601 rectList.clear();
602 rectList.add(mBounds);
603 }
604 return rectList.size();
605 }
606
607 // ----------------------------------------------------------------------------
608
dump(String8 & out,const char * what,uint32_t flags) const609 void Region::dump(String8& out, const char* what, uint32_t flags) const
610 {
611 (void)flags;
612 const_iterator head = begin();
613 const_iterator const tail = end();
614
615 size_t SIZE = 256;
616 char buffer[SIZE];
617
618 snprintf(buffer, SIZE, " Region %s (this=%p, count=%d)\n",
619 what, this, tail-head);
620 out.append(buffer);
621 while (head != tail) {
622 snprintf(buffer, SIZE, " [%3d, %3d, %3d, %3d]\n",
623 head->left, head->top, head->right, head->bottom);
624 out.append(buffer);
625 head++;
626 }
627 }
628
dump(const char * what,uint32_t flags) const629 void Region::dump(const char* what, uint32_t flags) const
630 {
631 (void)flags;
632 const_iterator head = begin();
633 const_iterator const tail = end();
634 LOGD(" Region %s (this=%p, count=%d)\n", what, this, tail-head);
635 while (head != tail) {
636 LOGD(" [%3d, %3d, %3d, %3d]\n",
637 head->left, head->top, head->right, head->bottom);
638 head++;
639 }
640 }
641
642 // ----------------------------------------------------------------------------
643
644 }; // namespace android
645