blob: 84eb10079b5509cadcb2ddde81aac598822ebe1f [file] [log] [blame]
Mathias Agopian20f68782009-05-11 00:03:41 -07001/*
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 <stdint.h>
21#include <sys/types.h>
22
23namespace android {
24// ----------------------------------------------------------------------------
25
26template<typename RECT>
27class region_operator
28{
Mathias Agopian068d47f2012-09-11 18:56:23 -070029public:
Mathias Agopian20f68782009-05-11 00:03:41 -070030 typedef typename RECT::value_type TYPE;
31 static const TYPE max_value = 0x7FFFFFF;
32
Mathias Agopian20f68782009-05-11 00:03:41 -070033 /*
34 * Common boolean operations:
35 * value is computed as 0b101 op 0b110
36 * other boolean operation are possible, simply compute
37 * their corresponding value with the above formulae and use
38 * it when instantiating a region_operator.
39 */
40 static const uint32_t LHS = 0x5; // 0b101
41 static const uint32_t RHS = 0x6; // 0b110
42 enum {
43 op_nand = LHS & ~RHS,
44 op_and = LHS & RHS,
45 op_or = LHS | RHS,
46 op_xor = LHS ^ RHS
47 };
48
49 struct region {
50 RECT const* rects;
51 size_t count;
52 TYPE dx;
53 TYPE dy;
54 inline region(const region& rhs)
55 : rects(rhs.rects), count(rhs.count), dx(rhs.dx), dy(rhs.dy) { }
56 inline region(RECT const* r, size_t c)
57 : rects(r), count(c), dx(), dy() { }
58 inline region(RECT const* r, size_t c, TYPE dx, TYPE dy)
59 : rects(r), count(c), dx(dx), dy(dy) { }
60 };
61
62 class region_rasterizer {
63 friend class region_operator;
64 virtual void operator()(const RECT& rect) = 0;
Mathias Agopiane7c4c282009-07-07 12:29:17 -070065 public:
66 virtual ~region_rasterizer() { };
Mathias Agopian20f68782009-05-11 00:03:41 -070067 };
68
69 inline region_operator(int op, const region& lhs, const region& rhs)
70 : op_mask(op), spanner(lhs, rhs)
71 {
72 }
73
74 void operator()(region_rasterizer& rasterizer) {
Pablo Ceballos60d69222015-08-07 14:47:20 -070075 RECT current(Rect::EMPTY_RECT);
Mathias Agopian20f68782009-05-11 00:03:41 -070076 do {
77 SpannerInner spannerInner(spanner.lhs, spanner.rhs);
78 int inside = spanner.next(current.top, current.bottom);
79 spannerInner.prepare(inside);
80 do {
81 TYPE left, right;
82 int inside = spannerInner.next(current.left, current.right);
83 if ((op_mask >> inside) & 1) {
84 if (current.left < current.right &&
85 current.top < current.bottom) {
86 rasterizer(current);
87 }
88 }
Mathias Agopian38a7fa22009-10-15 18:08:15 -070089 } while(!spannerInner.isDone());
Mathias Agopian20f68782009-05-11 00:03:41 -070090 } while(!spanner.isDone());
91 }
92
93private:
94 uint32_t op_mask;
95
96 class SpannerBase
97 {
98 public:
Mathias Agopian3aecbb02012-04-16 18:40:30 -070099 SpannerBase()
100 : lhs_head(max_value), lhs_tail(max_value),
101 rhs_head(max_value), rhs_tail(max_value) {
102 }
103
Mathias Agopian20f68782009-05-11 00:03:41 -0700104 enum {
105 lhs_before_rhs = 0,
106 lhs_after_rhs = 1,
107 lhs_coincide_rhs = 2
108 };
109
110 protected:
111 TYPE lhs_head;
112 TYPE lhs_tail;
113 TYPE rhs_head;
114 TYPE rhs_tail;
115
116 inline int next(TYPE& head, TYPE& tail,
117 bool& more_lhs, bool& more_rhs)
118 {
119 int inside;
120 more_lhs = false;
121 more_rhs = false;
122 if (lhs_head < rhs_head) {
123 inside = lhs_before_rhs;
124 head = lhs_head;
125 if (lhs_tail <= rhs_head) {
126 tail = lhs_tail;
127 more_lhs = true;
128 } else {
129 lhs_head = rhs_head;
130 tail = rhs_head;
131 }
132 } else if (rhs_head < lhs_head) {
133 inside = lhs_after_rhs;
134 head = rhs_head;
135 if (rhs_tail <= lhs_head) {
136 tail = rhs_tail;
137 more_rhs = true;
138 } else {
139 rhs_head = lhs_head;
140 tail = lhs_head;
141 }
142 } else {
143 inside = lhs_coincide_rhs;
144 head = lhs_head;
145 if (lhs_tail <= rhs_tail) {
146 tail = rhs_head = lhs_tail;
147 more_lhs = true;
148 }
149 if (rhs_tail <= lhs_tail) {
150 tail = lhs_head = rhs_tail;
151 more_rhs = true;
152 }
153 }
154 return inside;
155 }
156 };
157
158 class Spanner : protected SpannerBase
159 {
160 friend class region_operator;
161 region lhs;
162 region rhs;
163
164 public:
165 inline Spanner(const region& lhs, const region& rhs)
Mathias Agopian3aecbb02012-04-16 18:40:30 -0700166 : lhs(lhs), rhs(rhs)
Mathias Agopian20f68782009-05-11 00:03:41 -0700167 {
Mathias Agopian3aecbb02012-04-16 18:40:30 -0700168 if (lhs.count) {
169 SpannerBase::lhs_head = lhs.rects->top + lhs.dy;
170 SpannerBase::lhs_tail = lhs.rects->bottom + lhs.dy;
171 }
172 if (rhs.count) {
173 SpannerBase::rhs_head = rhs.rects->top + rhs.dy;
174 SpannerBase::rhs_tail = rhs.rects->bottom + rhs.dy;
175 }
Mathias Agopian20f68782009-05-11 00:03:41 -0700176 }
177
178 inline bool isDone() const {
179 return !rhs.count && !lhs.count;
180 }
181
182 inline int next(TYPE& top, TYPE& bottom)
183 {
184 bool more_lhs = false;
185 bool more_rhs = false;
186 int inside = SpannerBase::next(top, bottom, more_lhs, more_rhs);
187 if (more_lhs) {
188 advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail);
189 }
190 if (more_rhs) {
191 advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail);
192 }
193 return inside;
194 }
195
196 private:
197 static inline
198 void advance(region& reg, TYPE& aTop, TYPE& aBottom) {
199 // got to next span
200 size_t count = reg.count;
201 RECT const * rects = reg.rects;
202 RECT const * const end = rects + count;
203 const int top = rects->top;
204 while (rects != end && rects->top == top) {
205 rects++;
206 count--;
207 }
208 if (rects != end) {
209 aTop = rects->top + reg.dy;
210 aBottom = rects->bottom + reg.dy;
211 } else {
212 aTop = max_value;
213 aBottom = max_value;
214 }
215 reg.rects = rects;
216 reg.count = count;
217 }
218 };
219
220 class SpannerInner : protected SpannerBase
221 {
222 region lhs;
223 region rhs;
224
225 public:
226 inline SpannerInner(const region& lhs, const region& rhs)
227 : lhs(lhs), rhs(rhs)
228 {
229 }
230
231 inline void prepare(int inside) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700232 if (inside == SpannerBase::lhs_before_rhs) {
Mathias Agopian3aecbb02012-04-16 18:40:30 -0700233 if (lhs.count) {
234 SpannerBase::lhs_head = lhs.rects->left + lhs.dx;
235 SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
236 }
Mathias Agopian20f68782009-05-11 00:03:41 -0700237 SpannerBase::rhs_head = max_value;
238 SpannerBase::rhs_tail = max_value;
239 } else if (inside == SpannerBase::lhs_after_rhs) {
240 SpannerBase::lhs_head = max_value;
241 SpannerBase::lhs_tail = max_value;
Mathias Agopian3aecbb02012-04-16 18:40:30 -0700242 if (rhs.count) {
243 SpannerBase::rhs_head = rhs.rects->left + rhs.dx;
244 SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
245 }
Mathias Agopian20f68782009-05-11 00:03:41 -0700246 } else {
Mathias Agopian3aecbb02012-04-16 18:40:30 -0700247 if (lhs.count) {
248 SpannerBase::lhs_head = lhs.rects->left + lhs.dx;
249 SpannerBase::lhs_tail = lhs.rects->right + lhs.dx;
250 }
251 if (rhs.count) {
252 SpannerBase::rhs_head = rhs.rects->left + rhs.dx;
253 SpannerBase::rhs_tail = rhs.rects->right + rhs.dx;
254 }
Mathias Agopian20f68782009-05-11 00:03:41 -0700255 }
256 }
257
258 inline bool isDone() const {
259 return SpannerBase::lhs_head == max_value &&
260 SpannerBase::rhs_head == max_value;
261 }
262
263 inline int next(TYPE& left, TYPE& right)
264 {
265 bool more_lhs = false;
266 bool more_rhs = false;
267 int inside = SpannerBase::next(left, right, more_lhs, more_rhs);
268 if (more_lhs) {
269 advance(lhs, SpannerBase::lhs_head, SpannerBase::lhs_tail);
270 }
271 if (more_rhs) {
272 advance(rhs, SpannerBase::rhs_head, SpannerBase::rhs_tail);
273 }
274 return inside;
275 }
276
277 private:
278 static inline
279 void advance(region& reg, TYPE& left, TYPE& right) {
280 if (reg.rects && reg.count) {
281 const int cur_span_top = reg.rects->top;
282 reg.rects++;
283 reg.count--;
284 if (!reg.count || reg.rects->top != cur_span_top) {
285 left = max_value;
286 right = max_value;
287 } else {
288 left = reg.rects->left + reg.dx;
289 right = reg.rects->right + reg.dx;
290 }
291 }
292 }
293 };
294
295 Spanner spanner;
296};
297
298// ----------------------------------------------------------------------------
299};
300
301#endif /* ANDROID_UI_PRIVATE_REGION_HELPER_H */