| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 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 |  | 
| Mark Salyzyn | 92dc3fc | 2014-03-12 13:12:44 -0700 | [diff] [blame] | 19 | #include <inttypes.h> | 
| Mathias Agopian | 72b0ffe | 2009-07-06 18:07:26 -0700 | [diff] [blame] | 20 | #include <limits.h> | 
 | 21 |  | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 22 | #include <utils/Log.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 23 | #include <utils/String8.h> | 
| Mathias Agopian | 068d47f | 2012-09-11 18:56:23 -0700 | [diff] [blame] | 24 | #include <utils/CallStack.h> | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 25 |  | 
 | 26 | #include <ui/Rect.h> | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 27 | #include <ui/Region.h> | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 28 | #include <ui/Point.h> | 
 | 29 |  | 
 | 30 | #include <private/ui/RegionHelper.h> | 
 | 31 |  | 
 | 32 | // ---------------------------------------------------------------------------- | 
 | 33 | #define VALIDATE_REGIONS        (false) | 
 | 34 | #define VALIDATE_WITH_CORECG    (false) | 
 | 35 | // ---------------------------------------------------------------------------- | 
 | 36 |  | 
 | 37 | #if VALIDATE_WITH_CORECG | 
 | 38 | #include <core/SkRegion.h> | 
 | 39 | #endif | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 40 |  | 
 | 41 | namespace android { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 42 | // ---------------------------------------------------------------------------- | 
 | 43 |  | 
 | 44 | enum { | 
 | 45 |     op_nand = region_operator<Rect>::op_nand, | 
 | 46 |     op_and  = region_operator<Rect>::op_and, | 
 | 47 |     op_or   = region_operator<Rect>::op_or, | 
 | 48 |     op_xor  = region_operator<Rect>::op_xor | 
 | 49 | }; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 50 |  | 
| Chris Craik | 3e010f3 | 2013-02-25 19:12:47 -0800 | [diff] [blame] | 51 | enum { | 
 | 52 |     direction_LTR, | 
 | 53 |     direction_RTL | 
 | 54 | }; | 
 | 55 |  | 
| Dan Stoza | 5065a55 | 2015-03-17 16:23:42 -0700 | [diff] [blame] | 56 | const Region Region::INVALID_REGION(Rect::INVALID_RECT); | 
 | 57 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 58 | // ---------------------------------------------------------------------------- | 
 | 59 |  | 
| Mathias Agopian | 3ab6855 | 2012-08-31 14:31:40 -0700 | [diff] [blame] | 60 | Region::Region() { | 
 | 61 |     mStorage.add(Rect(0,0)); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 62 | } | 
 | 63 |  | 
 | 64 | Region::Region(const Region& rhs) | 
| Mathias Agopian | 3ab6855 | 2012-08-31 14:31:40 -0700 | [diff] [blame] | 65 |     : mStorage(rhs.mStorage) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 66 | { | 
| Mathias Agopian | d0b55c0 | 2011-03-16 23:18:07 -0700 | [diff] [blame] | 67 | #if VALIDATE_REGIONS | 
 | 68 |     validate(rhs, "rhs copy-ctor"); | 
 | 69 | #endif | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 70 | } | 
 | 71 |  | 
| Mathias Agopian | 3ab6855 | 2012-08-31 14:31:40 -0700 | [diff] [blame] | 72 | Region::Region(const Rect& rhs) { | 
 | 73 |     mStorage.add(rhs); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 74 | } | 
 | 75 |  | 
 | 76 | Region::~Region() | 
 | 77 | { | 
 | 78 | } | 
 | 79 |  | 
| Chris Craik | 3e010f3 | 2013-02-25 19:12:47 -0800 | [diff] [blame] | 80 | /** | 
 | 81 |  * Copy rects from the src vector into the dst vector, resolving vertical T-Junctions along the way | 
 | 82 |  * | 
 | 83 |  * First pass through, divideSpanRTL will be set because the 'previous span' (indexing into the dst | 
 | 84 |  * vector) will be reversed. Each rectangle in the original list, starting from the bottom, will be | 
 | 85 |  * compared with the span directly below, and subdivided as needed to resolve T-junctions. | 
 | 86 |  * | 
 | 87 |  * The resulting temporary vector will be a completely reversed copy of the original, without any | 
 | 88 |  * bottom-up T-junctions. | 
 | 89 |  * | 
 | 90 |  * Second pass through, divideSpanRTL will be false since the previous span will index into the | 
 | 91 |  * final, correctly ordered region buffer. Each rectangle will be compared with the span directly | 
 | 92 |  * above it, and subdivided to resolve any remaining T-junctions. | 
 | 93 |  */ | 
 | 94 | static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, | 
 | 95 |         Vector<Rect>& dst, int spanDirection) { | 
 | 96 |     dst.clear(); | 
 | 97 |  | 
 | 98 |     const Rect* current = end - 1; | 
 | 99 |     int lastTop = current->top; | 
 | 100 |  | 
 | 101 |     // add first span immediately | 
 | 102 |     do { | 
 | 103 |         dst.add(*current); | 
 | 104 |         current--; | 
 | 105 |     } while (current->top == lastTop && current >= begin); | 
 | 106 |  | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 107 |     int beginLastSpan = -1; | 
 | 108 |     int endLastSpan = -1; | 
| Chris Craik | 3e010f3 | 2013-02-25 19:12:47 -0800 | [diff] [blame] | 109 |     int top = -1; | 
 | 110 |     int bottom = -1; | 
 | 111 |  | 
 | 112 |     // for all other spans, split if a t-junction exists in the span directly above | 
 | 113 |     while (current >= begin) { | 
 | 114 |         if (current->top != (current + 1)->top) { | 
 | 115 |             // new span | 
 | 116 |             if ((spanDirection == direction_RTL && current->bottom != (current + 1)->top) || | 
 | 117 |                     (spanDirection == direction_LTR && current->top != (current + 1)->bottom)) { | 
 | 118 |                 // previous span not directly adjacent, don't check for T junctions | 
 | 119 |                 beginLastSpan = INT_MAX; | 
 | 120 |             } else { | 
 | 121 |                 beginLastSpan = endLastSpan + 1; | 
 | 122 |             } | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 123 |             endLastSpan = static_cast<int>(dst.size()) - 1; | 
| Chris Craik | 3e010f3 | 2013-02-25 19:12:47 -0800 | [diff] [blame] | 124 |  | 
 | 125 |             top = current->top; | 
 | 126 |             bottom = current->bottom; | 
 | 127 |         } | 
 | 128 |         int left = current->left; | 
 | 129 |         int right = current->right; | 
 | 130 |  | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 131 |         for (int prevIndex = beginLastSpan; prevIndex <= endLastSpan; prevIndex++) { | 
 | 132 |             // prevIndex can't be -1 here because if endLastSpan is set to a | 
 | 133 |             // value greater than -1 (allowing the loop to execute), | 
 | 134 |             // beginLastSpan (and therefore prevIndex) will also be increased | 
| ywen | aef0445 | 2015-03-26 19:51:12 +0800 | [diff] [blame] | 135 |             const Rect prev = dst[static_cast<size_t>(prevIndex)]; | 
| Chris Craik | 3e010f3 | 2013-02-25 19:12:47 -0800 | [diff] [blame] | 136 |             if (spanDirection == direction_RTL) { | 
 | 137 |                 // iterating over previous span RTL, quit if it's too far left | 
| ywen | aef0445 | 2015-03-26 19:51:12 +0800 | [diff] [blame] | 138 |                 if (prev.right <= left) break; | 
| Chris Craik | 3e010f3 | 2013-02-25 19:12:47 -0800 | [diff] [blame] | 139 |  | 
| ywen | aef0445 | 2015-03-26 19:51:12 +0800 | [diff] [blame] | 140 |                 if (prev.right > left && prev.right < right) { | 
 | 141 |                     dst.add(Rect(prev.right, top, right, bottom)); | 
 | 142 |                     right = prev.right; | 
| Chris Craik | 3e010f3 | 2013-02-25 19:12:47 -0800 | [diff] [blame] | 143 |                 } | 
 | 144 |  | 
| ywen | aef0445 | 2015-03-26 19:51:12 +0800 | [diff] [blame] | 145 |                 if (prev.left > left && prev.left < right) { | 
 | 146 |                     dst.add(Rect(prev.left, top, right, bottom)); | 
 | 147 |                     right = prev.left; | 
| Chris Craik | 3e010f3 | 2013-02-25 19:12:47 -0800 | [diff] [blame] | 148 |                 } | 
 | 149 |  | 
 | 150 |                 // if an entry in the previous span is too far right, nothing further left in the | 
 | 151 |                 // current span will need it | 
| ywen | aef0445 | 2015-03-26 19:51:12 +0800 | [diff] [blame] | 152 |                 if (prev.left >= right) { | 
| Chris Craik | 3e010f3 | 2013-02-25 19:12:47 -0800 | [diff] [blame] | 153 |                     beginLastSpan = prevIndex; | 
 | 154 |                 } | 
 | 155 |             } else { | 
 | 156 |                 // iterating over previous span LTR, quit if it's too far right | 
| ywen | aef0445 | 2015-03-26 19:51:12 +0800 | [diff] [blame] | 157 |                 if (prev.left >= right) break; | 
| Chris Craik | 3e010f3 | 2013-02-25 19:12:47 -0800 | [diff] [blame] | 158 |  | 
| ywen | aef0445 | 2015-03-26 19:51:12 +0800 | [diff] [blame] | 159 |                 if (prev.left > left && prev.left < right) { | 
 | 160 |                     dst.add(Rect(left, top, prev.left, bottom)); | 
 | 161 |                     left = prev.left; | 
| Chris Craik | 3e010f3 | 2013-02-25 19:12:47 -0800 | [diff] [blame] | 162 |                 } | 
 | 163 |  | 
| ywen | aef0445 | 2015-03-26 19:51:12 +0800 | [diff] [blame] | 164 |                 if (prev.right > left && prev.right < right) { | 
 | 165 |                     dst.add(Rect(left, top, prev.right, bottom)); | 
 | 166 |                     left = prev.right; | 
| Chris Craik | 3e010f3 | 2013-02-25 19:12:47 -0800 | [diff] [blame] | 167 |                 } | 
 | 168 |                 // if an entry in the previous span is too far left, nothing further right in the | 
 | 169 |                 // current span will need it | 
| ywen | aef0445 | 2015-03-26 19:51:12 +0800 | [diff] [blame] | 170 |                 if (prev.right <= left) { | 
| Chris Craik | 3e010f3 | 2013-02-25 19:12:47 -0800 | [diff] [blame] | 171 |                     beginLastSpan = prevIndex; | 
 | 172 |                 } | 
 | 173 |             } | 
 | 174 |         } | 
 | 175 |  | 
 | 176 |         if (left < right) { | 
 | 177 |             dst.add(Rect(left, top, right, bottom)); | 
 | 178 |         } | 
 | 179 |  | 
 | 180 |         current--; | 
 | 181 |     } | 
 | 182 | } | 
 | 183 |  | 
 | 184 | /** | 
 | 185 |  * Creates a new region with the same data as the argument, but divides rectangles as necessary to | 
 | 186 |  * remove T-Junctions | 
 | 187 |  * | 
 | 188 |  * Note: the output will not necessarily be a very efficient representation of the region, since it | 
 | 189 |  * may be that a triangle-based approach would generate significantly simpler geometry | 
 | 190 |  */ | 
 | 191 | Region Region::createTJunctionFreeRegion(const Region& r) { | 
 | 192 |     if (r.isEmpty()) return r; | 
 | 193 |     if (r.isRect()) return r; | 
 | 194 |  | 
 | 195 |     Vector<Rect> reversed; | 
 | 196 |     reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL); | 
 | 197 |  | 
 | 198 |     Region outputRegion; | 
 | 199 |     reverseRectsResolvingJunctions(reversed.begin(), reversed.end(), | 
 | 200 |             outputRegion.mStorage, direction_LTR); | 
 | 201 |     outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds | 
 | 202 |  | 
 | 203 | #if VALIDATE_REGIONS | 
 | 204 |     validate(outputRegion, "T-Junction free region"); | 
 | 205 | #endif | 
 | 206 |  | 
 | 207 |     return outputRegion; | 
 | 208 | } | 
 | 209 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 210 | Region& Region::operator = (const Region& rhs) | 
 | 211 | { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 212 | #if VALIDATE_REGIONS | 
| Mathias Agopian | d0b55c0 | 2011-03-16 23:18:07 -0700 | [diff] [blame] | 213 |     validate(*this, "this->operator="); | 
 | 214 |     validate(rhs, "rhs.operator="); | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 215 | #endif | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 216 |     mStorage = rhs.mStorage; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 217 |     return *this; | 
 | 218 | } | 
 | 219 |  | 
| Mathias Agopian | 9f96145 | 2009-06-29 18:46:37 -0700 | [diff] [blame] | 220 | Region& Region::makeBoundsSelf() | 
 | 221 | { | 
| Mathias Agopian | 3ab6855 | 2012-08-31 14:31:40 -0700 | [diff] [blame] | 222 |     if (mStorage.size() >= 2) { | 
 | 223 |         const Rect bounds(getBounds()); | 
 | 224 |         mStorage.clear(); | 
 | 225 |         mStorage.add(bounds); | 
 | 226 |     } | 
| Mathias Agopian | 9f96145 | 2009-06-29 18:46:37 -0700 | [diff] [blame] | 227 |     return *this; | 
 | 228 | } | 
 | 229 |  | 
| Michael Wright | 1c284a9 | 2014-02-10 13:00:14 -0800 | [diff] [blame] | 230 | bool Region::contains(const Point& point) const { | 
 | 231 |     return contains(point.x, point.y); | 
 | 232 | } | 
 | 233 |  | 
 | 234 | bool Region::contains(int x, int y) const { | 
 | 235 |     const_iterator cur = begin(); | 
 | 236 |     const_iterator const tail = end(); | 
 | 237 |     while (cur != tail) { | 
 | 238 |         if (y >= cur->top && y < cur->bottom && x >= cur->left && x < cur->right) { | 
 | 239 |             return true; | 
 | 240 |         } | 
 | 241 |         cur++; | 
 | 242 |     } | 
 | 243 |     return false; | 
 | 244 | } | 
 | 245 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 246 | void Region::clear() | 
 | 247 | { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 248 |     mStorage.clear(); | 
| Mathias Agopian | 3ab6855 | 2012-08-31 14:31:40 -0700 | [diff] [blame] | 249 |     mStorage.add(Rect(0,0)); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 250 | } | 
 | 251 |  | 
 | 252 | void Region::set(const Rect& r) | 
 | 253 | { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 254 |     mStorage.clear(); | 
| Mathias Agopian | 3ab6855 | 2012-08-31 14:31:40 -0700 | [diff] [blame] | 255 |     mStorage.add(r); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 256 | } | 
 | 257 |  | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 258 | void Region::set(int32_t w, int32_t h) | 
| Mathias Agopian | 0926f50 | 2009-05-04 14:17:04 -0700 | [diff] [blame] | 259 | { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 260 |     mStorage.clear(); | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 261 |     mStorage.add(Rect(w, h)); | 
| Mathias Agopian | 0926f50 | 2009-05-04 14:17:04 -0700 | [diff] [blame] | 262 | } | 
 | 263 |  | 
| Bernhard Rosenkraenzer | fe4966d | 2014-12-22 21:15:08 +0100 | [diff] [blame] | 264 | void Region::set(uint32_t w, uint32_t h) | 
 | 265 | { | 
 | 266 |     mStorage.clear(); | 
 | 267 |     mStorage.add(Rect(w, h)); | 
 | 268 | } | 
 | 269 |  | 
| Mathias Agopian | 2ca7939 | 2013-04-02 18:30:32 -0700 | [diff] [blame] | 270 | bool Region::isTriviallyEqual(const Region& region) const { | 
 | 271 |     return begin() == region.begin(); | 
 | 272 | } | 
 | 273 |  | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 274 | // ---------------------------------------------------------------------------- | 
 | 275 |  | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 276 | void Region::addRectUnchecked(int l, int t, int r, int b) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 277 | { | 
| Mathias Agopian | 3ab6855 | 2012-08-31 14:31:40 -0700 | [diff] [blame] | 278 |     Rect rect(l,t,r,b); | 
 | 279 |     size_t where = mStorage.size() - 1; | 
 | 280 |     mStorage.insertAt(rect, where, 1); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 281 | } | 
 | 282 |  | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 283 | // ---------------------------------------------------------------------------- | 
 | 284 |  | 
 | 285 | Region& Region::orSelf(const Rect& r) { | 
 | 286 |     return operationSelf(r, op_or); | 
 | 287 | } | 
| Romain Guy | b8a2e98 | 2012-02-07 17:04:34 -0800 | [diff] [blame] | 288 | Region& Region::xorSelf(const Rect& r) { | 
 | 289 |     return operationSelf(r, op_xor); | 
 | 290 | } | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 291 | Region& Region::andSelf(const Rect& r) { | 
 | 292 |     return operationSelf(r, op_and); | 
 | 293 | } | 
 | 294 | Region& Region::subtractSelf(const Rect& r) { | 
 | 295 |     return operationSelf(r, op_nand); | 
 | 296 | } | 
| Colin Cross | 8f27996 | 2016-09-26 13:08:16 -0700 | [diff] [blame] | 297 | Region& Region::operationSelf(const Rect& r, uint32_t op) { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 298 |     Region lhs(*this); | 
 | 299 |     boolean_operation(op, *this, lhs, r); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 300 |     return *this; | 
 | 301 | } | 
 | 302 |  | 
 | 303 | // ---------------------------------------------------------------------------- | 
 | 304 |  | 
 | 305 | Region& Region::orSelf(const Region& rhs) { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 306 |     return operationSelf(rhs, op_or); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 307 | } | 
| Romain Guy | b8a2e98 | 2012-02-07 17:04:34 -0800 | [diff] [blame] | 308 | Region& Region::xorSelf(const Region& rhs) { | 
 | 309 |     return operationSelf(rhs, op_xor); | 
 | 310 | } | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 311 | Region& Region::andSelf(const Region& rhs) { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 312 |     return operationSelf(rhs, op_and); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 313 | } | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 314 | Region& Region::subtractSelf(const Region& rhs) { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 315 |     return operationSelf(rhs, op_nand); | 
 | 316 | } | 
| Colin Cross | 8f27996 | 2016-09-26 13:08:16 -0700 | [diff] [blame] | 317 | Region& Region::operationSelf(const Region& rhs, uint32_t op) { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 318 |     Region lhs(*this); | 
 | 319 |     boolean_operation(op, *this, lhs, rhs); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 320 |     return *this; | 
 | 321 | } | 
 | 322 |  | 
 | 323 | Region& Region::translateSelf(int x, int y) { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 324 |     if (x|y) translate(*this, x, y); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 325 |     return *this; | 
 | 326 | } | 
 | 327 |  | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 328 | // ---------------------------------------------------------------------------- | 
 | 329 |  | 
| Mathias Agopian | bed9dd1 | 2009-05-27 17:01:58 -0700 | [diff] [blame] | 330 | const Region Region::merge(const Rect& rhs) const { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 331 |     return operation(rhs, op_or); | 
 | 332 | } | 
| Romain Guy | b8a2e98 | 2012-02-07 17:04:34 -0800 | [diff] [blame] | 333 | const Region Region::mergeExclusive(const Rect& rhs) const { | 
 | 334 |     return operation(rhs, op_xor); | 
 | 335 | } | 
| Mathias Agopian | bed9dd1 | 2009-05-27 17:01:58 -0700 | [diff] [blame] | 336 | const Region Region::intersect(const Rect& rhs) const { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 337 |     return operation(rhs, op_and); | 
 | 338 | } | 
| Mathias Agopian | bed9dd1 | 2009-05-27 17:01:58 -0700 | [diff] [blame] | 339 | const Region Region::subtract(const Rect& rhs) const { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 340 |     return operation(rhs, op_nand); | 
 | 341 | } | 
| Colin Cross | 8f27996 | 2016-09-26 13:08:16 -0700 | [diff] [blame] | 342 | const Region Region::operation(const Rect& rhs, uint32_t op) const { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 343 |     Region result; | 
 | 344 |     boolean_operation(op, result, *this, rhs); | 
 | 345 |     return result; | 
 | 346 | } | 
 | 347 |  | 
 | 348 | // ---------------------------------------------------------------------------- | 
 | 349 |  | 
| Mathias Agopian | bed9dd1 | 2009-05-27 17:01:58 -0700 | [diff] [blame] | 350 | const Region Region::merge(const Region& rhs) const { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 351 |     return operation(rhs, op_or); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 352 | } | 
| Romain Guy | b8a2e98 | 2012-02-07 17:04:34 -0800 | [diff] [blame] | 353 | const Region Region::mergeExclusive(const Region& rhs) const { | 
 | 354 |     return operation(rhs, op_xor); | 
 | 355 | } | 
| Mathias Agopian | bed9dd1 | 2009-05-27 17:01:58 -0700 | [diff] [blame] | 356 | const Region Region::intersect(const Region& rhs) const { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 357 |     return operation(rhs, op_and); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 358 | } | 
| Mathias Agopian | bed9dd1 | 2009-05-27 17:01:58 -0700 | [diff] [blame] | 359 | const Region Region::subtract(const Region& rhs) const { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 360 |     return operation(rhs, op_nand); | 
 | 361 | } | 
| Colin Cross | 8f27996 | 2016-09-26 13:08:16 -0700 | [diff] [blame] | 362 | const Region Region::operation(const Region& rhs, uint32_t op) const { | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 363 |     Region result; | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 364 |     boolean_operation(op, result, *this, rhs); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 365 |     return result; | 
 | 366 | } | 
 | 367 |  | 
| Mathias Agopian | bed9dd1 | 2009-05-27 17:01:58 -0700 | [diff] [blame] | 368 | const Region Region::translate(int x, int y) const { | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 369 |     Region result; | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 370 |     translate(result, *this, x, y); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 371 |     return result; | 
 | 372 | } | 
 | 373 |  | 
 | 374 | // ---------------------------------------------------------------------------- | 
 | 375 |  | 
 | 376 | Region& Region::orSelf(const Region& rhs, int dx, int dy) { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 377 |     return operationSelf(rhs, dx, dy, op_or); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 378 | } | 
| Romain Guy | b8a2e98 | 2012-02-07 17:04:34 -0800 | [diff] [blame] | 379 | Region& Region::xorSelf(const Region& rhs, int dx, int dy) { | 
 | 380 |     return operationSelf(rhs, dx, dy, op_xor); | 
 | 381 | } | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 382 | Region& Region::andSelf(const Region& rhs, int dx, int dy) { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 383 |     return operationSelf(rhs, dx, dy, op_and); | 
 | 384 | } | 
 | 385 | Region& Region::subtractSelf(const Region& rhs, int dx, int dy) { | 
 | 386 |     return operationSelf(rhs, dx, dy, op_nand); | 
 | 387 | } | 
| Colin Cross | 8f27996 | 2016-09-26 13:08:16 -0700 | [diff] [blame] | 388 | Region& Region::operationSelf(const Region& rhs, int dx, int dy, uint32_t op) { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 389 |     Region lhs(*this); | 
 | 390 |     boolean_operation(op, *this, lhs, rhs, dx, dy); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 391 |     return *this; | 
 | 392 | } | 
 | 393 |  | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 394 | // ---------------------------------------------------------------------------- | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 395 |  | 
| Mathias Agopian | bed9dd1 | 2009-05-27 17:01:58 -0700 | [diff] [blame] | 396 | const Region Region::merge(const Region& rhs, int dx, int dy) const { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 397 |     return operation(rhs, dx, dy, op_or); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 398 | } | 
| Romain Guy | b8a2e98 | 2012-02-07 17:04:34 -0800 | [diff] [blame] | 399 | const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const { | 
 | 400 |     return operation(rhs, dx, dy, op_xor); | 
 | 401 | } | 
| Mathias Agopian | bed9dd1 | 2009-05-27 17:01:58 -0700 | [diff] [blame] | 402 | const Region Region::intersect(const Region& rhs, int dx, int dy) const { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 403 |     return operation(rhs, dx, dy, op_and); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 404 | } | 
| Mathias Agopian | bed9dd1 | 2009-05-27 17:01:58 -0700 | [diff] [blame] | 405 | const Region Region::subtract(const Region& rhs, int dx, int dy) const { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 406 |     return operation(rhs, dx, dy, op_nand); | 
 | 407 | } | 
| Colin Cross | 8f27996 | 2016-09-26 13:08:16 -0700 | [diff] [blame] | 408 | const Region Region::operation(const Region& rhs, int dx, int dy, uint32_t op) const { | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 409 |     Region result; | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 410 |     boolean_operation(op, result, *this, rhs, dx, dy); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 411 |     return result; | 
 | 412 | } | 
 | 413 |  | 
 | 414 | // ---------------------------------------------------------------------------- | 
 | 415 |  | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 416 | // This is our region rasterizer, which merges rects and spans together | 
 | 417 | // to obtain an optimal region. | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 418 | class Region::rasterizer : public region_operator<Rect>::region_rasterizer | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 419 | { | 
| Mathias Agopian | 3ab6855 | 2012-08-31 14:31:40 -0700 | [diff] [blame] | 420 |     Rect bounds; | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 421 |     Vector<Rect>& storage; | 
 | 422 |     Rect* head; | 
 | 423 |     Rect* tail; | 
 | 424 |     Vector<Rect> span; | 
 | 425 |     Rect* cur; | 
 | 426 | public: | 
| Chih-Hung Hsieh | e2347b7 | 2016-04-25 15:41:05 -0700 | [diff] [blame] | 427 |     explicit rasterizer(Region& reg) | 
| Mathias Agopian | 3ab6855 | 2012-08-31 14:31:40 -0700 | [diff] [blame] | 428 |         : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 429 |         storage.clear(); | 
 | 430 |     } | 
 | 431 |  | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 432 |     virtual ~rasterizer(); | 
 | 433 |  | 
 | 434 |     virtual void operator()(const Rect& rect); | 
 | 435 |  | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 436 | private: | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 437 |     template<typename T> | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 438 |     static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; } | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 439 |     template<typename T> | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 440 |     static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; } | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 441 |  | 
 | 442 |     void flushSpan(); | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 443 | }; | 
 | 444 |  | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 445 | Region::rasterizer::~rasterizer() | 
 | 446 | { | 
 | 447 |     if (span.size()) { | 
 | 448 |         flushSpan(); | 
 | 449 |     } | 
 | 450 |     if (storage.size()) { | 
 | 451 |         bounds.top = storage.itemAt(0).top; | 
 | 452 |         bounds.bottom = storage.top().bottom; | 
 | 453 |         if (storage.size() == 1) { | 
 | 454 |             storage.clear(); | 
 | 455 |         } | 
 | 456 |     } else { | 
 | 457 |         bounds.left  = 0; | 
 | 458 |         bounds.right = 0; | 
 | 459 |     } | 
 | 460 |     storage.add(bounds); | 
 | 461 | } | 
 | 462 |  | 
 | 463 | void Region::rasterizer::operator()(const Rect& rect) | 
 | 464 | { | 
 | 465 |     //ALOGD(">>> %3d, %3d, %3d, %3d", | 
 | 466 |     //        rect.left, rect.top, rect.right, rect.bottom); | 
 | 467 |     if (span.size()) { | 
 | 468 |         if (cur->top != rect.top) { | 
 | 469 |             flushSpan(); | 
 | 470 |         } else if (cur->right == rect.left) { | 
 | 471 |             cur->right = rect.right; | 
 | 472 |             return; | 
 | 473 |         } | 
 | 474 |     } | 
 | 475 |     span.add(rect); | 
 | 476 |     cur = span.editArray() + (span.size() - 1); | 
 | 477 | } | 
 | 478 |  | 
 | 479 | void Region::rasterizer::flushSpan() | 
 | 480 | { | 
 | 481 |     bool merge = false; | 
 | 482 |     if (tail-head == ssize_t(span.size())) { | 
 | 483 |         Rect const* p = span.editArray(); | 
 | 484 |         Rect const* q = head; | 
 | 485 |         if (p->top == q->bottom) { | 
 | 486 |             merge = true; | 
 | 487 |             while (q != tail) { | 
 | 488 |                 if ((p->left != q->left) || (p->right != q->right)) { | 
 | 489 |                     merge = false; | 
 | 490 |                     break; | 
 | 491 |                 } | 
| Stephen Hines | 9c22c3c | 2016-03-31 22:02:38 -0700 | [diff] [blame] | 492 |                 p++; | 
 | 493 |                 q++; | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 494 |             } | 
 | 495 |         } | 
 | 496 |     } | 
 | 497 |     if (merge) { | 
 | 498 |         const int bottom = span[0].bottom; | 
 | 499 |         Rect* r = head; | 
 | 500 |         while (r != tail) { | 
 | 501 |             r->bottom = bottom; | 
 | 502 |             r++; | 
 | 503 |         } | 
 | 504 |     } else { | 
 | 505 |         bounds.left = min(span.itemAt(0).left, bounds.left); | 
 | 506 |         bounds.right = max(span.top().right, bounds.right); | 
 | 507 |         storage.appendVector(span); | 
 | 508 |         tail = storage.editArray() + storage.size(); | 
 | 509 |         head = tail - span.size(); | 
 | 510 |     } | 
 | 511 |     span.clear(); | 
 | 512 | } | 
 | 513 |  | 
| Mathias Agopian | 068d47f | 2012-09-11 18:56:23 -0700 | [diff] [blame] | 514 | bool Region::validate(const Region& reg, const char* name, bool silent) | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 515 | { | 
 | 516 |     bool result = true; | 
 | 517 |     const_iterator cur = reg.begin(); | 
 | 518 |     const_iterator const tail = reg.end(); | 
| Mathias Agopian | 068d47f | 2012-09-11 18:56:23 -0700 | [diff] [blame] | 519 |     const_iterator prev = cur; | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 520 |     Rect b(*prev); | 
 | 521 |     while (cur != tail) { | 
| Mathias Agopian | 068d47f | 2012-09-11 18:56:23 -0700 | [diff] [blame] | 522 |         if (cur->isValid() == false) { | 
| Dan Stoza | 5065a55 | 2015-03-17 16:23:42 -0700 | [diff] [blame] | 523 |             // We allow this particular flavor of invalid Rect, since it is used | 
 | 524 |             // as a signal value in various parts of the system | 
 | 525 |             if (*cur != Rect::INVALID_RECT) { | 
 | 526 |                 ALOGE_IF(!silent, "%s: region contains an invalid Rect", name); | 
 | 527 |                 result = false; | 
 | 528 |             } | 
| Mathias Agopian | 068d47f | 2012-09-11 18:56:23 -0700 | [diff] [blame] | 529 |         } | 
 | 530 |         if (cur->right > region_operator<Rect>::max_value) { | 
 | 531 |             ALOGE_IF(!silent, "%s: rect->right > max_value", name); | 
 | 532 |             result = false; | 
 | 533 |         } | 
 | 534 |         if (cur->bottom > region_operator<Rect>::max_value) { | 
 | 535 |             ALOGE_IF(!silent, "%s: rect->right > max_value", name); | 
 | 536 |             result = false; | 
 | 537 |         } | 
 | 538 |         if (prev != cur) { | 
 | 539 |             b.left   = b.left   < cur->left   ? b.left   : cur->left; | 
 | 540 |             b.top    = b.top    < cur->top    ? b.top    : cur->top; | 
 | 541 |             b.right  = b.right  > cur->right  ? b.right  : cur->right; | 
 | 542 |             b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom; | 
 | 543 |             if ((*prev < *cur) == false) { | 
 | 544 |                 ALOGE_IF(!silent, "%s: region's Rects not sorted", name); | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 545 |                 result = false; | 
| Mathias Agopian | 068d47f | 2012-09-11 18:56:23 -0700 | [diff] [blame] | 546 |             } | 
 | 547 |             if (cur->top == prev->top) { | 
 | 548 |                 if (cur->bottom != prev->bottom) { | 
 | 549 |                     ALOGE_IF(!silent, "%s: invalid span %p", name, cur); | 
 | 550 |                     result = false; | 
 | 551 |                 } else if (cur->left < prev->right) { | 
 | 552 |                     ALOGE_IF(!silent, | 
 | 553 |                             "%s: spans overlap horizontally prev=%p, cur=%p", | 
 | 554 |                             name, prev, cur); | 
 | 555 |                     result = false; | 
 | 556 |                 } | 
 | 557 |             } else if (cur->top < prev->bottom) { | 
 | 558 |                 ALOGE_IF(!silent, | 
 | 559 |                         "%s: spans overlap vertically prev=%p, cur=%p", | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 560 |                         name, prev, cur); | 
 | 561 |                 result = false; | 
 | 562 |             } | 
| Mathias Agopian | 068d47f | 2012-09-11 18:56:23 -0700 | [diff] [blame] | 563 |             prev = cur; | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 564 |         } | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 565 |         cur++; | 
 | 566 |     } | 
 | 567 |     if (b != reg.getBounds()) { | 
 | 568 |         result = false; | 
| Mathias Agopian | 068d47f | 2012-09-11 18:56:23 -0700 | [diff] [blame] | 569 |         ALOGE_IF(!silent, | 
 | 570 |                 "%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name, | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 571 |                 b.left, b.top, b.right, b.bottom, | 
 | 572 |                 reg.getBounds().left, reg.getBounds().top,  | 
 | 573 |                 reg.getBounds().right, reg.getBounds().bottom); | 
 | 574 |     } | 
| Mathias Agopian | 3ab6855 | 2012-08-31 14:31:40 -0700 | [diff] [blame] | 575 |     if (reg.mStorage.size() == 2) { | 
| Mathias Agopian | 068d47f | 2012-09-11 18:56:23 -0700 | [diff] [blame] | 576 |         result = false; | 
 | 577 |         ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name); | 
| Mathias Agopian | 3ab6855 | 2012-08-31 14:31:40 -0700 | [diff] [blame] | 578 |     } | 
| Mathias Agopian | 068d47f | 2012-09-11 18:56:23 -0700 | [diff] [blame] | 579 |     if (result == false && !silent) { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 580 |         reg.dump(name); | 
| Mathias Agopian | cab25d6 | 2013-03-21 17:12:40 -0700 | [diff] [blame] | 581 |         CallStack stack(LOG_TAG); | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 582 |     } | 
 | 583 |     return result; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 584 | } | 
 | 585 |  | 
| Colin Cross | 8f27996 | 2016-09-26 13:08:16 -0700 | [diff] [blame] | 586 | void Region::boolean_operation(uint32_t op, Region& dst, | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 587 |         const Region& lhs, | 
 | 588 |         const Region& rhs, int dx, int dy) | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 589 | { | 
| Mathias Agopian | d0b55c0 | 2011-03-16 23:18:07 -0700 | [diff] [blame] | 590 | #if VALIDATE_REGIONS | 
 | 591 |     validate(lhs, "boolean_operation (before): lhs"); | 
 | 592 |     validate(rhs, "boolean_operation (before): rhs"); | 
 | 593 |     validate(dst, "boolean_operation (before): dst"); | 
 | 594 | #endif | 
 | 595 |  | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 596 |     size_t lhs_count; | 
 | 597 |     Rect const * const lhs_rects = lhs.getArray(&lhs_count); | 
 | 598 |  | 
 | 599 |     size_t rhs_count; | 
 | 600 |     Rect const * const rhs_rects = rhs.getArray(&rhs_count); | 
 | 601 |  | 
 | 602 |     region_operator<Rect>::region lhs_region(lhs_rects, lhs_count); | 
 | 603 |     region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy); | 
 | 604 |     region_operator<Rect> operation(op, lhs_region, rhs_region); | 
 | 605 |     { // scope for rasterizer (dtor has side effects) | 
 | 606 |         rasterizer r(dst); | 
 | 607 |         operation(r); | 
 | 608 |     } | 
 | 609 |  | 
 | 610 | #if VALIDATE_REGIONS | 
 | 611 |     validate(lhs, "boolean_operation: lhs"); | 
 | 612 |     validate(rhs, "boolean_operation: rhs"); | 
 | 613 |     validate(dst, "boolean_operation: dst"); | 
 | 614 | #endif | 
 | 615 |  | 
 | 616 | #if VALIDATE_WITH_CORECG | 
 | 617 |     SkRegion sk_lhs; | 
 | 618 |     SkRegion sk_rhs; | 
 | 619 |     SkRegion sk_dst; | 
 | 620 |      | 
 | 621 |     for (size_t i=0 ; i<lhs_count ; i++) | 
 | 622 |         sk_lhs.op( | 
 | 623 |                 lhs_rects[i].left   + dx, | 
 | 624 |                 lhs_rects[i].top    + dy, | 
 | 625 |                 lhs_rects[i].right  + dx, | 
 | 626 |                 lhs_rects[i].bottom + dy, | 
 | 627 |                 SkRegion::kUnion_Op); | 
 | 628 |      | 
 | 629 |     for (size_t i=0 ; i<rhs_count ; i++) | 
 | 630 |         sk_rhs.op( | 
 | 631 |                 rhs_rects[i].left   + dx, | 
 | 632 |                 rhs_rects[i].top    + dy, | 
 | 633 |                 rhs_rects[i].right  + dx, | 
 | 634 |                 rhs_rects[i].bottom + dy, | 
 | 635 |                 SkRegion::kUnion_Op); | 
 | 636 |   | 
 | 637 |     const char* name = "---"; | 
 | 638 |     SkRegion::Op sk_op; | 
 | 639 |     switch (op) { | 
 | 640 |         case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break; | 
| Romain Guy | b8a2e98 | 2012-02-07 17:04:34 -0800 | [diff] [blame] | 641 |         case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break; | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 642 |         case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break; | 
 | 643 |         case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break; | 
 | 644 |     } | 
 | 645 |     sk_dst.op(sk_lhs, sk_rhs, sk_op); | 
 | 646 |  | 
 | 647 |     if (sk_dst.isEmpty() && dst.isEmpty()) | 
 | 648 |         return; | 
 | 649 |      | 
 | 650 |     bool same = true; | 
 | 651 |     Region::const_iterator head = dst.begin(); | 
 | 652 |     Region::const_iterator const tail = dst.end(); | 
 | 653 |     SkRegion::Iterator it(sk_dst); | 
 | 654 |     while (!it.done()) { | 
 | 655 |         if (head != tail) { | 
 | 656 |             if ( | 
 | 657 |                     head->left != it.rect().fLeft ||      | 
 | 658 |                     head->top != it.rect().fTop ||      | 
 | 659 |                     head->right != it.rect().fRight ||      | 
 | 660 |                     head->bottom != it.rect().fBottom | 
 | 661 |             ) { | 
 | 662 |                 same = false; | 
 | 663 |                 break; | 
 | 664 |             } | 
 | 665 |         } else { | 
 | 666 |             same = false; | 
 | 667 |             break; | 
 | 668 |         } | 
 | 669 |         head++; | 
 | 670 |         it.next(); | 
 | 671 |     } | 
 | 672 |      | 
 | 673 |     if (head != tail) { | 
 | 674 |         same = false; | 
 | 675 |     } | 
 | 676 |      | 
 | 677 |     if(!same) { | 
| Steve Block | 9d45368 | 2011-12-20 16:23:08 +0000 | [diff] [blame] | 678 |         ALOGD("---\nregion boolean %s failed", name); | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 679 |         lhs.dump("lhs"); | 
 | 680 |         rhs.dump("rhs"); | 
 | 681 |         dst.dump("dst"); | 
| Steve Block | 9d45368 | 2011-12-20 16:23:08 +0000 | [diff] [blame] | 682 |         ALOGD("should be"); | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 683 |         SkRegion::Iterator it(sk_dst); | 
 | 684 |         while (!it.done()) { | 
| Steve Block | 9d45368 | 2011-12-20 16:23:08 +0000 | [diff] [blame] | 685 |             ALOGD("    [%3d, %3d, %3d, %3d]", | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 686 |                 it.rect().fLeft, | 
 | 687 |                 it.rect().fTop, | 
 | 688 |                 it.rect().fRight, | 
 | 689 |                 it.rect().fBottom); | 
 | 690 |             it.next(); | 
 | 691 |         } | 
 | 692 |     } | 
 | 693 | #endif | 
 | 694 | } | 
 | 695 |  | 
| Colin Cross | 8f27996 | 2016-09-26 13:08:16 -0700 | [diff] [blame] | 696 | void Region::boolean_operation(uint32_t op, Region& dst, | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 697 |         const Region& lhs, | 
 | 698 |         const Rect& rhs, int dx, int dy) | 
 | 699 | { | 
| Dan Stoza | 5065a55 | 2015-03-17 16:23:42 -0700 | [diff] [blame] | 700 |     // We allow this particular flavor of invalid Rect, since it is used as a | 
 | 701 |     // signal value in various parts of the system | 
 | 702 |     if (!rhs.isValid() && rhs != Rect::INVALID_RECT) { | 
| Steve Block | e6f43dd | 2012-01-06 19:20:56 +0000 | [diff] [blame] | 703 |         ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}", | 
| Mathias Agopian | 0450452 | 2011-09-19 16:12:08 -0700 | [diff] [blame] | 704 |                 op, rhs.left, rhs.top, rhs.right, rhs.bottom); | 
| Mathias Agopian | 0857c8f | 2011-09-26 15:58:20 -0700 | [diff] [blame] | 705 |         return; | 
| Mathias Agopian | 0450452 | 2011-09-19 16:12:08 -0700 | [diff] [blame] | 706 |     } | 
 | 707 |  | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 708 | #if VALIDATE_WITH_CORECG || VALIDATE_REGIONS | 
 | 709 |     boolean_operation(op, dst, lhs, Region(rhs), dx, dy); | 
 | 710 | #else | 
 | 711 |     size_t lhs_count; | 
 | 712 |     Rect const * const lhs_rects = lhs.getArray(&lhs_count); | 
 | 713 |  | 
 | 714 |     region_operator<Rect>::region lhs_region(lhs_rects, lhs_count); | 
 | 715 |     region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy); | 
 | 716 |     region_operator<Rect> operation(op, lhs_region, rhs_region); | 
 | 717 |     { // scope for rasterizer (dtor has side effects) | 
 | 718 |         rasterizer r(dst); | 
 | 719 |         operation(r); | 
 | 720 |     } | 
 | 721 |  | 
 | 722 | #endif | 
 | 723 | } | 
 | 724 |  | 
| Colin Cross | 8f27996 | 2016-09-26 13:08:16 -0700 | [diff] [blame] | 725 | void Region::boolean_operation(uint32_t op, Region& dst, | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 726 |         const Region& lhs, const Region& rhs) | 
 | 727 | { | 
 | 728 |     boolean_operation(op, dst, lhs, rhs, 0, 0); | 
 | 729 | } | 
 | 730 |  | 
| Colin Cross | 8f27996 | 2016-09-26 13:08:16 -0700 | [diff] [blame] | 731 | void Region::boolean_operation(uint32_t op, Region& dst, | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 732 |         const Region& lhs, const Rect& rhs) | 
 | 733 | { | 
 | 734 |     boolean_operation(op, dst, lhs, rhs, 0, 0); | 
 | 735 | } | 
 | 736 |  | 
 | 737 | void Region::translate(Region& reg, int dx, int dy) | 
 | 738 | { | 
| Mathias Agopian | 4c0a170 | 2012-08-31 12:45:33 -0700 | [diff] [blame] | 739 |     if ((dx || dy) && !reg.isEmpty()) { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 740 | #if VALIDATE_REGIONS | 
 | 741 |         validate(reg, "translate (before)"); | 
 | 742 | #endif | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 743 |         size_t count = reg.mStorage.size(); | 
 | 744 |         Rect* rects = reg.mStorage.editArray(); | 
 | 745 |         while (count) { | 
| Mathias Agopian | 6c7f25a | 2013-05-09 20:37:10 -0700 | [diff] [blame] | 746 |             rects->offsetBy(dx, dy); | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 747 |             rects++; | 
 | 748 |             count--; | 
 | 749 |         } | 
 | 750 | #if VALIDATE_REGIONS | 
 | 751 |         validate(reg, "translate (after)"); | 
 | 752 | #endif | 
 | 753 |     } | 
 | 754 | } | 
 | 755 |  | 
 | 756 | void Region::translate(Region& dst, const Region& reg, int dx, int dy) | 
 | 757 | { | 
 | 758 |     dst = reg; | 
 | 759 |     translate(dst, dx, dy); | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 760 | } | 
 | 761 |  | 
 | 762 | // ---------------------------------------------------------------------------- | 
 | 763 |  | 
| Mathias Agopian | e142428 | 2013-07-29 21:24:40 -0700 | [diff] [blame] | 764 | size_t Region::getFlattenedSize() const { | 
| Dan Stoza | 6fbefbb | 2015-03-23 13:46:14 -0700 | [diff] [blame] | 765 |     return sizeof(uint32_t) + mStorage.size() * sizeof(Rect); | 
| Mathias Agopian | 8683fca | 2012-08-12 19:37:16 -0700 | [diff] [blame] | 766 | } | 
 | 767 |  | 
| Mathias Agopian | e142428 | 2013-07-29 21:24:40 -0700 | [diff] [blame] | 768 | status_t Region::flatten(void* buffer, size_t size) const { | 
| Mathias Agopian | 068d47f | 2012-09-11 18:56:23 -0700 | [diff] [blame] | 769 | #if VALIDATE_REGIONS | 
 | 770 |     validate(*this, "Region::flatten"); | 
 | 771 | #endif | 
| Dan Stoza | 6fbefbb | 2015-03-23 13:46:14 -0700 | [diff] [blame] | 772 |     if (size < getFlattenedSize()) { | 
| Mathias Agopian | e142428 | 2013-07-29 21:24:40 -0700 | [diff] [blame] | 773 |         return NO_MEMORY; | 
 | 774 |     } | 
| Dan Stoza | 6fbefbb | 2015-03-23 13:46:14 -0700 | [diff] [blame] | 775 |     // Cast to uint32_t since the size of a size_t can vary between 32- and | 
 | 776 |     // 64-bit processes | 
 | 777 |     FlattenableUtils::write(buffer, size, static_cast<uint32_t>(mStorage.size())); | 
 | 778 |     for (auto rect : mStorage) { | 
 | 779 |         status_t result = rect.flatten(buffer, size); | 
 | 780 |         if (result != NO_ERROR) { | 
 | 781 |             return result; | 
 | 782 |         } | 
 | 783 |         FlattenableUtils::advance(buffer, size, sizeof(rect)); | 
 | 784 |     } | 
| Mathias Agopian | 8683fca | 2012-08-12 19:37:16 -0700 | [diff] [blame] | 785 |     return NO_ERROR; | 
 | 786 | } | 
 | 787 |  | 
 | 788 | status_t Region::unflatten(void const* buffer, size_t size) { | 
| Dan Stoza | 6fbefbb | 2015-03-23 13:46:14 -0700 | [diff] [blame] | 789 |     if (size < sizeof(uint32_t)) { | 
 | 790 |         return NO_MEMORY; | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 791 |     } | 
| Dan Stoza | 6fbefbb | 2015-03-23 13:46:14 -0700 | [diff] [blame] | 792 |  | 
 | 793 |     uint32_t numRects = 0; | 
 | 794 |     FlattenableUtils::read(buffer, size, numRects); | 
 | 795 |     if (size < numRects * sizeof(Rect)) { | 
 | 796 |         return NO_MEMORY; | 
 | 797 |     } | 
 | 798 |  | 
| Pablo Ceballos | 1a65fcc | 2016-07-13 14:11:57 -0700 | [diff] [blame] | 799 |     if (numRects > (UINT32_MAX / sizeof(Rect))) { | 
 | 800 |         android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, NULL, 0); | 
 | 801 |         return NO_MEMORY; | 
 | 802 |     } | 
 | 803 |  | 
| Dan Stoza | 6fbefbb | 2015-03-23 13:46:14 -0700 | [diff] [blame] | 804 |     Region result; | 
 | 805 |     result.mStorage.clear(); | 
 | 806 |     for (size_t r = 0; r < numRects; ++r) { | 
| Pablo Ceballos | 60d6922 | 2015-08-07 14:47:20 -0700 | [diff] [blame] | 807 |         Rect rect(Rect::EMPTY_RECT); | 
| Dan Stoza | 6fbefbb | 2015-03-23 13:46:14 -0700 | [diff] [blame] | 808 |         status_t status = rect.unflatten(buffer, size); | 
 | 809 |         if (status != NO_ERROR) { | 
 | 810 |             return status; | 
 | 811 |         } | 
 | 812 |         FlattenableUtils::advance(buffer, size, sizeof(rect)); | 
 | 813 |         result.mStorage.push_back(rect); | 
 | 814 |     } | 
 | 815 |  | 
| Mathias Agopian | 3ab6855 | 2012-08-31 14:31:40 -0700 | [diff] [blame] | 816 | #if VALIDATE_REGIONS | 
| Mathias Agopian | 068d47f | 2012-09-11 18:56:23 -0700 | [diff] [blame] | 817 |     validate(result, "Region::unflatten"); | 
| Mathias Agopian | 3ab6855 | 2012-08-31 14:31:40 -0700 | [diff] [blame] | 818 | #endif | 
| Mathias Agopian | 068d47f | 2012-09-11 18:56:23 -0700 | [diff] [blame] | 819 |  | 
 | 820 |     if (!result.validate(result, "Region::unflatten", true)) { | 
 | 821 |         ALOGE("Region::unflatten() failed, invalid region"); | 
 | 822 |         return BAD_VALUE; | 
 | 823 |     } | 
 | 824 |     mStorage = result.mStorage; | 
| Mathias Agopian | 8683fca | 2012-08-12 19:37:16 -0700 | [diff] [blame] | 825 |     return NO_ERROR; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 826 | } | 
 | 827 |  | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 828 | // ---------------------------------------------------------------------------- | 
 | 829 |  | 
 | 830 | Region::const_iterator Region::begin() const { | 
| Mathias Agopian | 3ab6855 | 2012-08-31 14:31:40 -0700 | [diff] [blame] | 831 |     return mStorage.array(); | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 832 | } | 
 | 833 |  | 
 | 834 | Region::const_iterator Region::end() const { | 
| Mathias Agopian | 3ab6855 | 2012-08-31 14:31:40 -0700 | [diff] [blame] | 835 |     size_t numRects = isRect() ? 1 : mStorage.size() - 1; | 
 | 836 |     return mStorage.array() + numRects; | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 837 | } | 
 | 838 |  | 
 | 839 | Rect const* Region::getArray(size_t* count) const { | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 840 |     if (count) *count = static_cast<size_t>(end() - begin()); | 
 | 841 |     return begin(); | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 842 | } | 
 | 843 |  | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 844 | // ---------------------------------------------------------------------------- | 
 | 845 |  | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 846 | void Region::dump(String8& out, const char* what, uint32_t /* flags */) const | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 847 | { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 848 |     const_iterator head = begin(); | 
 | 849 |     const_iterator const tail = end(); | 
 | 850 |  | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 851 |     out.appendFormat("  Region %s (this=%p, count=%" PRIdPTR ")\n", | 
 | 852 |             what, this, tail - head); | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 853 |     while (head != tail) { | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 854 |         out.appendFormat("    [%3d, %3d, %3d, %3d]\n", head->left, head->top, | 
 | 855 |                 head->right, head->bottom); | 
 | 856 |         ++head; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 857 |     } | 
 | 858 | } | 
 | 859 |  | 
| Dan Stoza | d318240 | 2014-11-17 12:03:59 -0800 | [diff] [blame] | 860 | void Region::dump(const char* what, uint32_t /* flags */) const | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 861 | { | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 862 |     const_iterator head = begin(); | 
 | 863 |     const_iterator const tail = end(); | 
| Mark Salyzyn | 92dc3fc | 2014-03-12 13:12:44 -0700 | [diff] [blame] | 864 |     ALOGD("  Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail-head); | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 865 |     while (head != tail) { | 
| Steve Block | 9d45368 | 2011-12-20 16:23:08 +0000 | [diff] [blame] | 866 |         ALOGD("    [%3d, %3d, %3d, %3d]\n", | 
| Mathias Agopian | 20f6878 | 2009-05-11 00:03:41 -0700 | [diff] [blame] | 867 |                 head->left, head->top, head->right, head->bottom); | 
 | 868 |         head++; | 
| The Android Open Source Project | edbf3b6 | 2009-03-03 19:31:44 -0800 | [diff] [blame] | 869 |     } | 
 | 870 | } | 
 | 871 |  | 
 | 872 | // ---------------------------------------------------------------------------- | 
 | 873 |  | 
 | 874 | }; // namespace android |