• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2009 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 #ifndef ANDROID_UI_PRIVATE_REGION_HELPER_H
18 #define ANDROID_UI_PRIVATE_REGION_HELPER_H
19 
20 #include <limits>
21 #include <stdint.h>
22 #include <sys/types.h>
23 
24 #include <limits>
25 
26 namespace android {
27 // ----------------------------------------------------------------------------
28 
29 template<typename RECT>
30 class region_operator
31 {
32 public:
33     typedef typename RECT::value_type TYPE;
34     static const TYPE max_value = std::numeric_limits<TYPE>::max();
35 
36     /*
37      * Common boolean operations:
38      * value is computed as 0b101 op 0b110
39      *    other boolean operation are possible, simply compute
40      *    their corresponding value with the above formulae and use
41      *    it when instantiating a region_operator.
42      */
43     static const uint32_t LHS = 0x5;  // 0b101
44     static const uint32_t RHS = 0x6;  // 0b110
45     enum {
46         op_nand = LHS & ~RHS,
47         op_and  = LHS &  RHS,
48         op_or   = LHS |  RHS,
49         op_xor  = LHS ^  RHS
50     };
51 
52     struct region {
53         RECT const* rects;
54         size_t count;
55         TYPE dx;
56         TYPE dy;
regionregion57         inline region(const region& rhs)
58             : rects(rhs.rects), count(rhs.count), dx(rhs.dx), dy(rhs.dy) { }
regionregion59         inline region(RECT const* _r, size_t _c)
60             : rects(_r), count(_c), dx(), dy() { }
regionregion61         inline region(RECT const* _r, size_t _c, TYPE _dx, TYPE _dy)
62             : rects(_r), count(_c), dx(_dx), dy(_dy) { }
63     };
64 
65     class region_rasterizer {
66         friend class region_operator;
67         virtual void operator()(const RECT& rect) = 0;
68     public:
~region_rasterizer()69         virtual ~region_rasterizer() { }
70     };
71 
region_operator(uint32_t op,const region & lhs,const region & rhs)72     inline region_operator(uint32_t op, const region& lhs, const region& rhs)
73         : op_mask(op), spanner(lhs, rhs)
74     {
75     }
76 
operator()77     void operator()(region_rasterizer& rasterizer) {
78         RECT current(Rect::EMPTY_RECT);
79         do {
80             SpannerInner spannerInner(spanner.lhs, spanner.rhs);
81             int inside = spanner.next(current.top, current.bottom);
82             spannerInner.prepare(inside);
83             do {
84                 TYPE left, right;
85                 int inner_inside = spannerInner.next(current.left, current.right);
86                 if ((op_mask >> inner_inside) & 1) {
87                     if (current.left < current.right &&
88                             current.top < current.bottom) {
89                         rasterizer(current);
90                     }
91                 }
92             } while(!spannerInner.isDone());
93         } while(!spanner.isDone());
94     }
95 
96 private:
97     uint32_t op_mask;
98 
99     class SpannerBase
100     {
101     public:
SpannerBase()102         SpannerBase()
103             : lhs_head(max_value), lhs_tail(max_value),
104               rhs_head(max_value), rhs_tail(max_value) {
105         }
106 
107         enum {
108             lhs_before_rhs   = 0,
109             lhs_after_rhs    = 1,
110             lhs_coincide_rhs = 2
111         };
112 
113     protected:
114         TYPE lhs_head;
115         TYPE lhs_tail;
116         TYPE rhs_head;
117         TYPE rhs_tail;
118 
next(TYPE & head,TYPE & tail,bool & more_lhs,bool & more_rhs)119         inline int next(TYPE& head, TYPE& tail,
120                 bool& more_lhs, bool& more_rhs)
121         {
122             int inside;
123             more_lhs = false;
124             more_rhs = false;
125             if (lhs_head < rhs_head) {
126                 inside = lhs_before_rhs;
127                 head = lhs_head;
128                 if (lhs_tail <= rhs_head) {
129                     tail = lhs_tail;
130                     more_lhs = true;
131                 } else {
132                     lhs_head = rhs_head;
133                     tail = rhs_head;
134                 }
135             } else if (rhs_head < lhs_head) {
136                 inside = lhs_after_rhs;
137                 head = rhs_head;
138                 if (rhs_tail <= lhs_head) {
139                     tail = rhs_tail;
140                     more_rhs = true;
141                 } else {
142                     rhs_head = lhs_head;
143                     tail = lhs_head;
144                 }
145             } else {
146                 inside = lhs_coincide_rhs;
147                 head = lhs_head;
148                 if (lhs_tail <= rhs_tail) {
149                     tail = rhs_head = lhs_tail;
150                     more_lhs = true;
151                 }
152                 if (rhs_tail <= lhs_tail) {
153                     tail = lhs_head = rhs_tail;
154                     more_rhs = true;
155                 }
156             }
157             return inside;
158         }
159     };
160 
161     class Spanner : protected SpannerBase
162     {
163         friend class region_operator;
164         region lhs;
165         region rhs;
166 
167     public:
Spanner(const region & _lhs,const region & _rhs)168         inline Spanner(const region& _lhs, const region& _rhs)
169         : lhs(_lhs), rhs(_rhs)
170         {
171             if (lhs.count) {
172                 SpannerBase::lhs_head = lhs.rects->top      + lhs.dy;
173                 SpannerBase::lhs_tail = lhs.rects->bottom   + lhs.dy;
174             }
175             if (rhs.count) {
176                 SpannerBase::rhs_head = rhs.rects->top      + rhs.dy;
177                 SpannerBase::rhs_tail = rhs.rects->bottom   + rhs.dy;
178             }
179         }
180 
isDone()181         inline bool isDone() const {
182             return !rhs.count && !lhs.count;
183         }
184 
next(TYPE & top,TYPE & bottom)185         inline int next(TYPE& top, TYPE& bottom)
186         {
187             bool more_lhs = false;
188             bool more_rhs = false;
189             int inside = SpannerBase::next(top, bottom, more_lhs, more_rhs);
190             if (more_lhs) {
191                 advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail);
192             }
193             if (more_rhs) {
194                 advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail);
195             }
196             return inside;
197         }
198 
199     private:
200         static inline
advance(region & reg,TYPE & aTop,TYPE & aBottom)201         void advance(region& reg, TYPE& aTop, TYPE& aBottom) {
202             // got to next span
203             size_t count = reg.count;
204             RECT const * rects = reg.rects;
205             RECT const * const end = rects + count;
206             const int top = rects->top;
207             while (rects != end && rects->top == top) {
208                 rects++;
209                 count--;
210             }
211             if (rects != end) {
212                 aTop    = rects->top    + reg.dy;
213                 aBottom = rects->bottom + reg.dy;
214             } else {
215                 aTop    = max_value;
216                 aBottom = max_value;
217             }
218             reg.rects = rects;
219             reg.count = count;
220         }
221     };
222 
223     class SpannerInner : protected SpannerBase
224     {
225         region lhs;
226         region rhs;
227 
228     public:
SpannerInner(const region & _lhs,const region & _rhs)229         inline SpannerInner(const region& _lhs, const region& _rhs)
230             : lhs(_lhs), rhs(_rhs)
231         {
232         }
233 
prepare(int inside)234         inline void prepare(int inside) {
235             if (inside == SpannerBase::lhs_before_rhs) {
236                 if (lhs.count) {
237                     SpannerBase::lhs_head = lhs.rects->left  + lhs.dx;
238                     SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
239                 }
240                 SpannerBase::rhs_head = max_value;
241                 SpannerBase::rhs_tail = max_value;
242             } else if (inside == SpannerBase::lhs_after_rhs) {
243                 SpannerBase::lhs_head = max_value;
244                 SpannerBase::lhs_tail = max_value;
245                 if (rhs.count) {
246                     SpannerBase::rhs_head = rhs.rects->left  + rhs.dx;
247                     SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
248                 }
249             } else {
250                 if (lhs.count) {
251                     SpannerBase::lhs_head = lhs.rects->left  + lhs.dx;
252                     SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
253                 }
254                 if (rhs.count) {
255                     SpannerBase::rhs_head = rhs.rects->left  + rhs.dx;
256                     SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
257                 }
258             }
259         }
260 
isDone()261         inline bool isDone() const {
262             return SpannerBase::lhs_head == max_value &&
263                    SpannerBase::rhs_head == max_value;
264         }
265 
next(TYPE & left,TYPE & right)266         inline int next(TYPE& left, TYPE& right)
267         {
268             bool more_lhs = false;
269             bool more_rhs = false;
270             int inside = SpannerBase::next(left, right, more_lhs, more_rhs);
271             if (more_lhs) {
272                 advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail);
273             }
274             if (more_rhs) {
275                 advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail);
276             }
277             return inside;
278         }
279 
280     private:
281         static inline
advance(region & reg,TYPE & left,TYPE & right)282         void advance(region& reg, TYPE& left, TYPE& right) {
283             if (reg.rects && reg.count) {
284                 const int cur_span_top = reg.rects->top;
285                 reg.rects++;
286                 reg.count--;
287                 if (!reg.count || reg.rects->top != cur_span_top) {
288                     left  = max_value;
289                     right = max_value;
290                 } else {
291                     left  = reg.rects->left  + reg.dx;
292                     right = reg.rects->right + reg.dx;
293                 }
294             }
295         }
296     };
297 
298     Spanner spanner;
299 };
300 
301 // ----------------------------------------------------------------------------
302 };
303 
304 #endif /* ANDROID_UI_PRIVATE_REGION_HELPER_H */
305