blob: d929cc30bacadb58101de9ad66b45e932833afd8 [file] [log] [blame]
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -08001/*
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 Salyzyn92dc3fc2014-03-12 13:12:44 -070019#include <inttypes.h>
Mathias Agopian72b0ffe2009-07-06 18:07:26 -070020#include <limits.h>
21
Yiwei Zhang5434a782018-12-05 18:06:32 -080022#include <android-base/stringprintf.h>
23
Mathias Agopian20f68782009-05-11 00:03:41 -070024#include <utils/Log.h>
Mathias Agopian20f68782009-05-11 00:03:41 -070025
Marissa Wall15375f92019-12-03 15:10:46 -080026#include <ui/Point.h>
Mathias Agopian20f68782009-05-11 00:03:41 -070027#include <ui/Rect.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080028#include <ui/Region.h>
Marissa Wall15375f92019-12-03 15:10:46 -080029#include <ui/RegionHelper.h>
Mathias Agopian20f68782009-05-11 00:03:41 -070030
31// ----------------------------------------------------------------------------
Chong Zhang639a1e12019-04-22 14:01:20 -070032
33// ### VALIDATE_REGIONS ###
34// To enable VALIDATE_REGIONS traces, use the "libui-validate-regions-defaults"
35// in Android.bp. Do not #define VALIDATE_REGIONS here as it requires extra libs.
36
Mathias Agopian20f68782009-05-11 00:03:41 -070037#define VALIDATE_WITH_CORECG (false)
38// ----------------------------------------------------------------------------
39
Chong Zhang639a1e12019-04-22 14:01:20 -070040#if defined(VALIDATE_REGIONS)
41#include <utils/CallStack.h>
42#endif
43
Mathias Agopian20f68782009-05-11 00:03:41 -070044#if VALIDATE_WITH_CORECG
45#include <core/SkRegion.h>
46#endif
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080047
48namespace android {
Mathias Agopian20f68782009-05-11 00:03:41 -070049// ----------------------------------------------------------------------------
50
Yiwei Zhang5434a782018-12-05 18:06:32 -080051using base::StringAppendF;
52
Mathias Agopian20f68782009-05-11 00:03:41 -070053enum {
54 op_nand = region_operator<Rect>::op_nand,
55 op_and = region_operator<Rect>::op_and,
56 op_or = region_operator<Rect>::op_or,
57 op_xor = region_operator<Rect>::op_xor
58};
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080059
Chris Craik3e010f32013-02-25 19:12:47 -080060enum {
61 direction_LTR,
62 direction_RTL
63};
64
Dan Stoza5065a552015-03-17 16:23:42 -070065const Region Region::INVALID_REGION(Rect::INVALID_RECT);
66
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080067// ----------------------------------------------------------------------------
68
Mathias Agopian3ab68552012-08-31 14:31:40 -070069Region::Region() {
Tim Murrayb11abe72020-02-24 21:30:20 +000070 mStorage.add(Rect(0,0));
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080071}
72
73Region::Region(const Region& rhs)
Tim Murrayb11abe72020-02-24 21:30:20 +000074 : mStorage(rhs.mStorage)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080075{
Chong Zhang639a1e12019-04-22 14:01:20 -070076#if defined(VALIDATE_REGIONS)
Mathias Agopiand0b55c02011-03-16 23:18:07 -070077 validate(rhs, "rhs copy-ctor");
78#endif
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080079}
80
Mathias Agopian3ab68552012-08-31 14:31:40 -070081Region::Region(const Rect& rhs) {
Tim Murrayb11abe72020-02-24 21:30:20 +000082 mStorage.add(rhs);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080083}
84
85Region::~Region()
86{
87}
88
Chris Craik3e010f32013-02-25 19:12:47 -080089/**
90 * Copy rects from the src vector into the dst vector, resolving vertical T-Junctions along the way
91 *
92 * First pass through, divideSpanRTL will be set because the 'previous span' (indexing into the dst
93 * vector) will be reversed. Each rectangle in the original list, starting from the bottom, will be
94 * compared with the span directly below, and subdivided as needed to resolve T-junctions.
95 *
96 * The resulting temporary vector will be a completely reversed copy of the original, without any
97 * bottom-up T-junctions.
98 *
99 * Second pass through, divideSpanRTL will be false since the previous span will index into the
100 * final, correctly ordered region buffer. Each rectangle will be compared with the span directly
101 * above it, and subdivided to resolve any remaining T-junctions.
102 */
Tim Murrayb11abe72020-02-24 21:30:20 +0000103static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end,
104 Vector<Rect>& dst, int spanDirection) {
Chris Craik3e010f32013-02-25 19:12:47 -0800105 dst.clear();
106
107 const Rect* current = end - 1;
108 int lastTop = current->top;
109
110 // add first span immediately
111 do {
Tim Murrayb11abe72020-02-24 21:30:20 +0000112 dst.add(*current);
Chris Craik3e010f32013-02-25 19:12:47 -0800113 current--;
114 } while (current->top == lastTop && current >= begin);
115
Dan Stozad3182402014-11-17 12:03:59 -0800116 int beginLastSpan = -1;
117 int endLastSpan = -1;
Chris Craik3e010f32013-02-25 19:12:47 -0800118 int top = -1;
119 int bottom = -1;
120
121 // for all other spans, split if a t-junction exists in the span directly above
122 while (current >= begin) {
123 if (current->top != (current + 1)->top) {
124 // new span
125 if ((spanDirection == direction_RTL && current->bottom != (current + 1)->top) ||
126 (spanDirection == direction_LTR && current->top != (current + 1)->bottom)) {
127 // previous span not directly adjacent, don't check for T junctions
128 beginLastSpan = INT_MAX;
129 } else {
130 beginLastSpan = endLastSpan + 1;
131 }
Dan Stozad3182402014-11-17 12:03:59 -0800132 endLastSpan = static_cast<int>(dst.size()) - 1;
Chris Craik3e010f32013-02-25 19:12:47 -0800133
134 top = current->top;
135 bottom = current->bottom;
136 }
137 int left = current->left;
138 int right = current->right;
139
Dan Stozad3182402014-11-17 12:03:59 -0800140 for (int prevIndex = beginLastSpan; prevIndex <= endLastSpan; prevIndex++) {
141 // prevIndex can't be -1 here because if endLastSpan is set to a
142 // value greater than -1 (allowing the loop to execute),
143 // beginLastSpan (and therefore prevIndex) will also be increased
ywenaef04452015-03-26 19:51:12 +0800144 const Rect prev = dst[static_cast<size_t>(prevIndex)];
Chris Craik3e010f32013-02-25 19:12:47 -0800145 if (spanDirection == direction_RTL) {
146 // iterating over previous span RTL, quit if it's too far left
ywenaef04452015-03-26 19:51:12 +0800147 if (prev.right <= left) break;
Chris Craik3e010f32013-02-25 19:12:47 -0800148
ywenaef04452015-03-26 19:51:12 +0800149 if (prev.right > left && prev.right < right) {
Tim Murrayb11abe72020-02-24 21:30:20 +0000150 dst.add(Rect(prev.right, top, right, bottom));
ywenaef04452015-03-26 19:51:12 +0800151 right = prev.right;
Chris Craik3e010f32013-02-25 19:12:47 -0800152 }
153
ywenaef04452015-03-26 19:51:12 +0800154 if (prev.left > left && prev.left < right) {
Tim Murrayb11abe72020-02-24 21:30:20 +0000155 dst.add(Rect(prev.left, top, right, bottom));
ywenaef04452015-03-26 19:51:12 +0800156 right = prev.left;
Chris Craik3e010f32013-02-25 19:12:47 -0800157 }
158
159 // if an entry in the previous span is too far right, nothing further left in the
160 // current span will need it
ywenaef04452015-03-26 19:51:12 +0800161 if (prev.left >= right) {
Chris Craik3e010f32013-02-25 19:12:47 -0800162 beginLastSpan = prevIndex;
163 }
164 } else {
165 // iterating over previous span LTR, quit if it's too far right
ywenaef04452015-03-26 19:51:12 +0800166 if (prev.left >= right) break;
Chris Craik3e010f32013-02-25 19:12:47 -0800167
ywenaef04452015-03-26 19:51:12 +0800168 if (prev.left > left && prev.left < right) {
Tim Murrayb11abe72020-02-24 21:30:20 +0000169 dst.add(Rect(left, top, prev.left, bottom));
ywenaef04452015-03-26 19:51:12 +0800170 left = prev.left;
Chris Craik3e010f32013-02-25 19:12:47 -0800171 }
172
ywenaef04452015-03-26 19:51:12 +0800173 if (prev.right > left && prev.right < right) {
Tim Murrayb11abe72020-02-24 21:30:20 +0000174 dst.add(Rect(left, top, prev.right, bottom));
ywenaef04452015-03-26 19:51:12 +0800175 left = prev.right;
Chris Craik3e010f32013-02-25 19:12:47 -0800176 }
177 // if an entry in the previous span is too far left, nothing further right in the
178 // current span will need it
ywenaef04452015-03-26 19:51:12 +0800179 if (prev.right <= left) {
Chris Craik3e010f32013-02-25 19:12:47 -0800180 beginLastSpan = prevIndex;
181 }
182 }
183 }
184
185 if (left < right) {
Tim Murrayb11abe72020-02-24 21:30:20 +0000186 dst.add(Rect(left, top, right, bottom));
Chris Craik3e010f32013-02-25 19:12:47 -0800187 }
188
189 current--;
190 }
191}
192
193/**
194 * Creates a new region with the same data as the argument, but divides rectangles as necessary to
195 * remove T-Junctions
196 *
197 * Note: the output will not necessarily be a very efficient representation of the region, since it
198 * may be that a triangle-based approach would generate significantly simpler geometry
199 */
200Region Region::createTJunctionFreeRegion(const Region& r) {
201 if (r.isEmpty()) return r;
202 if (r.isRect()) return r;
203
Tim Murrayb11abe72020-02-24 21:30:20 +0000204 Vector<Rect> reversed;
Chris Craik3e010f32013-02-25 19:12:47 -0800205 reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL);
206
207 Region outputRegion;
Tim Murrayb11abe72020-02-24 21:30:20 +0000208 reverseRectsResolvingJunctions(reversed.begin(), reversed.end(),
209 outputRegion.mStorage, direction_LTR);
210 outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds
Chris Craik3e010f32013-02-25 19:12:47 -0800211
Chong Zhang639a1e12019-04-22 14:01:20 -0700212#if defined(VALIDATE_REGIONS)
Chris Craik3e010f32013-02-25 19:12:47 -0800213 validate(outputRegion, "T-Junction free region");
214#endif
215
216 return outputRegion;
217}
218
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800219Region& Region::operator = (const Region& rhs)
220{
Chong Zhang639a1e12019-04-22 14:01:20 -0700221#if defined(VALIDATE_REGIONS)
Mathias Agopiand0b55c02011-03-16 23:18:07 -0700222 validate(*this, "this->operator=");
223 validate(rhs, "rhs.operator=");
Mathias Agopian20f68782009-05-11 00:03:41 -0700224#endif
Tim Murrayb11abe72020-02-24 21:30:20 +0000225 mStorage = rhs.mStorage;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800226 return *this;
227}
228
Mathias Agopian9f961452009-06-29 18:46:37 -0700229Region& Region::makeBoundsSelf()
230{
Mathias Agopian3ab68552012-08-31 14:31:40 -0700231 if (mStorage.size() >= 2) {
232 const Rect bounds(getBounds());
233 mStorage.clear();
Tim Murrayb11abe72020-02-24 21:30:20 +0000234 mStorage.add(bounds);
Mathias Agopian3ab68552012-08-31 14:31:40 -0700235 }
Mathias Agopian9f961452009-06-29 18:46:37 -0700236 return *this;
237}
238
Michael Wright1c284a92014-02-10 13:00:14 -0800239bool Region::contains(const Point& point) const {
240 return contains(point.x, point.y);
241}
242
243bool Region::contains(int x, int y) const {
244 const_iterator cur = begin();
245 const_iterator const tail = end();
246 while (cur != tail) {
247 if (y >= cur->top && y < cur->bottom && x >= cur->left && x < cur->right) {
248 return true;
249 }
250 cur++;
251 }
252 return false;
253}
254
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800255void Region::clear()
256{
Mathias Agopian20f68782009-05-11 00:03:41 -0700257 mStorage.clear();
Tim Murrayb11abe72020-02-24 21:30:20 +0000258 mStorage.add(Rect(0,0));
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800259}
260
261void Region::set(const Rect& r)
262{
Mathias Agopian20f68782009-05-11 00:03:41 -0700263 mStorage.clear();
Tim Murrayb11abe72020-02-24 21:30:20 +0000264 mStorage.add(r);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800265}
266
Dan Stozad3182402014-11-17 12:03:59 -0800267void Region::set(int32_t w, int32_t h)
Mathias Agopian0926f502009-05-04 14:17:04 -0700268{
Mathias Agopian20f68782009-05-11 00:03:41 -0700269 mStorage.clear();
Tim Murrayb11abe72020-02-24 21:30:20 +0000270 mStorage.add(Rect(w, h));
Mathias Agopian0926f502009-05-04 14:17:04 -0700271}
272
Bernhard Rosenkraenzerfe4966d2014-12-22 21:15:08 +0100273void Region::set(uint32_t w, uint32_t h)
274{
275 mStorage.clear();
Tim Murrayb11abe72020-02-24 21:30:20 +0000276 mStorage.add(Rect(w, h));
Bernhard Rosenkraenzerfe4966d2014-12-22 21:15:08 +0100277}
278
Mathias Agopian2ca79392013-04-02 18:30:32 -0700279bool Region::isTriviallyEqual(const Region& region) const {
280 return begin() == region.begin();
281}
282
Lloyd Piqueea629282019-12-03 15:57:10 -0800283bool Region::hasSameRects(const Region& other) const {
284 size_t thisRectCount = 0;
285 android::Rect const* thisRects = getArray(&thisRectCount);
286 size_t otherRectCount = 0;
287 android::Rect const* otherRects = other.getArray(&otherRectCount);
288
289 if (thisRectCount != otherRectCount) return false;
290
291 for (size_t i = 0; i < thisRectCount; i++) {
292 if (thisRects[i] != otherRects[i]) return false;
293 }
294 return true;
295}
296
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800297// ----------------------------------------------------------------------------
298
Mathias Agopian20f68782009-05-11 00:03:41 -0700299void Region::addRectUnchecked(int l, int t, int r, int b)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800300{
Mathias Agopian3ab68552012-08-31 14:31:40 -0700301 Rect rect(l,t,r,b);
Tim Murrayb11abe72020-02-24 21:30:20 +0000302 size_t where = mStorage.size() - 1;
303 mStorage.insertAt(rect, where, 1);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800304}
305
Mathias Agopian20f68782009-05-11 00:03:41 -0700306// ----------------------------------------------------------------------------
307
308Region& Region::orSelf(const Rect& r) {
Dan Stoza547808b2020-04-02 09:31:08 -0700309 if (isEmpty()) {
310 set(r);
311 return *this;
312 }
Mathias Agopian20f68782009-05-11 00:03:41 -0700313 return operationSelf(r, op_or);
314}
Romain Guyb8a2e982012-02-07 17:04:34 -0800315Region& Region::xorSelf(const Rect& r) {
316 return operationSelf(r, op_xor);
317}
Mathias Agopian20f68782009-05-11 00:03:41 -0700318Region& Region::andSelf(const Rect& r) {
319 return operationSelf(r, op_and);
320}
321Region& Region::subtractSelf(const Rect& r) {
322 return operationSelf(r, op_nand);
323}
Colin Cross8f279962016-09-26 13:08:16 -0700324Region& Region::operationSelf(const Rect& r, uint32_t op) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700325 Region lhs(*this);
326 boolean_operation(op, *this, lhs, r);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800327 return *this;
328}
329
330// ----------------------------------------------------------------------------
331
332Region& Region::orSelf(const Region& rhs) {
Dan Stoza547808b2020-04-02 09:31:08 -0700333 if (isEmpty()) {
334 *this = rhs;
335 return *this;
336 }
Mathias Agopian20f68782009-05-11 00:03:41 -0700337 return operationSelf(rhs, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800338}
Romain Guyb8a2e982012-02-07 17:04:34 -0800339Region& Region::xorSelf(const Region& rhs) {
340 return operationSelf(rhs, op_xor);
341}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800342Region& Region::andSelf(const Region& rhs) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700343 return operationSelf(rhs, op_and);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800344}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800345Region& Region::subtractSelf(const Region& rhs) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700346 return operationSelf(rhs, op_nand);
347}
Colin Cross8f279962016-09-26 13:08:16 -0700348Region& Region::operationSelf(const Region& rhs, uint32_t op) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700349 Region lhs(*this);
350 boolean_operation(op, *this, lhs, rhs);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800351 return *this;
352}
353
354Region& Region::translateSelf(int x, int y) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700355 if (x|y) translate(*this, x, y);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800356 return *this;
357}
358
Riddle Hsu39d4aa52018-11-30 20:46:53 +0800359Region& Region::scaleSelf(float sx, float sy) {
Robert Carre07e1032018-11-26 12:55:53 -0800360 size_t count = mStorage.size();
Tim Murrayb11abe72020-02-24 21:30:20 +0000361 Rect* rects = mStorage.editArray();
Robert Carre07e1032018-11-26 12:55:53 -0800362 while (count) {
Nick Desaulniersea6c7132019-10-15 19:14:39 -0700363 rects->left = static_cast<int32_t>(static_cast<float>(rects->left) * sx + 0.5f);
364 rects->right = static_cast<int32_t>(static_cast<float>(rects->right) * sx + 0.5f);
365 rects->top = static_cast<int32_t>(static_cast<float>(rects->top) * sy + 0.5f);
366 rects->bottom = static_cast<int32_t>(static_cast<float>(rects->bottom) * sy + 0.5f);
Robert Carre07e1032018-11-26 12:55:53 -0800367 rects++;
368 count--;
369 }
370 return *this;
371}
372
Mathias Agopian20f68782009-05-11 00:03:41 -0700373// ----------------------------------------------------------------------------
374
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700375const Region Region::merge(const Rect& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700376 return operation(rhs, op_or);
377}
Romain Guyb8a2e982012-02-07 17:04:34 -0800378const Region Region::mergeExclusive(const Rect& rhs) const {
379 return operation(rhs, op_xor);
380}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700381const Region Region::intersect(const Rect& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700382 return operation(rhs, op_and);
383}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700384const Region Region::subtract(const Rect& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700385 return operation(rhs, op_nand);
386}
Colin Cross8f279962016-09-26 13:08:16 -0700387const Region Region::operation(const Rect& rhs, uint32_t op) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700388 Region result;
389 boolean_operation(op, result, *this, rhs);
390 return result;
391}
392
393// ----------------------------------------------------------------------------
394
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700395const Region Region::merge(const Region& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700396 return operation(rhs, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800397}
Romain Guyb8a2e982012-02-07 17:04:34 -0800398const Region Region::mergeExclusive(const Region& rhs) const {
399 return operation(rhs, op_xor);
400}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700401const Region Region::intersect(const Region& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700402 return operation(rhs, op_and);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800403}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700404const Region Region::subtract(const Region& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700405 return operation(rhs, op_nand);
406}
Colin Cross8f279962016-09-26 13:08:16 -0700407const Region Region::operation(const Region& rhs, uint32_t op) const {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800408 Region result;
Mathias Agopian20f68782009-05-11 00:03:41 -0700409 boolean_operation(op, result, *this, rhs);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800410 return result;
411}
412
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700413const Region Region::translate(int x, int y) const {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800414 Region result;
Mathias Agopian20f68782009-05-11 00:03:41 -0700415 translate(result, *this, x, y);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800416 return result;
417}
418
419// ----------------------------------------------------------------------------
420
421Region& Region::orSelf(const Region& rhs, int dx, int dy) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700422 return operationSelf(rhs, dx, dy, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800423}
Romain Guyb8a2e982012-02-07 17:04:34 -0800424Region& Region::xorSelf(const Region& rhs, int dx, int dy) {
425 return operationSelf(rhs, dx, dy, op_xor);
426}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800427Region& Region::andSelf(const Region& rhs, int dx, int dy) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700428 return operationSelf(rhs, dx, dy, op_and);
429}
430Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
431 return operationSelf(rhs, dx, dy, op_nand);
432}
Colin Cross8f279962016-09-26 13:08:16 -0700433Region& Region::operationSelf(const Region& rhs, int dx, int dy, uint32_t op) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700434 Region lhs(*this);
435 boolean_operation(op, *this, lhs, rhs, dx, dy);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800436 return *this;
437}
438
Mathias Agopian20f68782009-05-11 00:03:41 -0700439// ----------------------------------------------------------------------------
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800440
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700441const Region Region::merge(const Region& rhs, int dx, int dy) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700442 return operation(rhs, dx, dy, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800443}
Romain Guyb8a2e982012-02-07 17:04:34 -0800444const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const {
445 return operation(rhs, dx, dy, op_xor);
446}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700447const Region Region::intersect(const Region& rhs, int dx, int dy) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700448 return operation(rhs, dx, dy, op_and);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800449}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700450const Region Region::subtract(const Region& rhs, int dx, int dy) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700451 return operation(rhs, dx, dy, op_nand);
452}
Colin Cross8f279962016-09-26 13:08:16 -0700453const Region Region::operation(const Region& rhs, int dx, int dy, uint32_t op) const {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800454 Region result;
Mathias Agopian20f68782009-05-11 00:03:41 -0700455 boolean_operation(op, result, *this, rhs, dx, dy);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800456 return result;
457}
458
459// ----------------------------------------------------------------------------
460
Mathias Agopian20f68782009-05-11 00:03:41 -0700461// This is our region rasterizer, which merges rects and spans together
462// to obtain an optimal region.
Dan Stozad3182402014-11-17 12:03:59 -0800463class Region::rasterizer : public region_operator<Rect>::region_rasterizer
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800464{
Mathias Agopian3ab68552012-08-31 14:31:40 -0700465 Rect bounds;
Tim Murrayb11abe72020-02-24 21:30:20 +0000466 Vector<Rect>& storage;
Mathias Agopian20f68782009-05-11 00:03:41 -0700467 Rect* head;
468 Rect* tail;
Tim Murrayb11abe72020-02-24 21:30:20 +0000469 Vector<Rect> span;
Mathias Agopian20f68782009-05-11 00:03:41 -0700470 Rect* cur;
471public:
Chih-Hung Hsiehe2347b72016-04-25 15:41:05 -0700472 explicit rasterizer(Region& reg)
Mathias Agopian3ab68552012-08-31 14:31:40 -0700473 : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() {
Mathias Agopian20f68782009-05-11 00:03:41 -0700474 storage.clear();
475 }
476
Dan Stozad3182402014-11-17 12:03:59 -0800477 virtual ~rasterizer();
478
479 virtual void operator()(const Rect& rect);
480
Mathias Agopian20f68782009-05-11 00:03:41 -0700481private:
Dan Stozad3182402014-11-17 12:03:59 -0800482 template<typename T>
Mathias Agopian20f68782009-05-11 00:03:41 -0700483 static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; }
Dan Stozad3182402014-11-17 12:03:59 -0800484 template<typename T>
Mathias Agopian20f68782009-05-11 00:03:41 -0700485 static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; }
Dan Stozad3182402014-11-17 12:03:59 -0800486
487 void flushSpan();
Mathias Agopian20f68782009-05-11 00:03:41 -0700488};
489
Dan Stozad3182402014-11-17 12:03:59 -0800490Region::rasterizer::~rasterizer()
491{
492 if (span.size()) {
493 flushSpan();
494 }
495 if (storage.size()) {
Tim Murrayb11abe72020-02-24 21:30:20 +0000496 bounds.top = storage.itemAt(0).top;
497 bounds.bottom = storage.top().bottom;
Dan Stozad3182402014-11-17 12:03:59 -0800498 if (storage.size() == 1) {
499 storage.clear();
500 }
501 } else {
502 bounds.left = 0;
503 bounds.right = 0;
504 }
Tim Murrayb11abe72020-02-24 21:30:20 +0000505 storage.add(bounds);
Dan Stozad3182402014-11-17 12:03:59 -0800506}
507
508void Region::rasterizer::operator()(const Rect& rect)
509{
510 //ALOGD(">>> %3d, %3d, %3d, %3d",
511 // rect.left, rect.top, rect.right, rect.bottom);
512 if (span.size()) {
513 if (cur->top != rect.top) {
514 flushSpan();
515 } else if (cur->right == rect.left) {
516 cur->right = rect.right;
517 return;
518 }
519 }
Tim Murrayb11abe72020-02-24 21:30:20 +0000520 span.add(rect);
521 cur = span.editArray() + (span.size() - 1);
Dan Stozad3182402014-11-17 12:03:59 -0800522}
523
524void Region::rasterizer::flushSpan()
525{
526 bool merge = false;
527 if (tail-head == ssize_t(span.size())) {
Tim Murrayb11abe72020-02-24 21:30:20 +0000528 Rect const* p = span.editArray();
Dan Stozad3182402014-11-17 12:03:59 -0800529 Rect const* q = head;
530 if (p->top == q->bottom) {
531 merge = true;
532 while (q != tail) {
533 if ((p->left != q->left) || (p->right != q->right)) {
534 merge = false;
535 break;
536 }
Stephen Hines9c22c3c2016-03-31 22:02:38 -0700537 p++;
538 q++;
Dan Stozad3182402014-11-17 12:03:59 -0800539 }
540 }
541 }
542 if (merge) {
Tim Murrayb11abe72020-02-24 21:30:20 +0000543 const int bottom = span[0].bottom;
Dan Stozad3182402014-11-17 12:03:59 -0800544 Rect* r = head;
545 while (r != tail) {
546 r->bottom = bottom;
547 r++;
548 }
549 } else {
Tim Murrayb11abe72020-02-24 21:30:20 +0000550 bounds.left = min(span.itemAt(0).left, bounds.left);
551 bounds.right = max(span.top().right, bounds.right);
552 storage.appendVector(span);
553 tail = storage.editArray() + storage.size();
Dan Stozad3182402014-11-17 12:03:59 -0800554 head = tail - span.size();
555 }
556 span.clear();
557}
558
Mathias Agopian068d47f2012-09-11 18:56:23 -0700559bool Region::validate(const Region& reg, const char* name, bool silent)
Mathias Agopian20f68782009-05-11 00:03:41 -0700560{
Tim Murrayb11abe72020-02-24 21:30:20 +0000561 if (reg.mStorage.isEmpty()) {
Chia-I Wub420b582018-02-07 11:53:41 -0800562 ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name);
563 // return immediately as the code below assumes mStorage is non-empty
564 return false;
565 }
566
Mathias Agopian20f68782009-05-11 00:03:41 -0700567 bool result = true;
568 const_iterator cur = reg.begin();
569 const_iterator const tail = reg.end();
Mathias Agopian068d47f2012-09-11 18:56:23 -0700570 const_iterator prev = cur;
Mathias Agopian20f68782009-05-11 00:03:41 -0700571 Rect b(*prev);
572 while (cur != tail) {
Mathias Agopian068d47f2012-09-11 18:56:23 -0700573 if (cur->isValid() == false) {
Dan Stoza5065a552015-03-17 16:23:42 -0700574 // We allow this particular flavor of invalid Rect, since it is used
575 // as a signal value in various parts of the system
576 if (*cur != Rect::INVALID_RECT) {
577 ALOGE_IF(!silent, "%s: region contains an invalid Rect", name);
578 result = false;
579 }
Mathias Agopian068d47f2012-09-11 18:56:23 -0700580 }
581 if (cur->right > region_operator<Rect>::max_value) {
582 ALOGE_IF(!silent, "%s: rect->right > max_value", name);
583 result = false;
584 }
585 if (cur->bottom > region_operator<Rect>::max_value) {
586 ALOGE_IF(!silent, "%s: rect->right > max_value", name);
587 result = false;
588 }
589 if (prev != cur) {
590 b.left = b.left < cur->left ? b.left : cur->left;
591 b.top = b.top < cur->top ? b.top : cur->top;
592 b.right = b.right > cur->right ? b.right : cur->right;
593 b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
594 if ((*prev < *cur) == false) {
595 ALOGE_IF(!silent, "%s: region's Rects not sorted", name);
Mathias Agopian20f68782009-05-11 00:03:41 -0700596 result = false;
Mathias Agopian068d47f2012-09-11 18:56:23 -0700597 }
598 if (cur->top == prev->top) {
599 if (cur->bottom != prev->bottom) {
600 ALOGE_IF(!silent, "%s: invalid span %p", name, cur);
601 result = false;
602 } else if (cur->left < prev->right) {
603 ALOGE_IF(!silent,
604 "%s: spans overlap horizontally prev=%p, cur=%p",
605 name, prev, cur);
606 result = false;
607 }
608 } else if (cur->top < prev->bottom) {
609 ALOGE_IF(!silent,
610 "%s: spans overlap vertically prev=%p, cur=%p",
Mathias Agopian20f68782009-05-11 00:03:41 -0700611 name, prev, cur);
612 result = false;
613 }
Mathias Agopian068d47f2012-09-11 18:56:23 -0700614 prev = cur;
Mathias Agopian20f68782009-05-11 00:03:41 -0700615 }
Mathias Agopian20f68782009-05-11 00:03:41 -0700616 cur++;
617 }
618 if (b != reg.getBounds()) {
619 result = false;
Mathias Agopian068d47f2012-09-11 18:56:23 -0700620 ALOGE_IF(!silent,
621 "%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
Mathias Agopian20f68782009-05-11 00:03:41 -0700622 b.left, b.top, b.right, b.bottom,
623 reg.getBounds().left, reg.getBounds().top,
624 reg.getBounds().right, reg.getBounds().bottom);
625 }
Mathias Agopian3ab68552012-08-31 14:31:40 -0700626 if (reg.mStorage.size() == 2) {
Mathias Agopian068d47f2012-09-11 18:56:23 -0700627 result = false;
628 ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name);
Mathias Agopian3ab68552012-08-31 14:31:40 -0700629 }
Chong Zhang639a1e12019-04-22 14:01:20 -0700630#if defined(VALIDATE_REGIONS)
Mathias Agopian068d47f2012-09-11 18:56:23 -0700631 if (result == false && !silent) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700632 reg.dump(name);
Mathias Agopiancab25d62013-03-21 17:12:40 -0700633 CallStack stack(LOG_TAG);
Mathias Agopian20f68782009-05-11 00:03:41 -0700634 }
Chong Zhang639a1e12019-04-22 14:01:20 -0700635#endif
Mathias Agopian20f68782009-05-11 00:03:41 -0700636 return result;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800637}
638
Colin Cross8f279962016-09-26 13:08:16 -0700639void Region::boolean_operation(uint32_t op, Region& dst,
Mathias Agopian20f68782009-05-11 00:03:41 -0700640 const Region& lhs,
641 const Region& rhs, int dx, int dy)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800642{
Chong Zhang639a1e12019-04-22 14:01:20 -0700643#if defined(VALIDATE_REGIONS)
Mathias Agopiand0b55c02011-03-16 23:18:07 -0700644 validate(lhs, "boolean_operation (before): lhs");
645 validate(rhs, "boolean_operation (before): rhs");
646 validate(dst, "boolean_operation (before): dst");
647#endif
648
Mathias Agopian20f68782009-05-11 00:03:41 -0700649 size_t lhs_count;
650 Rect const * const lhs_rects = lhs.getArray(&lhs_count);
651
652 size_t rhs_count;
653 Rect const * const rhs_rects = rhs.getArray(&rhs_count);
654
655 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
656 region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy);
657 region_operator<Rect> operation(op, lhs_region, rhs_region);
658 { // scope for rasterizer (dtor has side effects)
659 rasterizer r(dst);
660 operation(r);
661 }
662
Chong Zhang639a1e12019-04-22 14:01:20 -0700663#if defined(VALIDATE_REGIONS)
Mathias Agopian20f68782009-05-11 00:03:41 -0700664 validate(lhs, "boolean_operation: lhs");
665 validate(rhs, "boolean_operation: rhs");
666 validate(dst, "boolean_operation: dst");
667#endif
668
669#if VALIDATE_WITH_CORECG
670 SkRegion sk_lhs;
671 SkRegion sk_rhs;
672 SkRegion sk_dst;
673
674 for (size_t i=0 ; i<lhs_count ; i++)
675 sk_lhs.op(
676 lhs_rects[i].left + dx,
677 lhs_rects[i].top + dy,
678 lhs_rects[i].right + dx,
679 lhs_rects[i].bottom + dy,
680 SkRegion::kUnion_Op);
681
682 for (size_t i=0 ; i<rhs_count ; i++)
683 sk_rhs.op(
684 rhs_rects[i].left + dx,
685 rhs_rects[i].top + dy,
686 rhs_rects[i].right + dx,
687 rhs_rects[i].bottom + dy,
688 SkRegion::kUnion_Op);
689
690 const char* name = "---";
691 SkRegion::Op sk_op;
692 switch (op) {
693 case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
Romain Guyb8a2e982012-02-07 17:04:34 -0800694 case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break;
Mathias Agopian20f68782009-05-11 00:03:41 -0700695 case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
696 case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
697 }
698 sk_dst.op(sk_lhs, sk_rhs, sk_op);
699
Tim Murrayb11abe72020-02-24 21:30:20 +0000700 if (sk_dst.isEmpty() && dst.isEmpty())
701 return;
702
Mathias Agopian20f68782009-05-11 00:03:41 -0700703 bool same = true;
704 Region::const_iterator head = dst.begin();
705 Region::const_iterator const tail = dst.end();
706 SkRegion::Iterator it(sk_dst);
707 while (!it.done()) {
708 if (head != tail) {
709 if (
710 head->left != it.rect().fLeft ||
711 head->top != it.rect().fTop ||
712 head->right != it.rect().fRight ||
713 head->bottom != it.rect().fBottom
714 ) {
715 same = false;
716 break;
717 }
718 } else {
719 same = false;
720 break;
721 }
722 head++;
723 it.next();
724 }
725
726 if (head != tail) {
727 same = false;
728 }
729
730 if(!same) {
Steve Block9d453682011-12-20 16:23:08 +0000731 ALOGD("---\nregion boolean %s failed", name);
Mathias Agopian20f68782009-05-11 00:03:41 -0700732 lhs.dump("lhs");
733 rhs.dump("rhs");
734 dst.dump("dst");
Steve Block9d453682011-12-20 16:23:08 +0000735 ALOGD("should be");
Mathias Agopian20f68782009-05-11 00:03:41 -0700736 SkRegion::Iterator it(sk_dst);
737 while (!it.done()) {
Steve Block9d453682011-12-20 16:23:08 +0000738 ALOGD(" [%3d, %3d, %3d, %3d]",
Mathias Agopian20f68782009-05-11 00:03:41 -0700739 it.rect().fLeft,
740 it.rect().fTop,
741 it.rect().fRight,
742 it.rect().fBottom);
743 it.next();
744 }
745 }
746#endif
747}
748
Colin Cross8f279962016-09-26 13:08:16 -0700749void Region::boolean_operation(uint32_t op, Region& dst,
Mathias Agopian20f68782009-05-11 00:03:41 -0700750 const Region& lhs,
751 const Rect& rhs, int dx, int dy)
752{
Dan Stoza5065a552015-03-17 16:23:42 -0700753 // We allow this particular flavor of invalid Rect, since it is used as a
754 // signal value in various parts of the system
755 if (!rhs.isValid() && rhs != Rect::INVALID_RECT) {
Steve Blocke6f43dd2012-01-06 19:20:56 +0000756 ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}",
Mathias Agopian04504522011-09-19 16:12:08 -0700757 op, rhs.left, rhs.top, rhs.right, rhs.bottom);
Mathias Agopian0857c8f2011-09-26 15:58:20 -0700758 return;
Mathias Agopian04504522011-09-19 16:12:08 -0700759 }
760
Chong Zhang639a1e12019-04-22 14:01:20 -0700761#if VALIDATE_WITH_CORECG || defined(VALIDATE_REGIONS)
Mathias Agopian20f68782009-05-11 00:03:41 -0700762 boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
763#else
764 size_t lhs_count;
765 Rect const * const lhs_rects = lhs.getArray(&lhs_count);
766
767 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
768 region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy);
769 region_operator<Rect> operation(op, lhs_region, rhs_region);
770 { // scope for rasterizer (dtor has side effects)
771 rasterizer r(dst);
772 operation(r);
773 }
774
775#endif
776}
777
Colin Cross8f279962016-09-26 13:08:16 -0700778void Region::boolean_operation(uint32_t op, Region& dst,
Mathias Agopian20f68782009-05-11 00:03:41 -0700779 const Region& lhs, const Region& rhs)
780{
781 boolean_operation(op, dst, lhs, rhs, 0, 0);
782}
783
Colin Cross8f279962016-09-26 13:08:16 -0700784void Region::boolean_operation(uint32_t op, Region& dst,
Mathias Agopian20f68782009-05-11 00:03:41 -0700785 const Region& lhs, const Rect& rhs)
786{
787 boolean_operation(op, dst, lhs, rhs, 0, 0);
788}
789
790void Region::translate(Region& reg, int dx, int dy)
791{
Mathias Agopian4c0a1702012-08-31 12:45:33 -0700792 if ((dx || dy) && !reg.isEmpty()) {
Chong Zhang639a1e12019-04-22 14:01:20 -0700793#if defined(VALIDATE_REGIONS)
Mathias Agopian20f68782009-05-11 00:03:41 -0700794 validate(reg, "translate (before)");
795#endif
Mathias Agopian20f68782009-05-11 00:03:41 -0700796 size_t count = reg.mStorage.size();
Tim Murrayb11abe72020-02-24 21:30:20 +0000797 Rect* rects = reg.mStorage.editArray();
Mathias Agopian20f68782009-05-11 00:03:41 -0700798 while (count) {
Mathias Agopian6c7f25a2013-05-09 20:37:10 -0700799 rects->offsetBy(dx, dy);
Mathias Agopian20f68782009-05-11 00:03:41 -0700800 rects++;
801 count--;
802 }
Chong Zhang639a1e12019-04-22 14:01:20 -0700803#if defined(VALIDATE_REGIONS)
Mathias Agopian20f68782009-05-11 00:03:41 -0700804 validate(reg, "translate (after)");
805#endif
806 }
807}
808
809void Region::translate(Region& dst, const Region& reg, int dx, int dy)
810{
811 dst = reg;
812 translate(dst, dx, dy);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800813}
814
815// ----------------------------------------------------------------------------
816
Mathias Agopiane1424282013-07-29 21:24:40 -0700817size_t Region::getFlattenedSize() const {
Dan Stoza6fbefbb2015-03-23 13:46:14 -0700818 return sizeof(uint32_t) + mStorage.size() * sizeof(Rect);
Mathias Agopian8683fca2012-08-12 19:37:16 -0700819}
820
Mathias Agopiane1424282013-07-29 21:24:40 -0700821status_t Region::flatten(void* buffer, size_t size) const {
Chong Zhang639a1e12019-04-22 14:01:20 -0700822#if defined(VALIDATE_REGIONS)
Mathias Agopian068d47f2012-09-11 18:56:23 -0700823 validate(*this, "Region::flatten");
824#endif
Dan Stoza6fbefbb2015-03-23 13:46:14 -0700825 if (size < getFlattenedSize()) {
Mathias Agopiane1424282013-07-29 21:24:40 -0700826 return NO_MEMORY;
827 }
Dan Stoza6fbefbb2015-03-23 13:46:14 -0700828 // Cast to uint32_t since the size of a size_t can vary between 32- and
829 // 64-bit processes
830 FlattenableUtils::write(buffer, size, static_cast<uint32_t>(mStorage.size()));
831 for (auto rect : mStorage) {
832 status_t result = rect.flatten(buffer, size);
833 if (result != NO_ERROR) {
834 return result;
835 }
836 FlattenableUtils::advance(buffer, size, sizeof(rect));
837 }
Mathias Agopian8683fca2012-08-12 19:37:16 -0700838 return NO_ERROR;
839}
840
841status_t Region::unflatten(void const* buffer, size_t size) {
Dan Stoza6fbefbb2015-03-23 13:46:14 -0700842 if (size < sizeof(uint32_t)) {
843 return NO_MEMORY;
Mathias Agopian20f68782009-05-11 00:03:41 -0700844 }
Dan Stoza6fbefbb2015-03-23 13:46:14 -0700845
846 uint32_t numRects = 0;
847 FlattenableUtils::read(buffer, size, numRects);
848 if (size < numRects * sizeof(Rect)) {
849 return NO_MEMORY;
850 }
851
Pablo Ceballos1a65fcc2016-07-13 14:11:57 -0700852 if (numRects > (UINT32_MAX / sizeof(Rect))) {
Yi Kong48d76082019-03-24 02:01:06 -0700853 android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, nullptr, 0);
Pablo Ceballos1a65fcc2016-07-13 14:11:57 -0700854 return NO_MEMORY;
855 }
856
Dan Stoza6fbefbb2015-03-23 13:46:14 -0700857 Region result;
858 result.mStorage.clear();
859 for (size_t r = 0; r < numRects; ++r) {
Pablo Ceballos60d69222015-08-07 14:47:20 -0700860 Rect rect(Rect::EMPTY_RECT);
Dan Stoza6fbefbb2015-03-23 13:46:14 -0700861 status_t status = rect.unflatten(buffer, size);
862 if (status != NO_ERROR) {
863 return status;
864 }
865 FlattenableUtils::advance(buffer, size, sizeof(rect));
866 result.mStorage.push_back(rect);
867 }
868
Chong Zhang639a1e12019-04-22 14:01:20 -0700869#if defined(VALIDATE_REGIONS)
Mathias Agopian068d47f2012-09-11 18:56:23 -0700870 validate(result, "Region::unflatten");
Mathias Agopian3ab68552012-08-31 14:31:40 -0700871#endif
Mathias Agopian068d47f2012-09-11 18:56:23 -0700872
873 if (!result.validate(result, "Region::unflatten", true)) {
874 ALOGE("Region::unflatten() failed, invalid region");
875 return BAD_VALUE;
876 }
Tim Murrayb11abe72020-02-24 21:30:20 +0000877 mStorage = result.mStorage;
Mathias Agopian8683fca2012-08-12 19:37:16 -0700878 return NO_ERROR;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800879}
880
Mathias Agopian20f68782009-05-11 00:03:41 -0700881// ----------------------------------------------------------------------------
882
883Region::const_iterator Region::begin() const {
Tim Murrayb11abe72020-02-24 21:30:20 +0000884 return mStorage.array();
Mathias Agopian20f68782009-05-11 00:03:41 -0700885}
886
887Region::const_iterator Region::end() const {
Dan Stoza2d023062018-04-09 12:14:55 -0700888 // Workaround for b/77643177
889 // mStorage should never be empty, but somehow it is and it's causing
890 // an abort in ubsan
Tim Murrayb11abe72020-02-24 21:30:20 +0000891 if (mStorage.isEmpty()) return mStorage.array();
Dan Stoza2d023062018-04-09 12:14:55 -0700892
Mathias Agopian3ab68552012-08-31 14:31:40 -0700893 size_t numRects = isRect() ? 1 : mStorage.size() - 1;
Tim Murrayb11abe72020-02-24 21:30:20 +0000894 return mStorage.array() + numRects;
Mathias Agopian20f68782009-05-11 00:03:41 -0700895}
896
897Rect const* Region::getArray(size_t* count) const {
Dan Stozad3182402014-11-17 12:03:59 -0800898 if (count) *count = static_cast<size_t>(end() - begin());
899 return begin();
Mathias Agopian20f68782009-05-11 00:03:41 -0700900}
901
Mathias Agopian20f68782009-05-11 00:03:41 -0700902// ----------------------------------------------------------------------------
903
Yiwei Zhang5434a782018-12-05 18:06:32 -0800904void Region::dump(std::string& out, const char* what, uint32_t /* flags */) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700905 const_iterator head = begin();
906 const_iterator const tail = end();
907
Yiwei Zhang5434a782018-12-05 18:06:32 -0800908 StringAppendF(&out, " Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail - head);
Mathias Agopian20f68782009-05-11 00:03:41 -0700909 while (head != tail) {
Yiwei Zhang5434a782018-12-05 18:06:32 -0800910 StringAppendF(&out, " [%3d, %3d, %3d, %3d]\n", head->left, head->top, head->right,
911 head->bottom);
Dan Stozad3182402014-11-17 12:03:59 -0800912 ++head;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800913 }
914}
915
Dan Stozad3182402014-11-17 12:03:59 -0800916void Region::dump(const char* what, uint32_t /* flags */) const
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800917{
Mathias Agopian20f68782009-05-11 00:03:41 -0700918 const_iterator head = begin();
919 const_iterator const tail = end();
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -0700920 ALOGD(" Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail-head);
Mathias Agopian20f68782009-05-11 00:03:41 -0700921 while (head != tail) {
Steve Block9d453682011-12-20 16:23:08 +0000922 ALOGD(" [%3d, %3d, %3d, %3d]\n",
Mathias Agopian20f68782009-05-11 00:03:41 -0700923 head->left, head->top, head->right, head->bottom);
924 head++;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800925 }
926}
927
928// ----------------------------------------------------------------------------
929
930}; // namespace android