blob: 53ef193713c4ca0359d52bb29b2dedbe0323c169 [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
Mathias Agopian20f68782009-05-11 00:03:41 -070022#include <utils/Log.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080023#include <utils/String8.h>
Mathias Agopian068d47f2012-09-11 18:56:23 -070024#include <utils/CallStack.h>
Mathias Agopian20f68782009-05-11 00:03:41 -070025
26#include <ui/Rect.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080027#include <ui/Region.h>
Mathias Agopian20f68782009-05-11 00:03:41 -070028#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 Projectedbf3b62009-03-03 19:31:44 -080040
41namespace android {
Mathias Agopian20f68782009-05-11 00:03:41 -070042// ----------------------------------------------------------------------------
43
44enum {
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 Projectedbf3b62009-03-03 19:31:44 -080050
Chris Craik3e010f32013-02-25 19:12:47 -080051enum {
52 direction_LTR,
53 direction_RTL
54};
55
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080056// ----------------------------------------------------------------------------
57
Mathias Agopian3ab68552012-08-31 14:31:40 -070058Region::Region() {
59 mStorage.add(Rect(0,0));
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080060}
61
62Region::Region(const Region& rhs)
Mathias Agopian3ab68552012-08-31 14:31:40 -070063 : mStorage(rhs.mStorage)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080064{
Mathias Agopiand0b55c02011-03-16 23:18:07 -070065#if VALIDATE_REGIONS
66 validate(rhs, "rhs copy-ctor");
67#endif
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080068}
69
Mathias Agopian3ab68552012-08-31 14:31:40 -070070Region::Region(const Rect& rhs) {
71 mStorage.add(rhs);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080072}
73
74Region::~Region()
75{
76}
77
Chris Craik3e010f32013-02-25 19:12:47 -080078/**
79 * Copy rects from the src vector into the dst vector, resolving vertical T-Junctions along the way
80 *
81 * First pass through, divideSpanRTL will be set because the 'previous span' (indexing into the dst
82 * vector) will be reversed. Each rectangle in the original list, starting from the bottom, will be
83 * compared with the span directly below, and subdivided as needed to resolve T-junctions.
84 *
85 * The resulting temporary vector will be a completely reversed copy of the original, without any
86 * bottom-up T-junctions.
87 *
88 * Second pass through, divideSpanRTL will be false since the previous span will index into the
89 * final, correctly ordered region buffer. Each rectangle will be compared with the span directly
90 * above it, and subdivided to resolve any remaining T-junctions.
91 */
92static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end,
93 Vector<Rect>& dst, int spanDirection) {
94 dst.clear();
95
96 const Rect* current = end - 1;
97 int lastTop = current->top;
98
99 // add first span immediately
100 do {
101 dst.add(*current);
102 current--;
103 } while (current->top == lastTop && current >= begin);
104
Dan Stozad3182402014-11-17 12:03:59 -0800105 int beginLastSpan = -1;
106 int endLastSpan = -1;
Chris Craik3e010f32013-02-25 19:12:47 -0800107 int top = -1;
108 int bottom = -1;
109
110 // for all other spans, split if a t-junction exists in the span directly above
111 while (current >= begin) {
112 if (current->top != (current + 1)->top) {
113 // new span
114 if ((spanDirection == direction_RTL && current->bottom != (current + 1)->top) ||
115 (spanDirection == direction_LTR && current->top != (current + 1)->bottom)) {
116 // previous span not directly adjacent, don't check for T junctions
117 beginLastSpan = INT_MAX;
118 } else {
119 beginLastSpan = endLastSpan + 1;
120 }
Dan Stozad3182402014-11-17 12:03:59 -0800121 endLastSpan = static_cast<int>(dst.size()) - 1;
Chris Craik3e010f32013-02-25 19:12:47 -0800122
123 top = current->top;
124 bottom = current->bottom;
125 }
126 int left = current->left;
127 int right = current->right;
128
Dan Stozad3182402014-11-17 12:03:59 -0800129 for (int prevIndex = beginLastSpan; prevIndex <= endLastSpan; prevIndex++) {
130 // prevIndex can't be -1 here because if endLastSpan is set to a
131 // value greater than -1 (allowing the loop to execute),
132 // beginLastSpan (and therefore prevIndex) will also be increased
ywenaef04452015-03-26 19:51:12 +0800133 const Rect prev = dst[static_cast<size_t>(prevIndex)];
Chris Craik3e010f32013-02-25 19:12:47 -0800134 if (spanDirection == direction_RTL) {
135 // iterating over previous span RTL, quit if it's too far left
ywenaef04452015-03-26 19:51:12 +0800136 if (prev.right <= left) break;
Chris Craik3e010f32013-02-25 19:12:47 -0800137
ywenaef04452015-03-26 19:51:12 +0800138 if (prev.right > left && prev.right < right) {
139 dst.add(Rect(prev.right, top, right, bottom));
140 right = prev.right;
Chris Craik3e010f32013-02-25 19:12:47 -0800141 }
142
ywenaef04452015-03-26 19:51:12 +0800143 if (prev.left > left && prev.left < right) {
144 dst.add(Rect(prev.left, top, right, bottom));
145 right = prev.left;
Chris Craik3e010f32013-02-25 19:12:47 -0800146 }
147
148 // if an entry in the previous span is too far right, nothing further left in the
149 // current span will need it
ywenaef04452015-03-26 19:51:12 +0800150 if (prev.left >= right) {
Chris Craik3e010f32013-02-25 19:12:47 -0800151 beginLastSpan = prevIndex;
152 }
153 } else {
154 // iterating over previous span LTR, quit if it's too far right
ywenaef04452015-03-26 19:51:12 +0800155 if (prev.left >= right) break;
Chris Craik3e010f32013-02-25 19:12:47 -0800156
ywenaef04452015-03-26 19:51:12 +0800157 if (prev.left > left && prev.left < right) {
158 dst.add(Rect(left, top, prev.left, bottom));
159 left = prev.left;
Chris Craik3e010f32013-02-25 19:12:47 -0800160 }
161
ywenaef04452015-03-26 19:51:12 +0800162 if (prev.right > left && prev.right < right) {
163 dst.add(Rect(left, top, prev.right, bottom));
164 left = prev.right;
Chris Craik3e010f32013-02-25 19:12:47 -0800165 }
166 // if an entry in the previous span is too far left, nothing further right in the
167 // current span will need it
ywenaef04452015-03-26 19:51:12 +0800168 if (prev.right <= left) {
Chris Craik3e010f32013-02-25 19:12:47 -0800169 beginLastSpan = prevIndex;
170 }
171 }
172 }
173
174 if (left < right) {
175 dst.add(Rect(left, top, right, bottom));
176 }
177
178 current--;
179 }
180}
181
182/**
183 * Creates a new region with the same data as the argument, but divides rectangles as necessary to
184 * remove T-Junctions
185 *
186 * Note: the output will not necessarily be a very efficient representation of the region, since it
187 * may be that a triangle-based approach would generate significantly simpler geometry
188 */
189Region Region::createTJunctionFreeRegion(const Region& r) {
190 if (r.isEmpty()) return r;
191 if (r.isRect()) return r;
192
193 Vector<Rect> reversed;
194 reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL);
195
196 Region outputRegion;
197 reverseRectsResolvingJunctions(reversed.begin(), reversed.end(),
198 outputRegion.mStorage, direction_LTR);
199 outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds
200
201#if VALIDATE_REGIONS
202 validate(outputRegion, "T-Junction free region");
203#endif
204
205 return outputRegion;
206}
207
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800208Region& Region::operator = (const Region& rhs)
209{
Mathias Agopian20f68782009-05-11 00:03:41 -0700210#if VALIDATE_REGIONS
Mathias Agopiand0b55c02011-03-16 23:18:07 -0700211 validate(*this, "this->operator=");
212 validate(rhs, "rhs.operator=");
Mathias Agopian20f68782009-05-11 00:03:41 -0700213#endif
Mathias Agopian20f68782009-05-11 00:03:41 -0700214 mStorage = rhs.mStorage;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800215 return *this;
216}
217
Mathias Agopian9f961452009-06-29 18:46:37 -0700218Region& Region::makeBoundsSelf()
219{
Mathias Agopian3ab68552012-08-31 14:31:40 -0700220 if (mStorage.size() >= 2) {
221 const Rect bounds(getBounds());
222 mStorage.clear();
223 mStorage.add(bounds);
224 }
Mathias Agopian9f961452009-06-29 18:46:37 -0700225 return *this;
226}
227
Michael Wright1c284a92014-02-10 13:00:14 -0800228bool Region::contains(const Point& point) const {
229 return contains(point.x, point.y);
230}
231
232bool Region::contains(int x, int y) const {
233 const_iterator cur = begin();
234 const_iterator const tail = end();
235 while (cur != tail) {
236 if (y >= cur->top && y < cur->bottom && x >= cur->left && x < cur->right) {
237 return true;
238 }
239 cur++;
240 }
241 return false;
242}
243
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800244void Region::clear()
245{
Mathias Agopian20f68782009-05-11 00:03:41 -0700246 mStorage.clear();
Mathias Agopian3ab68552012-08-31 14:31:40 -0700247 mStorage.add(Rect(0,0));
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800248}
249
250void Region::set(const Rect& r)
251{
Mathias Agopian20f68782009-05-11 00:03:41 -0700252 mStorage.clear();
Mathias Agopian3ab68552012-08-31 14:31:40 -0700253 mStorage.add(r);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800254}
255
Dan Stozad3182402014-11-17 12:03:59 -0800256void Region::set(int32_t w, int32_t h)
Mathias Agopian0926f502009-05-04 14:17:04 -0700257{
Mathias Agopian20f68782009-05-11 00:03:41 -0700258 mStorage.clear();
Dan Stozad3182402014-11-17 12:03:59 -0800259 mStorage.add(Rect(w, h));
Mathias Agopian0926f502009-05-04 14:17:04 -0700260}
261
Bernhard Rosenkraenzerfe4966d2014-12-22 21:15:08 +0100262void Region::set(uint32_t w, uint32_t h)
263{
264 mStorage.clear();
265 mStorage.add(Rect(w, h));
266}
267
Mathias Agopian2ca79392013-04-02 18:30:32 -0700268bool Region::isTriviallyEqual(const Region& region) const {
269 return begin() == region.begin();
270}
271
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800272// ----------------------------------------------------------------------------
273
Mathias Agopian20f68782009-05-11 00:03:41 -0700274void Region::addRectUnchecked(int l, int t, int r, int b)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800275{
Mathias Agopian3ab68552012-08-31 14:31:40 -0700276 Rect rect(l,t,r,b);
277 size_t where = mStorage.size() - 1;
278 mStorage.insertAt(rect, where, 1);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800279}
280
Mathias Agopian20f68782009-05-11 00:03:41 -0700281// ----------------------------------------------------------------------------
282
283Region& Region::orSelf(const Rect& r) {
284 return operationSelf(r, op_or);
285}
Romain Guyb8a2e982012-02-07 17:04:34 -0800286Region& Region::xorSelf(const Rect& r) {
287 return operationSelf(r, op_xor);
288}
Mathias Agopian20f68782009-05-11 00:03:41 -0700289Region& Region::andSelf(const Rect& r) {
290 return operationSelf(r, op_and);
291}
292Region& Region::subtractSelf(const Rect& r) {
293 return operationSelf(r, op_nand);
294}
295Region& Region::operationSelf(const Rect& r, int op) {
296 Region lhs(*this);
297 boolean_operation(op, *this, lhs, r);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800298 return *this;
299}
300
301// ----------------------------------------------------------------------------
302
303Region& Region::orSelf(const Region& rhs) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700304 return operationSelf(rhs, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800305}
Romain Guyb8a2e982012-02-07 17:04:34 -0800306Region& Region::xorSelf(const Region& rhs) {
307 return operationSelf(rhs, op_xor);
308}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800309Region& Region::andSelf(const Region& rhs) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700310 return operationSelf(rhs, op_and);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800311}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800312Region& Region::subtractSelf(const Region& rhs) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700313 return operationSelf(rhs, op_nand);
314}
315Region& Region::operationSelf(const Region& rhs, int op) {
316 Region lhs(*this);
317 boolean_operation(op, *this, lhs, rhs);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800318 return *this;
319}
320
321Region& Region::translateSelf(int x, int y) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700322 if (x|y) translate(*this, x, y);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800323 return *this;
324}
325
Mathias Agopian20f68782009-05-11 00:03:41 -0700326// ----------------------------------------------------------------------------
327
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700328const Region Region::merge(const Rect& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700329 return operation(rhs, op_or);
330}
Romain Guyb8a2e982012-02-07 17:04:34 -0800331const Region Region::mergeExclusive(const Rect& rhs) const {
332 return operation(rhs, op_xor);
333}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700334const Region Region::intersect(const Rect& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700335 return operation(rhs, op_and);
336}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700337const Region Region::subtract(const Rect& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700338 return operation(rhs, op_nand);
339}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700340const Region Region::operation(const Rect& rhs, int op) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700341 Region result;
342 boolean_operation(op, result, *this, rhs);
343 return result;
344}
345
346// ----------------------------------------------------------------------------
347
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700348const Region Region::merge(const Region& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700349 return operation(rhs, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800350}
Romain Guyb8a2e982012-02-07 17:04:34 -0800351const Region Region::mergeExclusive(const Region& rhs) const {
352 return operation(rhs, op_xor);
353}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700354const Region Region::intersect(const Region& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700355 return operation(rhs, op_and);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800356}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700357const Region Region::subtract(const Region& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700358 return operation(rhs, op_nand);
359}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700360const Region Region::operation(const Region& rhs, int op) const {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800361 Region result;
Mathias Agopian20f68782009-05-11 00:03:41 -0700362 boolean_operation(op, result, *this, rhs);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800363 return result;
364}
365
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700366const Region Region::translate(int x, int y) const {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800367 Region result;
Mathias Agopian20f68782009-05-11 00:03:41 -0700368 translate(result, *this, x, y);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800369 return result;
370}
371
372// ----------------------------------------------------------------------------
373
374Region& Region::orSelf(const Region& rhs, int dx, int dy) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700375 return operationSelf(rhs, dx, dy, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800376}
Romain Guyb8a2e982012-02-07 17:04:34 -0800377Region& Region::xorSelf(const Region& rhs, int dx, int dy) {
378 return operationSelf(rhs, dx, dy, op_xor);
379}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800380Region& Region::andSelf(const Region& rhs, int dx, int dy) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700381 return operationSelf(rhs, dx, dy, op_and);
382}
383Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
384 return operationSelf(rhs, dx, dy, op_nand);
385}
386Region& Region::operationSelf(const Region& rhs, int dx, int dy, int op) {
387 Region lhs(*this);
388 boolean_operation(op, *this, lhs, rhs, dx, dy);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800389 return *this;
390}
391
Mathias Agopian20f68782009-05-11 00:03:41 -0700392// ----------------------------------------------------------------------------
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800393
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700394const Region Region::merge(const Region& rhs, int dx, int dy) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700395 return operation(rhs, dx, dy, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800396}
Romain Guyb8a2e982012-02-07 17:04:34 -0800397const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const {
398 return operation(rhs, dx, dy, op_xor);
399}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700400const Region Region::intersect(const Region& rhs, int dx, int dy) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700401 return operation(rhs, dx, dy, op_and);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800402}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700403const Region Region::subtract(const Region& rhs, int dx, int dy) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700404 return operation(rhs, dx, dy, op_nand);
405}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700406const Region Region::operation(const Region& rhs, int dx, int dy, int op) const {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800407 Region result;
Mathias Agopian20f68782009-05-11 00:03:41 -0700408 boolean_operation(op, result, *this, rhs, dx, dy);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800409 return result;
410}
411
412// ----------------------------------------------------------------------------
413
Mathias Agopian20f68782009-05-11 00:03:41 -0700414// This is our region rasterizer, which merges rects and spans together
415// to obtain an optimal region.
Dan Stozad3182402014-11-17 12:03:59 -0800416class Region::rasterizer : public region_operator<Rect>::region_rasterizer
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800417{
Mathias Agopian3ab68552012-08-31 14:31:40 -0700418 Rect bounds;
Mathias Agopian20f68782009-05-11 00:03:41 -0700419 Vector<Rect>& storage;
420 Rect* head;
421 Rect* tail;
422 Vector<Rect> span;
423 Rect* cur;
424public:
Dan Stozad3182402014-11-17 12:03:59 -0800425 rasterizer(Region& reg)
Mathias Agopian3ab68552012-08-31 14:31:40 -0700426 : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() {
Mathias Agopian20f68782009-05-11 00:03:41 -0700427 storage.clear();
428 }
429
Dan Stozad3182402014-11-17 12:03:59 -0800430 virtual ~rasterizer();
431
432 virtual void operator()(const Rect& rect);
433
Mathias Agopian20f68782009-05-11 00:03:41 -0700434private:
Dan Stozad3182402014-11-17 12:03:59 -0800435 template<typename T>
Mathias Agopian20f68782009-05-11 00:03:41 -0700436 static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; }
Dan Stozad3182402014-11-17 12:03:59 -0800437 template<typename T>
Mathias Agopian20f68782009-05-11 00:03:41 -0700438 static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; }
Dan Stozad3182402014-11-17 12:03:59 -0800439
440 void flushSpan();
Mathias Agopian20f68782009-05-11 00:03:41 -0700441};
442
Dan Stozad3182402014-11-17 12:03:59 -0800443Region::rasterizer::~rasterizer()
444{
445 if (span.size()) {
446 flushSpan();
447 }
448 if (storage.size()) {
449 bounds.top = storage.itemAt(0).top;
450 bounds.bottom = storage.top().bottom;
451 if (storage.size() == 1) {
452 storage.clear();
453 }
454 } else {
455 bounds.left = 0;
456 bounds.right = 0;
457 }
458 storage.add(bounds);
459}
460
461void Region::rasterizer::operator()(const Rect& rect)
462{
463 //ALOGD(">>> %3d, %3d, %3d, %3d",
464 // rect.left, rect.top, rect.right, rect.bottom);
465 if (span.size()) {
466 if (cur->top != rect.top) {
467 flushSpan();
468 } else if (cur->right == rect.left) {
469 cur->right = rect.right;
470 return;
471 }
472 }
473 span.add(rect);
474 cur = span.editArray() + (span.size() - 1);
475}
476
477void Region::rasterizer::flushSpan()
478{
479 bool merge = false;
480 if (tail-head == ssize_t(span.size())) {
481 Rect const* p = span.editArray();
482 Rect const* q = head;
483 if (p->top == q->bottom) {
484 merge = true;
485 while (q != tail) {
486 if ((p->left != q->left) || (p->right != q->right)) {
487 merge = false;
488 break;
489 }
490 p++, q++;
491 }
492 }
493 }
494 if (merge) {
495 const int bottom = span[0].bottom;
496 Rect* r = head;
497 while (r != tail) {
498 r->bottom = bottom;
499 r++;
500 }
501 } else {
502 bounds.left = min(span.itemAt(0).left, bounds.left);
503 bounds.right = max(span.top().right, bounds.right);
504 storage.appendVector(span);
505 tail = storage.editArray() + storage.size();
506 head = tail - span.size();
507 }
508 span.clear();
509}
510
Mathias Agopian068d47f2012-09-11 18:56:23 -0700511bool Region::validate(const Region& reg, const char* name, bool silent)
Mathias Agopian20f68782009-05-11 00:03:41 -0700512{
513 bool result = true;
514 const_iterator cur = reg.begin();
515 const_iterator const tail = reg.end();
Mathias Agopian068d47f2012-09-11 18:56:23 -0700516 const_iterator prev = cur;
Mathias Agopian20f68782009-05-11 00:03:41 -0700517 Rect b(*prev);
518 while (cur != tail) {
Mathias Agopian068d47f2012-09-11 18:56:23 -0700519 if (cur->isValid() == false) {
520 ALOGE_IF(!silent, "%s: region contains an invalid Rect", name);
521 result = false;
522 }
523 if (cur->right > region_operator<Rect>::max_value) {
524 ALOGE_IF(!silent, "%s: rect->right > max_value", name);
525 result = false;
526 }
527 if (cur->bottom > region_operator<Rect>::max_value) {
528 ALOGE_IF(!silent, "%s: rect->right > max_value", name);
529 result = false;
530 }
531 if (prev != cur) {
532 b.left = b.left < cur->left ? b.left : cur->left;
533 b.top = b.top < cur->top ? b.top : cur->top;
534 b.right = b.right > cur->right ? b.right : cur->right;
535 b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
536 if ((*prev < *cur) == false) {
537 ALOGE_IF(!silent, "%s: region's Rects not sorted", name);
Mathias Agopian20f68782009-05-11 00:03:41 -0700538 result = false;
Mathias Agopian068d47f2012-09-11 18:56:23 -0700539 }
540 if (cur->top == prev->top) {
541 if (cur->bottom != prev->bottom) {
542 ALOGE_IF(!silent, "%s: invalid span %p", name, cur);
543 result = false;
544 } else if (cur->left < prev->right) {
545 ALOGE_IF(!silent,
546 "%s: spans overlap horizontally prev=%p, cur=%p",
547 name, prev, cur);
548 result = false;
549 }
550 } else if (cur->top < prev->bottom) {
551 ALOGE_IF(!silent,
552 "%s: spans overlap vertically prev=%p, cur=%p",
Mathias Agopian20f68782009-05-11 00:03:41 -0700553 name, prev, cur);
554 result = false;
555 }
Mathias Agopian068d47f2012-09-11 18:56:23 -0700556 prev = cur;
Mathias Agopian20f68782009-05-11 00:03:41 -0700557 }
Mathias Agopian20f68782009-05-11 00:03:41 -0700558 cur++;
559 }
560 if (b != reg.getBounds()) {
561 result = false;
Mathias Agopian068d47f2012-09-11 18:56:23 -0700562 ALOGE_IF(!silent,
563 "%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
Mathias Agopian20f68782009-05-11 00:03:41 -0700564 b.left, b.top, b.right, b.bottom,
565 reg.getBounds().left, reg.getBounds().top,
566 reg.getBounds().right, reg.getBounds().bottom);
567 }
Mathias Agopian3ab68552012-08-31 14:31:40 -0700568 if (reg.mStorage.size() == 2) {
Mathias Agopian068d47f2012-09-11 18:56:23 -0700569 result = false;
570 ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name);
Mathias Agopian3ab68552012-08-31 14:31:40 -0700571 }
Mathias Agopian068d47f2012-09-11 18:56:23 -0700572 if (result == false && !silent) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700573 reg.dump(name);
Mathias Agopiancab25d62013-03-21 17:12:40 -0700574 CallStack stack(LOG_TAG);
Mathias Agopian20f68782009-05-11 00:03:41 -0700575 }
576 return result;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800577}
578
Mathias Agopian20f68782009-05-11 00:03:41 -0700579void Region::boolean_operation(int op, Region& dst,
580 const Region& lhs,
581 const Region& rhs, int dx, int dy)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800582{
Mathias Agopiand0b55c02011-03-16 23:18:07 -0700583#if VALIDATE_REGIONS
584 validate(lhs, "boolean_operation (before): lhs");
585 validate(rhs, "boolean_operation (before): rhs");
586 validate(dst, "boolean_operation (before): dst");
587#endif
588
Mathias Agopian20f68782009-05-11 00:03:41 -0700589 size_t lhs_count;
590 Rect const * const lhs_rects = lhs.getArray(&lhs_count);
591
592 size_t rhs_count;
593 Rect const * const rhs_rects = rhs.getArray(&rhs_count);
594
595 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
596 region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy);
597 region_operator<Rect> operation(op, lhs_region, rhs_region);
598 { // scope for rasterizer (dtor has side effects)
599 rasterizer r(dst);
600 operation(r);
601 }
602
603#if VALIDATE_REGIONS
604 validate(lhs, "boolean_operation: lhs");
605 validate(rhs, "boolean_operation: rhs");
606 validate(dst, "boolean_operation: dst");
607#endif
608
609#if VALIDATE_WITH_CORECG
610 SkRegion sk_lhs;
611 SkRegion sk_rhs;
612 SkRegion sk_dst;
613
614 for (size_t i=0 ; i<lhs_count ; i++)
615 sk_lhs.op(
616 lhs_rects[i].left + dx,
617 lhs_rects[i].top + dy,
618 lhs_rects[i].right + dx,
619 lhs_rects[i].bottom + dy,
620 SkRegion::kUnion_Op);
621
622 for (size_t i=0 ; i<rhs_count ; i++)
623 sk_rhs.op(
624 rhs_rects[i].left + dx,
625 rhs_rects[i].top + dy,
626 rhs_rects[i].right + dx,
627 rhs_rects[i].bottom + dy,
628 SkRegion::kUnion_Op);
629
630 const char* name = "---";
631 SkRegion::Op sk_op;
632 switch (op) {
633 case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
Romain Guyb8a2e982012-02-07 17:04:34 -0800634 case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break;
Mathias Agopian20f68782009-05-11 00:03:41 -0700635 case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
636 case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
637 }
638 sk_dst.op(sk_lhs, sk_rhs, sk_op);
639
640 if (sk_dst.isEmpty() && dst.isEmpty())
641 return;
642
643 bool same = true;
644 Region::const_iterator head = dst.begin();
645 Region::const_iterator const tail = dst.end();
646 SkRegion::Iterator it(sk_dst);
647 while (!it.done()) {
648 if (head != tail) {
649 if (
650 head->left != it.rect().fLeft ||
651 head->top != it.rect().fTop ||
652 head->right != it.rect().fRight ||
653 head->bottom != it.rect().fBottom
654 ) {
655 same = false;
656 break;
657 }
658 } else {
659 same = false;
660 break;
661 }
662 head++;
663 it.next();
664 }
665
666 if (head != tail) {
667 same = false;
668 }
669
670 if(!same) {
Steve Block9d453682011-12-20 16:23:08 +0000671 ALOGD("---\nregion boolean %s failed", name);
Mathias Agopian20f68782009-05-11 00:03:41 -0700672 lhs.dump("lhs");
673 rhs.dump("rhs");
674 dst.dump("dst");
Steve Block9d453682011-12-20 16:23:08 +0000675 ALOGD("should be");
Mathias Agopian20f68782009-05-11 00:03:41 -0700676 SkRegion::Iterator it(sk_dst);
677 while (!it.done()) {
Steve Block9d453682011-12-20 16:23:08 +0000678 ALOGD(" [%3d, %3d, %3d, %3d]",
Mathias Agopian20f68782009-05-11 00:03:41 -0700679 it.rect().fLeft,
680 it.rect().fTop,
681 it.rect().fRight,
682 it.rect().fBottom);
683 it.next();
684 }
685 }
686#endif
687}
688
689void Region::boolean_operation(int op, Region& dst,
690 const Region& lhs,
691 const Rect& rhs, int dx, int dy)
692{
Mathias Agopian04504522011-09-19 16:12:08 -0700693 if (!rhs.isValid()) {
Steve Blocke6f43dd2012-01-06 19:20:56 +0000694 ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}",
Mathias Agopian04504522011-09-19 16:12:08 -0700695 op, rhs.left, rhs.top, rhs.right, rhs.bottom);
Mathias Agopian0857c8f2011-09-26 15:58:20 -0700696 return;
Mathias Agopian04504522011-09-19 16:12:08 -0700697 }
698
Mathias Agopian20f68782009-05-11 00:03:41 -0700699#if VALIDATE_WITH_CORECG || VALIDATE_REGIONS
700 boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
701#else
702 size_t lhs_count;
703 Rect const * const lhs_rects = lhs.getArray(&lhs_count);
704
705 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
706 region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy);
707 region_operator<Rect> operation(op, lhs_region, rhs_region);
708 { // scope for rasterizer (dtor has side effects)
709 rasterizer r(dst);
710 operation(r);
711 }
712
713#endif
714}
715
716void Region::boolean_operation(int op, Region& dst,
717 const Region& lhs, const Region& rhs)
718{
719 boolean_operation(op, dst, lhs, rhs, 0, 0);
720}
721
722void Region::boolean_operation(int op, Region& dst,
723 const Region& lhs, const Rect& rhs)
724{
725 boolean_operation(op, dst, lhs, rhs, 0, 0);
726}
727
728void Region::translate(Region& reg, int dx, int dy)
729{
Mathias Agopian4c0a1702012-08-31 12:45:33 -0700730 if ((dx || dy) && !reg.isEmpty()) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700731#if VALIDATE_REGIONS
732 validate(reg, "translate (before)");
733#endif
Mathias Agopian20f68782009-05-11 00:03:41 -0700734 size_t count = reg.mStorage.size();
735 Rect* rects = reg.mStorage.editArray();
736 while (count) {
Mathias Agopian6c7f25a2013-05-09 20:37:10 -0700737 rects->offsetBy(dx, dy);
Mathias Agopian20f68782009-05-11 00:03:41 -0700738 rects++;
739 count--;
740 }
741#if VALIDATE_REGIONS
742 validate(reg, "translate (after)");
743#endif
744 }
745}
746
747void Region::translate(Region& dst, const Region& reg, int dx, int dy)
748{
749 dst = reg;
750 translate(dst, dx, dy);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800751}
752
753// ----------------------------------------------------------------------------
754
Mathias Agopiane1424282013-07-29 21:24:40 -0700755size_t Region::getFlattenedSize() const {
Mathias Agopian3ab68552012-08-31 14:31:40 -0700756 return mStorage.size() * sizeof(Rect);
Mathias Agopian8683fca2012-08-12 19:37:16 -0700757}
758
Mathias Agopiane1424282013-07-29 21:24:40 -0700759status_t Region::flatten(void* buffer, size_t size) const {
Mathias Agopian068d47f2012-09-11 18:56:23 -0700760#if VALIDATE_REGIONS
761 validate(*this, "Region::flatten");
762#endif
Mathias Agopiane1424282013-07-29 21:24:40 -0700763 if (size < mStorage.size() * sizeof(Rect)) {
764 return NO_MEMORY;
765 }
Mathias Agopian8683fca2012-08-12 19:37:16 -0700766 Rect* rects = reinterpret_cast<Rect*>(buffer);
Mathias Agopian8683fca2012-08-12 19:37:16 -0700767 memcpy(rects, mStorage.array(), mStorage.size() * sizeof(Rect));
768 return NO_ERROR;
769}
770
771status_t Region::unflatten(void const* buffer, size_t size) {
Mathias Agopian068d47f2012-09-11 18:56:23 -0700772 Region result;
Mathias Agopian8683fca2012-08-12 19:37:16 -0700773 if (size >= sizeof(Rect)) {
774 Rect const* rects = reinterpret_cast<Rect const*>(buffer);
Mathias Agopian8683fca2012-08-12 19:37:16 -0700775 size_t count = size / sizeof(Rect);
776 if (count > 0) {
Mathias Agopian068d47f2012-09-11 18:56:23 -0700777 result.mStorage.clear();
778 ssize_t err = result.mStorage.insertAt(0, count);
Mathias Agopian8683fca2012-08-12 19:37:16 -0700779 if (err < 0) {
780 return status_t(err);
781 }
Mathias Agopian068d47f2012-09-11 18:56:23 -0700782 memcpy(result.mStorage.editArray(), rects, count*sizeof(Rect));
Mathias Agopianb6121422010-02-17 20:22:26 -0800783 }
Mathias Agopian20f68782009-05-11 00:03:41 -0700784 }
Mathias Agopian3ab68552012-08-31 14:31:40 -0700785#if VALIDATE_REGIONS
Mathias Agopian068d47f2012-09-11 18:56:23 -0700786 validate(result, "Region::unflatten");
Mathias Agopian3ab68552012-08-31 14:31:40 -0700787#endif
Mathias Agopian068d47f2012-09-11 18:56:23 -0700788
789 if (!result.validate(result, "Region::unflatten", true)) {
790 ALOGE("Region::unflatten() failed, invalid region");
791 return BAD_VALUE;
792 }
793 mStorage = result.mStorage;
Mathias Agopian8683fca2012-08-12 19:37:16 -0700794 return NO_ERROR;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800795}
796
Mathias Agopian20f68782009-05-11 00:03:41 -0700797// ----------------------------------------------------------------------------
798
799Region::const_iterator Region::begin() const {
Mathias Agopian3ab68552012-08-31 14:31:40 -0700800 return mStorage.array();
Mathias Agopian20f68782009-05-11 00:03:41 -0700801}
802
803Region::const_iterator Region::end() const {
Mathias Agopian3ab68552012-08-31 14:31:40 -0700804 size_t numRects = isRect() ? 1 : mStorage.size() - 1;
805 return mStorage.array() + numRects;
Mathias Agopian20f68782009-05-11 00:03:41 -0700806}
807
808Rect const* Region::getArray(size_t* count) const {
Dan Stozad3182402014-11-17 12:03:59 -0800809 if (count) *count = static_cast<size_t>(end() - begin());
810 return begin();
Mathias Agopian20f68782009-05-11 00:03:41 -0700811}
812
Mathias Agopian2401ead2012-08-31 15:41:24 -0700813SharedBuffer const* Region::getSharedBuffer(size_t* count) const {
814 // We can get to the SharedBuffer of a Vector<Rect> because Rect has
815 // a trivial destructor.
816 SharedBuffer const* sb = SharedBuffer::bufferFromData(mStorage.array());
817 if (count) {
818 size_t numRects = isRect() ? 1 : mStorage.size() - 1;
819 count[0] = numRects;
820 }
821 sb->acquire();
822 return sb;
823}
824
Mathias Agopian20f68782009-05-11 00:03:41 -0700825// ----------------------------------------------------------------------------
826
Dan Stozad3182402014-11-17 12:03:59 -0800827void Region::dump(String8& out, const char* what, uint32_t /* flags */) const
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800828{
Mathias Agopian20f68782009-05-11 00:03:41 -0700829 const_iterator head = begin();
830 const_iterator const tail = end();
831
Dan Stozad3182402014-11-17 12:03:59 -0800832 out.appendFormat(" Region %s (this=%p, count=%" PRIdPTR ")\n",
833 what, this, tail - head);
Mathias Agopian20f68782009-05-11 00:03:41 -0700834 while (head != tail) {
Dan Stozad3182402014-11-17 12:03:59 -0800835 out.appendFormat(" [%3d, %3d, %3d, %3d]\n", head->left, head->top,
836 head->right, head->bottom);
837 ++head;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800838 }
839}
840
Dan Stozad3182402014-11-17 12:03:59 -0800841void Region::dump(const char* what, uint32_t /* flags */) const
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800842{
Mathias Agopian20f68782009-05-11 00:03:41 -0700843 const_iterator head = begin();
844 const_iterator const tail = end();
Mark Salyzyn92dc3fc2014-03-12 13:12:44 -0700845 ALOGD(" Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail-head);
Mathias Agopian20f68782009-05-11 00:03:41 -0700846 while (head != tail) {
Steve Block9d453682011-12-20 16:23:08 +0000847 ALOGD(" [%3d, %3d, %3d, %3d]\n",
Mathias Agopian20f68782009-05-11 00:03:41 -0700848 head->left, head->top, head->right, head->bottom);
849 head++;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800850 }
851}
852
853// ----------------------------------------------------------------------------
854
855}; // namespace android