| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 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 <stdint.h> | 
|  | 21 | #include <sys/types.h> | 
|  | 22 |  | 
|  | 23 | namespace android { | 
|  | 24 | // ---------------------------------------------------------------------------- | 
|  | 25 |  | 
|  | 26 | template<typename RECT> | 
|  | 27 | class region_operator | 
|  | 28 | { | 
| Mathias Agopian | 068d47f | 2012-09-11 18:56:23 -0700 | [diff] [blame] | 29 | public: | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 30 | typedef typename RECT::value_type TYPE; | 
|  | 31 | static const TYPE max_value = 0x7FFFFFF; | 
|  | 32 |  | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 33 | /* | 
|  | 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) { } | 
| Colin Cross | 382ecd3 | 2016-09-26 13:33:59 -0700 | [diff] [blame] | 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) { } | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 60 | }; | 
|  | 61 |  | 
|  | 62 | class region_rasterizer { | 
|  | 63 | friend class region_operator; | 
|  | 64 | virtual void operator()(const RECT& rect) = 0; | 
| Mathias Agopian | e7c4c28 | 2009-07-07 12:29:17 -0700 | [diff] [blame] | 65 | public: | 
| Colin Cross | 17576de | 2016-09-26 13:07:06 -0700 | [diff] [blame] | 66 | virtual ~region_rasterizer() { } | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 67 | }; | 
|  | 68 |  | 
| Colin Cross | 8f27996 | 2016-09-26 13:08:16 -0700 | [diff] [blame] | 69 | inline region_operator(uint32_t op, const region& lhs, const region& rhs) | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 70 | : op_mask(op), spanner(lhs, rhs) | 
|  | 71 | { | 
|  | 72 | } | 
|  | 73 |  | 
|  | 74 | void operator()(region_rasterizer& rasterizer) { | 
| Pablo Ceballos | 60d6922 | 2015-08-07 14:47:20 -0700 | [diff] [blame] | 75 | RECT current(Rect::EMPTY_RECT); | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 76 | 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; | 
| Colin Cross | 382ecd3 | 2016-09-26 13:33:59 -0700 | [diff] [blame] | 82 | int inner_inside = spannerInner.next(current.left, current.right); | 
|  | 83 | if ((op_mask >> inner_inside) & 1) { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 84 | if (current.left < current.right && | 
|  | 85 | current.top < current.bottom) { | 
|  | 86 | rasterizer(current); | 
|  | 87 | } | 
|  | 88 | } | 
| Mathias Agopian | 38a7fa2 | 2009-10-15 18:08:15 -0700 | [diff] [blame] | 89 | } while(!spannerInner.isDone()); | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 90 | } while(!spanner.isDone()); | 
|  | 91 | } | 
|  | 92 |  | 
|  | 93 | private: | 
|  | 94 | uint32_t op_mask; | 
|  | 95 |  | 
|  | 96 | class SpannerBase | 
|  | 97 | { | 
|  | 98 | public: | 
| Mathias Agopian | 3aecbb0 | 2012-04-16 18:40:30 -0700 | [diff] [blame] | 99 | SpannerBase() | 
|  | 100 | : lhs_head(max_value), lhs_tail(max_value), | 
|  | 101 | rhs_head(max_value), rhs_tail(max_value) { | 
|  | 102 | } | 
|  | 103 |  | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 104 | 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: | 
| Colin Cross | 382ecd3 | 2016-09-26 13:33:59 -0700 | [diff] [blame] | 165 | inline Spanner(const region& _lhs, const region& _rhs) | 
|  | 166 | : lhs(_lhs), rhs(_rhs) | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 167 | { | 
| Mathias Agopian | 3aecbb0 | 2012-04-16 18:40:30 -0700 | [diff] [blame] | 168 | 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 Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 176 | } | 
|  | 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: | 
| Colin Cross | 382ecd3 | 2016-09-26 13:33:59 -0700 | [diff] [blame] | 226 | inline SpannerInner(const region& _lhs, const region& _rhs) | 
|  | 227 | : lhs(_lhs), rhs(_rhs) | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 228 | { | 
|  | 229 | } | 
|  | 230 |  | 
|  | 231 | inline void prepare(int inside) { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 232 | if (inside == SpannerBase::lhs_before_rhs) { | 
| Mathias Agopian | 3aecbb0 | 2012-04-16 18:40:30 -0700 | [diff] [blame] | 233 | if (lhs.count) { | 
|  | 234 | SpannerBase::lhs_head = lhs.rects->left  + lhs.dx; | 
|  | 235 | SpannerBase::lhs_tail = lhs.rects->right + lhs.dx; | 
|  | 236 | } | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 237 | 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 Agopian | 3aecbb0 | 2012-04-16 18:40:30 -0700 | [diff] [blame] | 242 | if (rhs.count) { | 
|  | 243 | SpannerBase::rhs_head = rhs.rects->left  + rhs.dx; | 
|  | 244 | SpannerBase::rhs_tail = rhs.rects->right + rhs.dx; | 
|  | 245 | } | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 246 | } else { | 
| Mathias Agopian | 3aecbb0 | 2012-04-16 18:40:30 -0700 | [diff] [blame] | 247 | 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 Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 255 | } | 
|  | 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 */ |