• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2007 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #define LOG_TAG "Region"
18 
19 #include <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 Parcel & parcel)66 Region::Region(const Parcel& parcel)
67 {
68     status_t err = read(parcel);
69     LOGE_IF(err<0, "error %s reading Region from parcel", strerror(err));
70 }
71 
Region(const void * buffer)72 Region::Region(const void* buffer)
73 {
74     status_t err = read(buffer);
75     LOGE_IF(err<0, "error %s reading Region from parcel", strerror(err));
76 }
77 
~Region()78 Region::~Region()
79 {
80 }
81 
operator =(const Region & rhs)82 Region& Region::operator = (const Region& rhs)
83 {
84 #if VALIDATE_REGIONS
85     validate(rhs, "operator=");
86 #endif
87     mBounds = rhs.mBounds;
88     mStorage = rhs.mStorage;
89     return *this;
90 }
91 
makeBoundsSelf()92 Region& Region::makeBoundsSelf()
93 {
94     mStorage.clear();
95     return *this;
96 }
97 
clear()98 void Region::clear()
99 {
100     mBounds.clear();
101     mStorage.clear();
102 }
103 
set(const Rect & r)104 void Region::set(const Rect& r)
105 {
106     mBounds = r;
107     mStorage.clear();
108 }
109 
set(uint32_t w,uint32_t h)110 void Region::set(uint32_t w, uint32_t h)
111 {
112     mBounds = Rect(int(w), int(h));
113     mStorage.clear();
114 }
115 
116 // ----------------------------------------------------------------------------
117 
addRectUnchecked(int l,int t,int r,int b)118 void Region::addRectUnchecked(int l, int t, int r, int b)
119 {
120     mStorage.add(Rect(l,t,r,b));
121 #if VALIDATE_REGIONS
122     validate(*this, "addRectUnchecked");
123 #endif
124 }
125 
126 // ----------------------------------------------------------------------------
127 
orSelf(const Rect & r)128 Region& Region::orSelf(const Rect& r) {
129     return operationSelf(r, op_or);
130 }
andSelf(const Rect & r)131 Region& Region::andSelf(const Rect& r) {
132     return operationSelf(r, op_and);
133 }
subtractSelf(const Rect & r)134 Region& Region::subtractSelf(const Rect& r) {
135     return operationSelf(r, op_nand);
136 }
operationSelf(const Rect & r,int op)137 Region& Region::operationSelf(const Rect& r, int op) {
138     Region lhs(*this);
139     boolean_operation(op, *this, lhs, r);
140     return *this;
141 }
142 
143 // ----------------------------------------------------------------------------
144 
orSelf(const Region & rhs)145 Region& Region::orSelf(const Region& rhs) {
146     return operationSelf(rhs, op_or);
147 }
andSelf(const Region & rhs)148 Region& Region::andSelf(const Region& rhs) {
149     return operationSelf(rhs, op_and);
150 }
subtractSelf(const Region & rhs)151 Region& Region::subtractSelf(const Region& rhs) {
152     return operationSelf(rhs, op_nand);
153 }
operationSelf(const Region & rhs,int op)154 Region& Region::operationSelf(const Region& rhs, int op) {
155     Region lhs(*this);
156     boolean_operation(op, *this, lhs, rhs);
157     return *this;
158 }
159 
translateSelf(int x,int y)160 Region& Region::translateSelf(int x, int y) {
161     if (x|y) translate(*this, x, y);
162     return *this;
163 }
164 
165 // ----------------------------------------------------------------------------
166 
merge(const Rect & rhs) const167 const Region Region::merge(const Rect& rhs) const {
168     return operation(rhs, op_or);
169 }
intersect(const Rect & rhs) const170 const Region Region::intersect(const Rect& rhs) const {
171     return operation(rhs, op_and);
172 }
subtract(const Rect & rhs) const173 const Region Region::subtract(const Rect& rhs) const {
174     return operation(rhs, op_nand);
175 }
operation(const Rect & rhs,int op) const176 const Region Region::operation(const Rect& rhs, int op) const {
177     Region result;
178     boolean_operation(op, result, *this, rhs);
179     return result;
180 }
181 
182 // ----------------------------------------------------------------------------
183 
merge(const Region & rhs) const184 const Region Region::merge(const Region& rhs) const {
185     return operation(rhs, op_or);
186 }
intersect(const Region & rhs) const187 const Region Region::intersect(const Region& rhs) const {
188     return operation(rhs, op_and);
189 }
subtract(const Region & rhs) const190 const Region Region::subtract(const Region& rhs) const {
191     return operation(rhs, op_nand);
192 }
operation(const Region & rhs,int op) const193 const Region Region::operation(const Region& rhs, int op) const {
194     Region result;
195     boolean_operation(op, result, *this, rhs);
196     return result;
197 }
198 
translate(int x,int y) const199 const Region Region::translate(int x, int y) const {
200     Region result;
201     translate(result, *this, x, y);
202     return result;
203 }
204 
205 // ----------------------------------------------------------------------------
206 
orSelf(const Region & rhs,int dx,int dy)207 Region& Region::orSelf(const Region& rhs, int dx, int dy) {
208     return operationSelf(rhs, dx, dy, op_or);
209 }
andSelf(const Region & rhs,int dx,int dy)210 Region& Region::andSelf(const Region& rhs, int dx, int dy) {
211     return operationSelf(rhs, dx, dy, op_and);
212 }
subtractSelf(const Region & rhs,int dx,int dy)213 Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
214     return operationSelf(rhs, dx, dy, op_nand);
215 }
operationSelf(const Region & rhs,int dx,int dy,int op)216 Region& Region::operationSelf(const Region& rhs, int dx, int dy, int op) {
217     Region lhs(*this);
218     boolean_operation(op, *this, lhs, rhs, dx, dy);
219     return *this;
220 }
221 
222 // ----------------------------------------------------------------------------
223 
merge(const Region & rhs,int dx,int dy) const224 const Region Region::merge(const Region& rhs, int dx, int dy) const {
225     return operation(rhs, dx, dy, op_or);
226 }
intersect(const Region & rhs,int dx,int dy) const227 const Region Region::intersect(const Region& rhs, int dx, int dy) const {
228     return operation(rhs, dx, dy, op_and);
229 }
subtract(const Region & rhs,int dx,int dy) const230 const Region Region::subtract(const Region& rhs, int dx, int dy) const {
231     return operation(rhs, dx, dy, op_nand);
232 }
operation(const Region & rhs,int dx,int dy,int op) const233 const Region Region::operation(const Region& rhs, int dx, int dy, int op) const {
234     Region result;
235     boolean_operation(op, result, *this, rhs, dx, dy);
236     return result;
237 }
238 
239 // ----------------------------------------------------------------------------
240 
241 // This is our region rasterizer, which merges rects and spans together
242 // to obtain an optimal region.
243 class Region::rasterizer : public region_operator<Rect>::region_rasterizer
244 {
245     Rect& bounds;
246     Vector<Rect>& storage;
247     Rect* head;
248     Rect* tail;
249     Vector<Rect> span;
250     Rect* cur;
251 public:
rasterizer(Region & reg)252     rasterizer(Region& reg)
253         : bounds(reg.mBounds), storage(reg.mStorage), head(), tail(), cur() {
254         bounds.top = bounds.bottom = 0;
255         bounds.left   = INT_MAX;
256         bounds.right  = INT_MIN;
257         storage.clear();
258     }
259 
~rasterizer()260     ~rasterizer() {
261         if (span.size()) {
262             flushSpan();
263         }
264         if (storage.size()) {
265             bounds.top = storage.itemAt(0).top;
266             bounds.bottom = storage.top().bottom;
267             if (storage.size() == 1) {
268                 storage.clear();
269             }
270         } else {
271             bounds.left  = 0;
272             bounds.right = 0;
273         }
274     }
275 
operator ()(const Rect & rect)276     virtual void operator()(const Rect& rect) {
277         //LOGD(">>> %3d, %3d, %3d, %3d",
278         //        rect.left, rect.top, rect.right, rect.bottom);
279         if (span.size()) {
280             if (cur->top != rect.top) {
281                 flushSpan();
282             } else if (cur->right == rect.left) {
283                 cur->right = rect.right;
284                 return;
285             }
286         }
287         span.add(rect);
288         cur = span.editArray() + (span.size() - 1);
289     }
290 private:
291     template<typename T>
min(T rhs,T lhs)292     static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; }
293     template<typename T>
max(T rhs,T lhs)294     static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; }
flushSpan()295     void flushSpan() {
296         bool merge = false;
297         if (tail-head == ssize_t(span.size())) {
298             Rect const* p = cur;
299             Rect const* q = head;
300             if (p->top == q->bottom) {
301                 merge = true;
302                 while (q != tail) {
303                     if ((p->left != q->left) || (p->right != q->right)) {
304                         merge = false;
305                         break;
306                     }
307                     p++, q++;
308                 }
309             }
310         }
311         if (merge) {
312             const int bottom = span[0].bottom;
313             Rect* r = head;
314             while (r != tail) {
315                 r->bottom = bottom;
316                 r++;
317             }
318         } else {
319             bounds.left = min(span.itemAt(0).left, bounds.left);
320             bounds.right = max(span.top().right, bounds.right);
321             storage.appendVector(span);
322             tail = storage.editArray() + storage.size();
323             head = tail - span.size();
324         }
325         span.clear();
326     }
327 };
328 
validate(const Region & reg,const char * name)329 bool Region::validate(const Region& reg, const char* name)
330 {
331     bool result = true;
332     const_iterator cur = reg.begin();
333     const_iterator const tail = reg.end();
334     const_iterator prev = cur++;
335     Rect b(*prev);
336     while (cur != tail) {
337         b.left   = b.left   < cur->left   ? b.left   : cur->left;
338         b.top    = b.top    < cur->top    ? b.top    : cur->top;
339         b.right  = b.right  > cur->right  ? b.right  : cur->right;
340         b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
341         if (cur->top == prev->top) {
342             if (cur->bottom != prev->bottom) {
343                 LOGE("%s: invalid span %p", name, cur);
344                 result = false;
345             } else if (cur->left < prev->right) {
346                 LOGE("%s: spans overlap horizontally prev=%p, cur=%p",
347                         name, prev, cur);
348                 result = false;
349             }
350         } else if (cur->top < prev->bottom) {
351             LOGE("%s: spans overlap vertically prev=%p, cur=%p",
352                     name, prev, cur);
353             result = false;
354         }
355         prev = cur;
356         cur++;
357     }
358     if (b != reg.getBounds()) {
359         result = false;
360         LOGE("%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
361                 b.left, b.top, b.right, b.bottom,
362                 reg.getBounds().left, reg.getBounds().top,
363                 reg.getBounds().right, reg.getBounds().bottom);
364     }
365     if (result == false) {
366         reg.dump(name);
367     }
368     return result;
369 }
370 
boolean_operation(int op,Region & dst,const Region & lhs,const Region & rhs,int dx,int dy)371 void Region::boolean_operation(int op, Region& dst,
372         const Region& lhs,
373         const Region& rhs, int dx, int dy)
374 {
375     size_t lhs_count;
376     Rect const * const lhs_rects = lhs.getArray(&lhs_count);
377 
378     size_t rhs_count;
379     Rect const * const rhs_rects = rhs.getArray(&rhs_count);
380 
381     region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
382     region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy);
383     region_operator<Rect> operation(op, lhs_region, rhs_region);
384     { // scope for rasterizer (dtor has side effects)
385         rasterizer r(dst);
386         operation(r);
387     }
388 
389 #if VALIDATE_REGIONS
390     validate(lhs, "boolean_operation: lhs");
391     validate(rhs, "boolean_operation: rhs");
392     validate(dst, "boolean_operation: dst");
393 #endif
394 
395 #if VALIDATE_WITH_CORECG
396     SkRegion sk_lhs;
397     SkRegion sk_rhs;
398     SkRegion sk_dst;
399 
400     for (size_t i=0 ; i<lhs_count ; i++)
401         sk_lhs.op(
402                 lhs_rects[i].left   + dx,
403                 lhs_rects[i].top    + dy,
404                 lhs_rects[i].right  + dx,
405                 lhs_rects[i].bottom + dy,
406                 SkRegion::kUnion_Op);
407 
408     for (size_t i=0 ; i<rhs_count ; i++)
409         sk_rhs.op(
410                 rhs_rects[i].left   + dx,
411                 rhs_rects[i].top    + dy,
412                 rhs_rects[i].right  + dx,
413                 rhs_rects[i].bottom + dy,
414                 SkRegion::kUnion_Op);
415 
416     const char* name = "---";
417     SkRegion::Op sk_op;
418     switch (op) {
419         case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
420         case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
421         case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
422     }
423     sk_dst.op(sk_lhs, sk_rhs, sk_op);
424 
425     if (sk_dst.isEmpty() && dst.isEmpty())
426         return;
427 
428     bool same = true;
429     Region::const_iterator head = dst.begin();
430     Region::const_iterator const tail = dst.end();
431     SkRegion::Iterator it(sk_dst);
432     while (!it.done()) {
433         if (head != tail) {
434             if (
435                     head->left != it.rect().fLeft ||
436                     head->top != it.rect().fTop ||
437                     head->right != it.rect().fRight ||
438                     head->bottom != it.rect().fBottom
439             ) {
440                 same = false;
441                 break;
442             }
443         } else {
444             same = false;
445             break;
446         }
447         head++;
448         it.next();
449     }
450 
451     if (head != tail) {
452         same = false;
453     }
454 
455     if(!same) {
456         LOGD("---\nregion boolean %s failed", name);
457         lhs.dump("lhs");
458         rhs.dump("rhs");
459         dst.dump("dst");
460         LOGD("should be");
461         SkRegion::Iterator it(sk_dst);
462         while (!it.done()) {
463             LOGD("    [%3d, %3d, %3d, %3d]",
464                 it.rect().fLeft,
465                 it.rect().fTop,
466                 it.rect().fRight,
467                 it.rect().fBottom);
468             it.next();
469         }
470     }
471 #endif
472 }
473 
boolean_operation(int op,Region & dst,const Region & lhs,const Rect & rhs,int dx,int dy)474 void Region::boolean_operation(int op, Region& dst,
475         const Region& lhs,
476         const Rect& rhs, int dx, int dy)
477 {
478 #if VALIDATE_WITH_CORECG || VALIDATE_REGIONS
479     boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
480 #else
481     size_t lhs_count;
482     Rect const * const lhs_rects = lhs.getArray(&lhs_count);
483 
484     region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
485     region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy);
486     region_operator<Rect> operation(op, lhs_region, rhs_region);
487     { // scope for rasterizer (dtor has side effects)
488         rasterizer r(dst);
489         operation(r);
490     }
491 
492 #endif
493 }
494 
boolean_operation(int op,Region & dst,const Region & lhs,const Region & rhs)495 void Region::boolean_operation(int op, Region& dst,
496         const Region& lhs, const Region& rhs)
497 {
498     boolean_operation(op, dst, lhs, rhs, 0, 0);
499 }
500 
boolean_operation(int op,Region & dst,const Region & lhs,const Rect & rhs)501 void Region::boolean_operation(int op, Region& dst,
502         const Region& lhs, const Rect& rhs)
503 {
504     boolean_operation(op, dst, lhs, rhs, 0, 0);
505 }
506 
translate(Region & reg,int dx,int dy)507 void Region::translate(Region& reg, int dx, int dy)
508 {
509     if (!reg.isEmpty()) {
510 #if VALIDATE_REGIONS
511         validate(reg, "translate (before)");
512 #endif
513         reg.mBounds.translate(dx, dy);
514         size_t count = reg.mStorage.size();
515         Rect* rects = reg.mStorage.editArray();
516         while (count) {
517             rects->translate(dx, dy);
518             rects++;
519             count--;
520         }
521 #if VALIDATE_REGIONS
522         validate(reg, "translate (after)");
523 #endif
524     }
525 }
526 
translate(Region & dst,const Region & reg,int dx,int dy)527 void Region::translate(Region& dst, const Region& reg, int dx, int dy)
528 {
529     dst = reg;
530     translate(dst, dx, dy);
531 }
532 
533 // ----------------------------------------------------------------------------
534 
write(Parcel & parcel) const535 status_t Region::write(Parcel& parcel) const
536 {
537 #if VALIDATE_REGIONS
538     validate(*this, "write(Parcel)");
539 #endif
540     status_t err;
541     const size_t count = mStorage.size();
542     const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
543     void* buffer = parcel.writeInplace(sizeNeeded);
544     if (!buffer) return NO_MEMORY;
545     ssize_t written = Region::write(buffer, sizeNeeded);
546     if (written < 0) return status_t(written);
547     return NO_ERROR;
548 }
549 
read(const Parcel & parcel)550 status_t Region::read(const Parcel& parcel)
551 {
552     void const* buffer = parcel.readInplace(sizeof(int32_t));
553     if (!buffer) return NO_MEMORY;
554     const size_t count = *static_cast<int32_t const *>(buffer);
555     void const* dummy = parcel.readInplace((1+count)*sizeof(Rect));
556     if (!dummy) return NO_MEMORY;
557     const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
558     const ssize_t read = Region::read(buffer);
559     if (read < 0) return status_t(read);
560 #if VALIDATE_REGIONS
561     validate(*this, "read(Parcel)");
562 #endif
563     return NO_ERROR;
564 }
565 
write(void * buffer,size_t size) const566 ssize_t Region::write(void* buffer, size_t size) const
567 {
568 #if VALIDATE_REGIONS
569     validate(*this, "write(buffer)");
570 #endif
571     const size_t count = mStorage.size();
572     const size_t sizeNeeded = sizeof(int32_t) + (1+count)*sizeof(Rect);
573     if (sizeNeeded > size) return NO_MEMORY;
574     int32_t* const p = static_cast<int32_t*>(buffer);
575     *p = count;
576     memcpy(p+1, &mBounds, sizeof(Rect));
577     if (count) {
578         memcpy(p+5, mStorage.array(), count*sizeof(Rect));
579     }
580     return ssize_t(sizeNeeded);
581 }
582 
read(const void * buffer)583 ssize_t Region::read(const void* buffer)
584 {
585     int32_t const* const p = static_cast<int32_t const*>(buffer);
586     const size_t count = *p;
587     memcpy(&mBounds, p+1, sizeof(Rect));
588     mStorage.clear();
589     if (count) {
590         mStorage.insertAt(0, count);
591         memcpy(mStorage.editArray(), p+5, count*sizeof(Rect));
592     }
593 #if VALIDATE_REGIONS
594     validate(*this, "read(buffer)");
595 #endif
596     return ssize_t(sizeof(int32_t) + (1+count)*sizeof(Rect));
597 }
598 
writeEmpty(void * buffer,size_t size)599 ssize_t Region::writeEmpty(void* buffer, size_t size)
600 {
601     const size_t sizeNeeded = sizeof(int32_t) + sizeof(Rect);
602     if (sizeNeeded > size) return NO_MEMORY;
603     int32_t* const p = static_cast<int32_t*>(buffer);
604     memset(p, 0, sizeNeeded);
605     return ssize_t(sizeNeeded);
606 }
607 
isEmpty(void * buffer)608 bool Region::isEmpty(void* buffer)
609 {
610     int32_t const* const p = static_cast<int32_t const*>(buffer);
611     Rect const* const b = reinterpret_cast<Rect const *>(p+1);
612     return b->isEmpty();
613 }
614 
615 // ----------------------------------------------------------------------------
616 
begin() const617 Region::const_iterator Region::begin() const {
618     return isRect() ? &mBounds : mStorage.array();
619 }
620 
end() const621 Region::const_iterator Region::end() const {
622     return isRect() ? ((&mBounds) + 1) : (mStorage.array() + mStorage.size());
623 }
624 
getArray(size_t * count) const625 Rect const* Region::getArray(size_t* count) const {
626     const_iterator const b(begin());
627     const_iterator const e(end());
628     if (count) *count = e-b;
629     return b;
630 }
631 
getRects(Vector<Rect> & rectList) const632 size_t Region::getRects(Vector<Rect>& rectList) const
633 {
634     rectList = mStorage;
635     if (rectList.isEmpty()) {
636         rectList.clear();
637         rectList.add(mBounds);
638     }
639     return rectList.size();
640 }
641 
642 // ----------------------------------------------------------------------------
643 
dump(String8 & out,const char * what,uint32_t flags) const644 void Region::dump(String8& out, const char* what, uint32_t flags) const
645 {
646     (void)flags;
647     const_iterator head = begin();
648     const_iterator const tail = end();
649 
650     size_t SIZE = 256;
651     char buffer[SIZE];
652 
653     snprintf(buffer, SIZE, "  Region %s (this=%p, count=%d)\n",
654             what, this, tail-head);
655     out.append(buffer);
656     while (head != tail) {
657         snprintf(buffer, SIZE, "    [%3d, %3d, %3d, %3d]\n",
658                 head->left, head->top, head->right, head->bottom);
659         out.append(buffer);
660         head++;
661     }
662 }
663 
dump(const char * what,uint32_t flags) const664 void Region::dump(const char* what, uint32_t flags) const
665 {
666     (void)flags;
667     const_iterator head = begin();
668     const_iterator const tail = end();
669     LOGD("  Region %s (this=%p, count=%d)\n", what, this, tail-head);
670     while (head != tail) {
671         LOGD("    [%3d, %3d, %3d, %3d]\n",
672                 head->left, head->top, head->right, head->bottom);
673         head++;
674     }
675 }
676 
677 // ----------------------------------------------------------------------------
678 
679 }; // namespace android
680