blob: 224dc2c122e6101055a40993f47a7436ceb31e26 [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 Agopian068d47f2012-09-11 18:56:23 -070025#include <utils/CallStack.h>
Mathias Agopian20f68782009-05-11 00:03:41 -070026
27#include <ui/Rect.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080028#include <ui/Region.h>
Mathias Agopian20f68782009-05-11 00:03:41 -070029#include <ui/Point.h>
30
31#include <private/ui/RegionHelper.h>
32
33// ----------------------------------------------------------------------------
34#define VALIDATE_REGIONS (false)
35#define VALIDATE_WITH_CORECG (false)
36// ----------------------------------------------------------------------------
37
38#if VALIDATE_WITH_CORECG
39#include <core/SkRegion.h>
40#endif
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080041
42namespace android {
Mathias Agopian20f68782009-05-11 00:03:41 -070043// ----------------------------------------------------------------------------
44
Yiwei Zhang5434a782018-12-05 18:06:32 -080045using base::StringAppendF;
46
Mathias Agopian20f68782009-05-11 00:03:41 -070047enum {
48 op_nand = region_operator<Rect>::op_nand,
49 op_and = region_operator<Rect>::op_and,
50 op_or = region_operator<Rect>::op_or,
51 op_xor = region_operator<Rect>::op_xor
52};
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080053
Chris Craik3e010f32013-02-25 19:12:47 -080054enum {
55 direction_LTR,
56 direction_RTL
57};
58
Dan Stoza5065a552015-03-17 16:23:42 -070059const Region Region::INVALID_REGION(Rect::INVALID_RECT);
60
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080061// ----------------------------------------------------------------------------
62
Mathias Agopian3ab68552012-08-31 14:31:40 -070063Region::Region() {
64 mStorage.add(Rect(0,0));
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080065}
66
67Region::Region(const Region& rhs)
Mathias Agopian3ab68552012-08-31 14:31:40 -070068 : mStorage(rhs.mStorage)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080069{
Mathias Agopiand0b55c02011-03-16 23:18:07 -070070#if VALIDATE_REGIONS
71 validate(rhs, "rhs copy-ctor");
72#endif
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080073}
74
Mathias Agopian3ab68552012-08-31 14:31:40 -070075Region::Region(const Rect& rhs) {
76 mStorage.add(rhs);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080077}
78
79Region::~Region()
80{
81}
82
Chris Craik3e010f32013-02-25 19:12:47 -080083/**
84 * Copy rects from the src vector into the dst vector, resolving vertical T-Junctions along the way
85 *
86 * First pass through, divideSpanRTL will be set because the 'previous span' (indexing into the dst
87 * vector) will be reversed. Each rectangle in the original list, starting from the bottom, will be
88 * compared with the span directly below, and subdivided as needed to resolve T-junctions.
89 *
90 * The resulting temporary vector will be a completely reversed copy of the original, without any
91 * bottom-up T-junctions.
92 *
93 * Second pass through, divideSpanRTL will be false since the previous span will index into the
94 * final, correctly ordered region buffer. Each rectangle will be compared with the span directly
95 * above it, and subdivided to resolve any remaining T-junctions.
96 */
97static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end,
98 Vector<Rect>& dst, int spanDirection) {
99 dst.clear();
100
101 const Rect* current = end - 1;
102 int lastTop = current->top;
103
104 // add first span immediately
105 do {
106 dst.add(*current);
107 current--;
108 } while (current->top == lastTop && current >= begin);
109
Dan Stozad3182402014-11-17 12:03:59 -0800110 int beginLastSpan = -1;
111 int endLastSpan = -1;
Chris Craik3e010f32013-02-25 19:12:47 -0800112 int top = -1;
113 int bottom = -1;
114
115 // for all other spans, split if a t-junction exists in the span directly above
116 while (current >= begin) {
117 if (current->top != (current + 1)->top) {
118 // new span
119 if ((spanDirection == direction_RTL && current->bottom != (current + 1)->top) ||
120 (spanDirection == direction_LTR && current->top != (current + 1)->bottom)) {
121 // previous span not directly adjacent, don't check for T junctions
122 beginLastSpan = INT_MAX;
123 } else {
124 beginLastSpan = endLastSpan + 1;
125 }
Dan Stozad3182402014-11-17 12:03:59 -0800126 endLastSpan = static_cast<int>(dst.size()) - 1;
Chris Craik3e010f32013-02-25 19:12:47 -0800127
128 top = current->top;
129 bottom = current->bottom;
130 }
131 int left = current->left;
132 int right = current->right;
133
Dan Stozad3182402014-11-17 12:03:59 -0800134 for (int prevIndex = beginLastSpan; prevIndex <= endLastSpan; prevIndex++) {
135 // prevIndex can't be -1 here because if endLastSpan is set to a
136 // value greater than -1 (allowing the loop to execute),
137 // beginLastSpan (and therefore prevIndex) will also be increased
ywenaef04452015-03-26 19:51:12 +0800138 const Rect prev = dst[static_cast<size_t>(prevIndex)];
Chris Craik3e010f32013-02-25 19:12:47 -0800139 if (spanDirection == direction_RTL) {
140 // iterating over previous span RTL, quit if it's too far left
ywenaef04452015-03-26 19:51:12 +0800141 if (prev.right <= left) break;
Chris Craik3e010f32013-02-25 19:12:47 -0800142
ywenaef04452015-03-26 19:51:12 +0800143 if (prev.right > left && prev.right < right) {
144 dst.add(Rect(prev.right, top, right, bottom));
145 right = prev.right;
Chris Craik3e010f32013-02-25 19:12:47 -0800146 }
147
ywenaef04452015-03-26 19:51:12 +0800148 if (prev.left > left && prev.left < right) {
149 dst.add(Rect(prev.left, top, right, bottom));
150 right = prev.left;
Chris Craik3e010f32013-02-25 19:12:47 -0800151 }
152
153 // if an entry in the previous span is too far right, nothing further left in the
154 // current span will need it
ywenaef04452015-03-26 19:51:12 +0800155 if (prev.left >= right) {
Chris Craik3e010f32013-02-25 19:12:47 -0800156 beginLastSpan = prevIndex;
157 }
158 } else {
159 // iterating over previous span LTR, quit if it's too far right
ywenaef04452015-03-26 19:51:12 +0800160 if (prev.left >= right) break;
Chris Craik3e010f32013-02-25 19:12:47 -0800161
ywenaef04452015-03-26 19:51:12 +0800162 if (prev.left > left && prev.left < right) {
163 dst.add(Rect(left, top, prev.left, bottom));
164 left = prev.left;
Chris Craik3e010f32013-02-25 19:12:47 -0800165 }
166
ywenaef04452015-03-26 19:51:12 +0800167 if (prev.right > left && prev.right < right) {
168 dst.add(Rect(left, top, prev.right, bottom));
169 left = prev.right;
Chris Craik3e010f32013-02-25 19:12:47 -0800170 }
171 // if an entry in the previous span is too far left, nothing further right in the
172 // current span will need it
ywenaef04452015-03-26 19:51:12 +0800173 if (prev.right <= left) {
Chris Craik3e010f32013-02-25 19:12:47 -0800174 beginLastSpan = prevIndex;
175 }
176 }
177 }
178
179 if (left < right) {
180 dst.add(Rect(left, top, right, bottom));
181 }
182
183 current--;
184 }
185}
186
187/**
188 * Creates a new region with the same data as the argument, but divides rectangles as necessary to
189 * remove T-Junctions
190 *
191 * Note: the output will not necessarily be a very efficient representation of the region, since it
192 * may be that a triangle-based approach would generate significantly simpler geometry
193 */
194Region Region::createTJunctionFreeRegion(const Region& r) {
195 if (r.isEmpty()) return r;
196 if (r.isRect()) return r;
197
198 Vector<Rect> reversed;
199 reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL);
200
201 Region outputRegion;
202 reverseRectsResolvingJunctions(reversed.begin(), reversed.end(),
203 outputRegion.mStorage, direction_LTR);
204 outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds
205
206#if VALIDATE_REGIONS
207 validate(outputRegion, "T-Junction free region");
208#endif
209
210 return outputRegion;
211}
212
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800213Region& Region::operator = (const Region& rhs)
214{
Mathias Agopian20f68782009-05-11 00:03:41 -0700215#if VALIDATE_REGIONS
Mathias Agopiand0b55c02011-03-16 23:18:07 -0700216 validate(*this, "this->operator=");
217 validate(rhs, "rhs.operator=");
Mathias Agopian20f68782009-05-11 00:03:41 -0700218#endif
Mathias Agopian20f68782009-05-11 00:03:41 -0700219 mStorage = rhs.mStorage;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800220 return *this;
221}
222
Mathias Agopian9f961452009-06-29 18:46:37 -0700223Region& Region::makeBoundsSelf()
224{
Mathias Agopian3ab68552012-08-31 14:31:40 -0700225 if (mStorage.size() >= 2) {
226 const Rect bounds(getBounds());
227 mStorage.clear();
228 mStorage.add(bounds);
229 }
Mathias Agopian9f961452009-06-29 18:46:37 -0700230 return *this;
231}
232
Michael Wright1c284a92014-02-10 13:00:14 -0800233bool Region::contains(const Point& point) const {
234 return contains(point.x, point.y);
235}
236
237bool Region::contains(int x, int y) const {
238 const_iterator cur = begin();
239 const_iterator const tail = end();
240 while (cur != tail) {
241 if (y >= cur->top && y < cur->bottom && x >= cur->left && x < cur->right) {
242 return true;
243 }
244 cur++;
245 }
246 return false;
247}
248
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800249void Region::clear()
250{
Mathias Agopian20f68782009-05-11 00:03:41 -0700251 mStorage.clear();
Mathias Agopian3ab68552012-08-31 14:31:40 -0700252 mStorage.add(Rect(0,0));
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800253}
254
255void Region::set(const Rect& r)
256{
Mathias Agopian20f68782009-05-11 00:03:41 -0700257 mStorage.clear();
Mathias Agopian3ab68552012-08-31 14:31:40 -0700258 mStorage.add(r);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800259}
260
Dan Stozad3182402014-11-17 12:03:59 -0800261void Region::set(int32_t w, int32_t h)
Mathias Agopian0926f502009-05-04 14:17:04 -0700262{
Mathias Agopian20f68782009-05-11 00:03:41 -0700263 mStorage.clear();
Dan Stozad3182402014-11-17 12:03:59 -0800264 mStorage.add(Rect(w, h));
Mathias Agopian0926f502009-05-04 14:17:04 -0700265}
266
Bernhard Rosenkraenzerfe4966d2014-12-22 21:15:08 +0100267void Region::set(uint32_t w, uint32_t h)
268{
269 mStorage.clear();
270 mStorage.add(Rect(w, h));
271}
272
Mathias Agopian2ca79392013-04-02 18:30:32 -0700273bool Region::isTriviallyEqual(const Region& region) const {
274 return begin() == region.begin();
275}
276
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800277// ----------------------------------------------------------------------------
278
Mathias Agopian20f68782009-05-11 00:03:41 -0700279void Region::addRectUnchecked(int l, int t, int r, int b)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800280{
Mathias Agopian3ab68552012-08-31 14:31:40 -0700281 Rect rect(l,t,r,b);
282 size_t where = mStorage.size() - 1;
283 mStorage.insertAt(rect, where, 1);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800284}
285
Mathias Agopian20f68782009-05-11 00:03:41 -0700286// ----------------------------------------------------------------------------
287
288Region& Region::orSelf(const Rect& r) {
289 return operationSelf(r, op_or);
290}
Romain Guyb8a2e982012-02-07 17:04:34 -0800291Region& Region::xorSelf(const Rect& r) {
292 return operationSelf(r, op_xor);
293}
Mathias Agopian20f68782009-05-11 00:03:41 -0700294Region& Region::andSelf(const Rect& r) {
295 return operationSelf(r, op_and);
296}
297Region& Region::subtractSelf(const Rect& r) {
298 return operationSelf(r, op_nand);
299}
Colin Cross8f279962016-09-26 13:08:16 -0700300Region& Region::operationSelf(const Rect& r, uint32_t op) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700301 Region lhs(*this);
302 boolean_operation(op, *this, lhs, r);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800303 return *this;
304}
305
306// ----------------------------------------------------------------------------
307
308Region& Region::orSelf(const Region& rhs) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700309 return operationSelf(rhs, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800310}
Romain Guyb8a2e982012-02-07 17:04:34 -0800311Region& Region::xorSelf(const Region& rhs) {
312 return operationSelf(rhs, op_xor);
313}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800314Region& Region::andSelf(const Region& rhs) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700315 return operationSelf(rhs, op_and);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800316}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800317Region& Region::subtractSelf(const Region& rhs) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700318 return operationSelf(rhs, op_nand);
319}
Colin Cross8f279962016-09-26 13:08:16 -0700320Region& Region::operationSelf(const Region& rhs, uint32_t op) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700321 Region lhs(*this);
322 boolean_operation(op, *this, lhs, rhs);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800323 return *this;
324}
325
326Region& Region::translateSelf(int x, int y) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700327 if (x|y) translate(*this, x, y);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800328 return *this;
329}
330
Riddle Hsu39d4aa52018-11-30 20:46:53 +0800331Region& Region::scaleSelf(float sx, float sy) {
Robert Carre07e1032018-11-26 12:55:53 -0800332 size_t count = mStorage.size();
333 Rect* rects = mStorage.editArray();
334 while (count) {
Riddle Hsu39d4aa52018-11-30 20:46:53 +0800335 rects->left = static_cast<int32_t>(rects->left * sx + 0.5f);
336 rects->right = static_cast<int32_t>(rects->right * sx + 0.5f);
337 rects->top = static_cast<int32_t>(rects->top * sy + 0.5f);
338 rects->bottom = static_cast<int32_t>(rects->bottom * sy + 0.5f);
Robert Carre07e1032018-11-26 12:55:53 -0800339 rects++;
340 count--;
341 }
342 return *this;
343}
344
Mathias Agopian20f68782009-05-11 00:03:41 -0700345// ----------------------------------------------------------------------------
346
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700347const Region Region::merge(const Rect& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700348 return operation(rhs, op_or);
349}
Romain Guyb8a2e982012-02-07 17:04:34 -0800350const Region Region::mergeExclusive(const Rect& rhs) const {
351 return operation(rhs, op_xor);
352}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700353const Region Region::intersect(const Rect& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700354 return operation(rhs, op_and);
355}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700356const Region Region::subtract(const Rect& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700357 return operation(rhs, op_nand);
358}
Colin Cross8f279962016-09-26 13:08:16 -0700359const Region Region::operation(const Rect& rhs, uint32_t op) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700360 Region result;
361 boolean_operation(op, result, *this, rhs);
362 return result;
363}
364
365// ----------------------------------------------------------------------------
366
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700367const Region Region::merge(const Region& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700368 return operation(rhs, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800369}
Romain Guyb8a2e982012-02-07 17:04:34 -0800370const Region Region::mergeExclusive(const Region& rhs) const {
371 return operation(rhs, op_xor);
372}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700373const Region Region::intersect(const Region& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700374 return operation(rhs, op_and);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800375}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700376const Region Region::subtract(const Region& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700377 return operation(rhs, op_nand);
378}
Colin Cross8f279962016-09-26 13:08:16 -0700379const Region Region::operation(const Region& rhs, uint32_t op) const {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800380 Region result;
Mathias Agopian20f68782009-05-11 00:03:41 -0700381 boolean_operation(op, result, *this, rhs);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800382 return result;
383}
384
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700385const Region Region::translate(int x, int y) const {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800386 Region result;
Mathias Agopian20f68782009-05-11 00:03:41 -0700387 translate(result, *this, x, y);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800388 return result;
389}
390
391// ----------------------------------------------------------------------------
392
393Region& Region::orSelf(const Region& rhs, int dx, int dy) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700394 return operationSelf(rhs, dx, dy, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800395}
Romain Guyb8a2e982012-02-07 17:04:34 -0800396Region& Region::xorSelf(const Region& rhs, int dx, int dy) {
397 return operationSelf(rhs, dx, dy, op_xor);
398}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800399Region& Region::andSelf(const Region& rhs, int dx, int dy) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700400 return operationSelf(rhs, dx, dy, op_and);
401}
402Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
403 return operationSelf(rhs, dx, dy, op_nand);
404}
Colin Cross8f279962016-09-26 13:08:16 -0700405Region& Region::operationSelf(const Region& rhs, int dx, int dy, uint32_t op) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700406 Region lhs(*this);
407 boolean_operation(op, *this, lhs, rhs, dx, dy);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800408 return *this;
409}
410
Mathias Agopian20f68782009-05-11 00:03:41 -0700411// ----------------------------------------------------------------------------
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800412
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700413const Region Region::merge(const Region& rhs, int dx, int dy) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700414 return operation(rhs, dx, dy, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800415}
Romain Guyb8a2e982012-02-07 17:04:34 -0800416const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const {
417 return operation(rhs, dx, dy, op_xor);
418}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700419const Region Region::intersect(const Region& rhs, int dx, int dy) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700420 return operation(rhs, dx, dy, op_and);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800421}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700422const Region Region::subtract(const Region& rhs, int dx, int dy) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700423 return operation(rhs, dx, dy, op_nand);
424}
Colin Cross8f279962016-09-26 13:08:16 -0700425const Region Region::operation(const Region& rhs, int dx, int dy, uint32_t op) const {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800426 Region result;
Mathias Agopian20f68782009-05-11 00:03:41 -0700427 boolean_operation(op, result, *this, rhs, dx, dy);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800428 return result;
429}
430
431// ----------------------------------------------------------------------------
432
Mathias Agopian20f68782009-05-11 00:03:41 -0700433// This is our region rasterizer, which merges rects and spans together
434// to obtain an optimal region.
Dan Stozad3182402014-11-17 12:03:59 -0800435class Region::rasterizer : public region_operator<Rect>::region_rasterizer
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800436{
Mathias Agopian3ab68552012-08-31 14:31:40 -0700437 Rect bounds;
Mathias Agopian20f68782009-05-11 00:03:41 -0700438 Vector<Rect>& storage;
439 Rect* head;
440 Rect* tail;
441 Vector<Rect> span;
442 Rect* cur;
443public:
Chih-Hung Hsiehe2347b72016-04-25 15:41:05 -0700444 explicit rasterizer(Region& reg)
Mathias Agopian3ab68552012-08-31 14:31:40 -0700445 : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() {
Mathias Agopian20f68782009-05-11 00:03:41 -0700446 storage.clear();
447 }
448
Dan Stozad3182402014-11-17 12:03:59 -0800449 virtual ~rasterizer();
450
451 virtual void operator()(const Rect& rect);
452
Mathias Agopian20f68782009-05-11 00:03:41 -0700453private:
Dan Stozad3182402014-11-17 12:03:59 -0800454 template<typename T>
Mathias Agopian20f68782009-05-11 00:03:41 -0700455 static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; }
Dan Stozad3182402014-11-17 12:03:59 -0800456 template<typename T>
Mathias Agopian20f68782009-05-11 00:03:41 -0700457 static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; }
Dan Stozad3182402014-11-17 12:03:59 -0800458
459 void flushSpan();
Mathias Agopian20f68782009-05-11 00:03:41 -0700460};
461
Dan Stozad3182402014-11-17 12:03:59 -0800462Region::rasterizer::~rasterizer()
463{
464 if (span.size()) {
465 flushSpan();
466 }
467 if (storage.size()) {
468 bounds.top = storage.itemAt(0).top;
469 bounds.bottom = storage.top().bottom;
470 if (storage.size() == 1) {
471 storage.clear();
472 }
473 } else {
474 bounds.left = 0;
475 bounds.right = 0;
476 }
477 storage.add(bounds);
478}
479
480void Region::rasterizer::operator()(const Rect& rect)
481{
482 //ALOGD(">>> %3d, %3d, %3d, %3d",
483 // rect.left, rect.top, rect.right, rect.bottom);
484 if (span.size()) {
485 if (cur->top != rect.top) {
486 flushSpan();
487 } else if (cur->right == rect.left) {
488 cur->right = rect.right;
489 return;
490 }
491 }
492 span.add(rect);
493 cur = span.editArray() + (span.size() - 1);
494}
495
496void Region::rasterizer::flushSpan()
497{
498 bool merge = false;
499 if (tail-head == ssize_t(span.size())) {
500 Rect const* p = span.editArray();
501 Rect const* q = head;
502 if (p->top == q->bottom) {
503 merge = true;
504 while (q != tail) {
505 if ((p->left != q->left) || (p->right != q->right)) {
506 merge = false;
507 break;
508 }
Stephen Hines9c22c3c2016-03-31 22:02:38 -0700509 p++;
510 q++;
Dan Stozad3182402014-11-17 12:03:59 -0800511 }
512 }
513 }
514 if (merge) {
515 const int bottom = span[0].bottom;
516 Rect* r = head;
517 while (r != tail) {
518 r->bottom = bottom;
519 r++;
520 }
521 } else {
522 bounds.left = min(span.itemAt(0).left, bounds.left);
523 bounds.right = max(span.top().right, bounds.right);
524 storage.appendVector(span);
525 tail = storage.editArray() + storage.size();
526 head = tail - span.size();
527 }
528 span.clear();
529}
530
Mathias Agopian068d47f2012-09-11 18:56:23 -0700531bool Region::validate(const Region& reg, const char* name, bool silent)
Mathias Agopian20f68782009-05-11 00:03:41 -0700532{
Chia-I Wub420b582018-02-07 11:53:41 -0800533 if (reg.mStorage.isEmpty()) {
534 ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name);
535 // return immediately as the code below assumes mStorage is non-empty
536 return false;
537 }
538
Mathias Agopian20f68782009-05-11 00:03:41 -0700539 bool result = true;
540 const_iterator cur = reg.begin();
541 const_iterator const tail = reg.end();
Mathias Agopian068d47f2012-09-11 18:56:23 -0700542 const_iterator prev = cur;
Mathias Agopian20f68782009-05-11 00:03:41 -0700543 Rect b(*prev);
544 while (cur != tail) {
Mathias Agopian068d47f2012-09-11 18:56:23 -0700545 if (cur->isValid() == false) {
Dan Stoza5065a552015-03-17 16:23:42 -0700546 // We allow this particular flavor of invalid Rect, since it is used
547 // as a signal value in various parts of the system
548 if (*cur != Rect::INVALID_RECT) {
549 ALOGE_IF(!silent, "%s: region contains an invalid Rect", name);
550 result = false;
551 }
Mathias Agopian068d47f2012-09-11 18:56:23 -0700552 }
553 if (cur->right > region_operator<Rect>::max_value) {
554 ALOGE_IF(!silent, "%s: rect->right > max_value", name);
555 result = false;
556 }
557 if (cur->bottom > region_operator<Rect>::max_value) {
558 ALOGE_IF(!silent, "%s: rect->right > max_value", name);
559 result = false;
560 }
561 if (prev != cur) {
562 b.left = b.left < cur->left ? b.left : cur->left;
563 b.top = b.top < cur->top ? b.top : cur->top;
564 b.right = b.right > cur->right ? b.right : cur->right;
565 b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
566 if ((*prev < *cur) == false) {
567 ALOGE_IF(!silent, "%s: region's Rects not sorted", name);
Mathias Agopian20f68782009-05-11 00:03:41 -0700568 result = false;
Mathias Agopian068d47f2012-09-11 18:56:23 -0700569 }
570 if (cur->top == prev->top) {
571 if (cur->bottom != prev->bottom) {
572 ALOGE_IF(!silent, "%s: invalid span %p", name, cur);
573 result = false;
574 } else if (cur->left < prev->right) {
575 ALOGE_IF(!silent,
576 "%s: spans overlap horizontally prev=%p, cur=%p",
577 name, prev, cur);
578 result = false;
579 }
580 } else if (cur->top < prev->bottom) {
581 ALOGE_IF(!silent,
582 "%s: spans overlap vertically prev=%p, cur=%p",
Mathias Agopian20f68782009-05-11 00:03:41 -0700583 name, prev, cur);
584 result = false;
585 }
Mathias Agopian068d47f2012-09-11 18:56:23 -0700586 prev = cur;
Mathias Agopian20f68782009-05-11 00:03:41 -0700587 }
Mathias Agopian20f68782009-05-11 00:03:41 -0700588 cur++;
589 }
590 if (b != reg.getBounds()) {
591 result = false;
Mathias Agopian068d47f2012-09-11 18:56:23 -0700592 ALOGE_IF(!silent,
593 "%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
Mathias Agopian20f68782009-05-11 00:03:41 -0700594 b.left, b.top, b.right, b.bottom,
595 reg.getBounds().left, reg.getBounds().top,
596 reg.getBounds().right, reg.getBounds().bottom);
597 }
Mathias Agopian3ab68552012-08-31 14:31:40 -0700598 if (reg.mStorage.size() == 2) {
Mathias Agopian068d47f2012-09-11 18:56:23 -0700599 result = false;
600 ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name);
Mathias Agopian3ab68552012-08-31 14:31:40 -0700601 }
Mathias Agopian068d47f2012-09-11 18:56:23 -0700602 if (result == false && !silent) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700603 reg.dump(name);
Mathias Agopiancab25d62013-03-21 17:12:40 -0700604 CallStack stack(LOG_TAG);
Mathias Agopian20f68782009-05-11 00:03:41 -0700605 }
606 return result;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800607}
608
Colin Cross8f279962016-09-26 13:08:16 -0700609void Region::boolean_operation(uint32_t op, Region& dst,
Mathias Agopian20f68782009-05-11 00:03:41 -0700610 const Region& lhs,
611 const Region& rhs, int dx, int dy)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800612{
Mathias Agopiand0b55c02011-03-16 23:18:07 -0700613#if VALIDATE_REGIONS
614 validate(lhs, "boolean_operation (before): lhs");
615 validate(rhs, "boolean_operation (before): rhs");
616 validate(dst, "boolean_operation (before): dst");
617#endif
618
Mathias Agopian20f68782009-05-11 00:03:41 -0700619 size_t lhs_count;
620 Rect const * const lhs_rects = lhs.getArray(&lhs_count);
621
622 size_t rhs_count;
623 Rect const * const rhs_rects = rhs.getArray(&rhs_count);
624
625 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
626 region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy);
627 region_operator<Rect> operation(op, lhs_region, rhs_region);
628 { // scope for rasterizer (dtor has side effects)
629 rasterizer r(dst);
630 operation(r);
631 }
632
633#if VALIDATE_REGIONS
634 validate(lhs, "boolean_operation: lhs");
635 validate(rhs, "boolean_operation: rhs");
636 validate(dst, "boolean_operation: dst");
637#endif
638
639#if VALIDATE_WITH_CORECG
640 SkRegion sk_lhs;
641 SkRegion sk_rhs;
642 SkRegion sk_dst;
643
644 for (size_t i=0 ; i<lhs_count ; i++)
645 sk_lhs.op(
646 lhs_rects[i].left + dx,
647 lhs_rects[i].top + dy,
648 lhs_rects[i].right + dx,
649 lhs_rects[i].bottom + dy,
650 SkRegion::kUnion_Op);
651
652 for (size_t i=0 ; i<rhs_count ; i++)
653 sk_rhs.op(
654 rhs_rects[i].left + dx,
655 rhs_rects[i].top + dy,
656 rhs_rects[i].right + dx,
657 rhs_rects[i].bottom + dy,
658 SkRegion::kUnion_Op);
659
660 const char* name = "---";
661 SkRegion::Op sk_op;
662 switch (op) {
663 case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
Romain Guyb8a2e982012-02-07 17:04:34 -0800664 case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break;
Mathias Agopian20f68782009-05-11 00:03:41 -0700665 case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
666 case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
667 }
668 sk_dst.op(sk_lhs, sk_rhs, sk_op);
669
670 if (sk_dst.isEmpty() && dst.isEmpty())
671 return;
672
673 bool same = true;
674 Region::const_iterator head = dst.begin();
675 Region::const_iterator const tail = dst.end();
676 SkRegion::Iterator it(sk_dst);
677 while (!it.done()) {
678 if (head != tail) {
679 if (
680 head->left != it.rect().fLeft ||
681 head->top != it.rect().fTop ||
682 head->right != it.rect().fRight ||
683 head->bottom != it.rect().fBottom
684 ) {
685 same = false;
686 break;
687 }
688 } else {
689 same = false;
690 break;
691 }
692 head++;
693 it.next();
694 }
695
696 if (head != tail) {
697 same = false;
698 }
699
700 if(!same) {
Steve Block9d453682011-12-20 16:23:08 +0000701 ALOGD("---\nregion boolean %s failed", name);
Mathias Agopian20f68782009-05-11 00:03:41 -0700702 lhs.dump("lhs");
703 rhs.dump("rhs");
704 dst.dump("dst");
Steve Block9d453682011-12-20 16:23:08 +0000705 ALOGD("should be");
Mathias Agopian20f68782009-05-11 00:03:41 -0700706 SkRegion::Iterator it(sk_dst);
707 while (!it.done()) {
Steve Block9d453682011-12-20 16:23:08 +0000708 ALOGD(" [%3d, %3d, %3d, %3d]",
Mathias Agopian20f68782009-05-11 00:03:41 -0700709 it.rect().fLeft,
710 it.rect().fTop,
711 it.rect().fRight,
712 it.rect().fBottom);
713 it.next();
714 }
715 }
716#endif
717}
718
Colin Cross8f279962016-09-26 13:08:16 -0700719void Region::boolean_operation(uint32_t op, Region& dst,
Mathias Agopian20f68782009-05-11 00:03:41 -0700720 const Region& lhs,
721 const Rect& rhs, int dx, int dy)
722{
Dan Stoza5065a552015-03-17 16:23:42 -0700723 // We allow this particular flavor of invalid Rect, since it is used as a
724 // signal value in various parts of the system
725 if (!rhs.isValid() && rhs != Rect::INVALID_RECT) {
Steve Blocke6f43dd2012-01-06 19:20:56 +0000726 ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}",
Mathias Agopian04504522011-09-19 16:12:08 -0700727 op, rhs.left, rhs.top, rhs.right, rhs.bottom);
Mathias Agopian0857c8f2011-09-26 15:58:20 -0700728 return;
Mathias Agopian04504522011-09-19 16:12:08 -0700729 }
730
Mathias Agopian20f68782009-05-11 00:03:41 -0700731#if VALIDATE_WITH_CORECG || VALIDATE_REGIONS
732 boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
733#else
734 size_t lhs_count;
735 Rect const * const lhs_rects = lhs.getArray(&lhs_count);
736
737 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
738 region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy);
739 region_operator<Rect> operation(op, lhs_region, rhs_region);
740 { // scope for rasterizer (dtor has side effects)
741 rasterizer r(dst);
742 operation(r);
743 }
744
745#endif
746}
747
Colin Cross8f279962016-09-26 13:08:16 -0700748void Region::boolean_operation(uint32_t op, Region& dst,
Mathias Agopian20f68782009-05-11 00:03:41 -0700749 const Region& lhs, const Region& rhs)
750{
751 boolean_operation(op, dst, lhs, rhs, 0, 0);
752}
753
Colin Cross8f279962016-09-26 13:08:16 -0700754void Region::boolean_operation(uint32_t op, Region& dst,
Mathias Agopian20f68782009-05-11 00:03:41 -0700755 const Region& lhs, const Rect& rhs)
756{
757 boolean_operation(op, dst, lhs, rhs, 0, 0);
758}
759
760void Region::translate(Region& reg, int dx, int dy)
761{
Mathias Agopian4c0a1702012-08-31 12:45:33 -0700762 if ((dx || dy) && !reg.isEmpty()) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700763#if VALIDATE_REGIONS
764 validate(reg, "translate (before)");
765#endif
Mathias Agopian20f68782009-05-11 00:03:41 -0700766 size_t count = reg.mStorage.size();
767 Rect* rects = reg.mStorage.editArray();
768 while (count) {
Mathias Agopian6c7f25a2013-05-09 20:37:10 -0700769 rects->offsetBy(dx, dy);
Mathias Agopian20f68782009-05-11 00:03:41 -0700770 rects++;
771 count--;
772 }
773#if VALIDATE_REGIONS
774 validate(reg, "translate (after)");
775#endif
776 }
777}
778
779void Region::translate(Region& dst, const Region& reg, int dx, int dy)
780{
781 dst = reg;
782 translate(dst, dx, dy);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800783}
784
785// ----------------------------------------------------------------------------
786
Mathias Agopiane1424282013-07-29 21:24:40 -0700787size_t Region::getFlattenedSize() const {
Dan Stoza6fbefbb2015-03-23 13:46:14 -0700788 return sizeof(uint32_t) + mStorage.size() * sizeof(Rect);
Mathias Agopian8683fca2012-08-12 19:37:16 -0700789}
790
Mathias Agopiane1424282013-07-29 21:24:40 -0700791status_t Region::flatten(void* buffer, size_t size) const {
Mathias Agopian068d47f2012-09-11 18:56:23 -0700792#if VALIDATE_REGIONS
793 validate(*this, "Region::flatten");
794#endif
Dan Stoza6fbefbb2015-03-23 13:46:14 -0700795 if (size < getFlattenedSize()) {
Mathias Agopiane1424282013-07-29 21:24:40 -0700796 return NO_MEMORY;
797 }
Dan Stoza6fbefbb2015-03-23 13:46:14 -0700798 // Cast to uint32_t since the size of a size_t can vary between 32- and
799 // 64-bit processes
800 FlattenableUtils::write(buffer, size, static_cast<uint32_t>(mStorage.size()));
801 for (auto rect : mStorage) {
802 status_t result = rect.flatten(buffer, size);
803 if (result != NO_ERROR) {
804 return result;
805 }
806 FlattenableUtils::advance(buffer, size, sizeof(rect));
807 }
Mathias Agopian8683fca2012-08-12 19:37:16 -0700808 return NO_ERROR;
809}
810
811status_t Region::unflatten(void const* buffer, size_t size) {
Dan Stoza6fbefbb2015-03-23 13:46:14 -0700812 if (size < sizeof(uint32_t)) {
813 return NO_MEMORY;
Mathias Agopian20f68782009-05-11 00:03:41 -0700814 }
Dan Stoza6fbefbb2015-03-23 13:46:14 -0700815
816 uint32_t numRects = 0;
817 FlattenableUtils::read(buffer, size, numRects);
818 if (size < numRects * sizeof(Rect)) {
819 return NO_MEMORY;
820 }
821
Pablo Ceballos1a65fcc2016-07-13 14:11:57 -0700822 if (numRects > (UINT32_MAX / sizeof(Rect))) {
Yi Kong48d76082019-03-24 02:01:06 -0700823 android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, nullptr, 0);
Pablo Ceballos1a65fcc2016-07-13 14:11:57 -0700824 return NO_MEMORY;
825 }
826
Dan Stoza6fbefbb2015-03-23 13:46:14 -0700827 Region result;
828 result.mStorage.clear();
829 for (size_t r = 0; r < numRects; ++r) {
Pablo Ceballos60d69222015-08-07 14:47:20 -0700830 Rect rect(Rect::EMPTY_RECT);
Dan Stoza6fbefbb2015-03-23 13:46:14 -0700831 status_t status = rect.unflatten(buffer, size);
832 if (status != NO_ERROR) {
833 return status;
834 }
835 FlattenableUtils::advance(buffer, size, sizeof(rect));
836 result.mStorage.push_back(rect);
837 }
838
Mathias Agopian3ab68552012-08-31 14:31:40 -0700839#if VALIDATE_REGIONS
Mathias Agopian068d47f2012-09-11 18:56:23 -0700840 validate(result, "Region::unflatten");
Mathias Agopian3ab68552012-08-31 14:31:40 -0700841#endif
Mathias Agopian068d47f2012-09-11 18:56:23 -0700842
843 if (!result.validate(result, "Region::unflatten", true)) {
844 ALOGE("Region::unflatten() failed, invalid region");
845 return BAD_VALUE;
846 }
847 mStorage = result.mStorage;
Mathias Agopian8683fca2012-08-12 19:37:16 -0700848 return NO_ERROR;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800849}
850
Mathias Agopian20f68782009-05-11 00:03:41 -0700851// ----------------------------------------------------------------------------
852
853Region::const_iterator Region::begin() const {
Mathias Agopian3ab68552012-08-31 14:31:40 -0700854 return mStorage.array();
Mathias Agopian20f68782009-05-11 00:03:41 -0700855}
856
857Region::const_iterator Region::end() const {
Dan Stoza2d023062018-04-09 12:14:55 -0700858 // Workaround for b/77643177
859 // mStorage should never be empty, but somehow it is and it's causing
860 // an abort in ubsan
861 if (mStorage.isEmpty()) return mStorage.array();
862
Mathias Agopian3ab68552012-08-31 14:31:40 -0700863 size_t numRects = isRect() ? 1 : mStorage.size() - 1;
864 return mStorage.array() + numRects;
Mathias Agopian20f68782009-05-11 00:03:41 -0700865}
866
867Rect const* Region::getArray(size_t* count) const {
Dan Stozad3182402014-11-17 12:03:59 -0800868 if (count) *count = static_cast<size_t>(end() - begin());
869 return begin();
Mathias Agopian20f68782009-05-11 00:03:41 -0700870}
871
Mathias Agopian20f68782009-05-11 00:03:41 -0700872// ----------------------------------------------------------------------------
873
Yiwei Zhang5434a782018-12-05 18:06:32 -0800874void Region::dump(std::string& out, const char* what, uint32_t /* flags */) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700875 const_iterator head = begin();
876 const_iterator const tail = end();
877
Yiwei Zhang5434a782018-12-05 18:06:32 -0800878 StringAppendF(&out, " Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail - head);
Mathias Agopian20f68782009-05-11 00:03:41 -0700879 while (head != tail) {
Yiwei Zhang5434a782018-12-05 18:06:32 -0800880 StringAppendF(&out, " [%3d, %3d, %3d, %3d]\n", head->left, head->top, head->right,
881 head->bottom);
Dan Stozad3182402014-11-17 12:03:59 -0800882 ++head;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800883 }
884}
885
Dan Stozad3182402014-11-17 12:03:59 -0800886void Region::dump(const char* what, uint32_t /* flags */) const
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800887{
Mathias Agopian20f68782009-05-11 00:03:41 -0700888 const_iterator head = begin();
889 const_iterator const tail = end();
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -0700890 ALOGD(" Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail-head);
Mathias Agopian20f68782009-05-11 00:03:41 -0700891 while (head != tail) {
Steve Block9d453682011-12-20 16:23:08 +0000892 ALOGD(" [%3d, %3d, %3d, %3d]\n",
Mathias Agopian20f68782009-05-11 00:03:41 -0700893 head->left, head->top, head->right, head->bottom);
894 head++;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800895 }
896}
897
898// ----------------------------------------------------------------------------
899
900}; // namespace android