blob: e5abcf5c84d7a3d90df442d31e26c81a0fe5f168 [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
Mathias Agopian72b0ffe2009-07-06 18:07:26 -070019#include <limits.h>
20
Mathias Agopian20f68782009-05-11 00:03:41 -070021#include <utils/Log.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080022#include <utils/String8.h>
Mathias Agopian068d47f2012-09-11 18:56:23 -070023#include <utils/CallStack.h>
Mathias Agopian20f68782009-05-11 00:03:41 -070024
25#include <ui/Rect.h>
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080026#include <ui/Region.h>
Mathias Agopian20f68782009-05-11 00:03:41 -070027#include <ui/Point.h>
28
29#include <private/ui/RegionHelper.h>
30
31// ----------------------------------------------------------------------------
32#define VALIDATE_REGIONS (false)
33#define VALIDATE_WITH_CORECG (false)
34// ----------------------------------------------------------------------------
35
36#if VALIDATE_WITH_CORECG
37#include <core/SkRegion.h>
38#endif
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080039
40namespace android {
Mathias Agopian20f68782009-05-11 00:03:41 -070041// ----------------------------------------------------------------------------
42
43enum {
44 op_nand = region_operator<Rect>::op_nand,
45 op_and = region_operator<Rect>::op_and,
46 op_or = region_operator<Rect>::op_or,
47 op_xor = region_operator<Rect>::op_xor
48};
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080049
Chris Craik3e010f32013-02-25 19:12:47 -080050enum {
51 direction_LTR,
52 direction_RTL
53};
54
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080055// ----------------------------------------------------------------------------
56
Mathias Agopian3ab68552012-08-31 14:31:40 -070057Region::Region() {
58 mStorage.add(Rect(0,0));
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080059}
60
61Region::Region(const Region& rhs)
Mathias Agopian3ab68552012-08-31 14:31:40 -070062 : mStorage(rhs.mStorage)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080063{
Mathias Agopiand0b55c02011-03-16 23:18:07 -070064#if VALIDATE_REGIONS
65 validate(rhs, "rhs copy-ctor");
66#endif
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080067}
68
Mathias Agopian3ab68552012-08-31 14:31:40 -070069Region::Region(const Rect& rhs) {
70 mStorage.add(rhs);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -080071}
72
73Region::~Region()
74{
75}
76
Chris Craik3e010f32013-02-25 19:12:47 -080077/**
78 * Copy rects from the src vector into the dst vector, resolving vertical T-Junctions along the way
79 *
80 * First pass through, divideSpanRTL will be set because the 'previous span' (indexing into the dst
81 * vector) will be reversed. Each rectangle in the original list, starting from the bottom, will be
82 * compared with the span directly below, and subdivided as needed to resolve T-junctions.
83 *
84 * The resulting temporary vector will be a completely reversed copy of the original, without any
85 * bottom-up T-junctions.
86 *
87 * Second pass through, divideSpanRTL will be false since the previous span will index into the
88 * final, correctly ordered region buffer. Each rectangle will be compared with the span directly
89 * above it, and subdivided to resolve any remaining T-junctions.
90 */
91static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end,
92 Vector<Rect>& dst, int spanDirection) {
93 dst.clear();
94
95 const Rect* current = end - 1;
96 int lastTop = current->top;
97
98 // add first span immediately
99 do {
100 dst.add(*current);
101 current--;
102 } while (current->top == lastTop && current >= begin);
103
104 unsigned int beginLastSpan = -1;
105 unsigned int endLastSpan = -1;
106 int top = -1;
107 int bottom = -1;
108
109 // for all other spans, split if a t-junction exists in the span directly above
110 while (current >= begin) {
111 if (current->top != (current + 1)->top) {
112 // new span
113 if ((spanDirection == direction_RTL && current->bottom != (current + 1)->top) ||
114 (spanDirection == direction_LTR && current->top != (current + 1)->bottom)) {
115 // previous span not directly adjacent, don't check for T junctions
116 beginLastSpan = INT_MAX;
117 } else {
118 beginLastSpan = endLastSpan + 1;
119 }
120 endLastSpan = dst.size() - 1;
121
122 top = current->top;
123 bottom = current->bottom;
124 }
125 int left = current->left;
126 int right = current->right;
127
128 for (unsigned int prevIndex = beginLastSpan; prevIndex <= endLastSpan; prevIndex++) {
129 const Rect* prev = &dst[prevIndex];
130 if (spanDirection == direction_RTL) {
131 // iterating over previous span RTL, quit if it's too far left
132 if (prev->right <= left) break;
133
134 if (prev->right > left && prev->right < right) {
135 dst.add(Rect(prev->right, top, right, bottom));
136 right = prev->right;
137 }
138
139 if (prev->left > left && prev->left < right) {
140 dst.add(Rect(prev->left, top, right, bottom));
141 right = prev->left;
142 }
143
144 // if an entry in the previous span is too far right, nothing further left in the
145 // current span will need it
146 if (prev->left >= right) {
147 beginLastSpan = prevIndex;
148 }
149 } else {
150 // iterating over previous span LTR, quit if it's too far right
151 if (prev->left >= right) break;
152
153 if (prev->left > left && prev->left < right) {
154 dst.add(Rect(left, top, prev->left, bottom));
155 left = prev->left;
156 }
157
158 if (prev->right > left && prev->right < right) {
159 dst.add(Rect(left, top, prev->right, bottom));
160 left = prev->right;
161 }
162 // if an entry in the previous span is too far left, nothing further right in the
163 // current span will need it
164 if (prev->right <= left) {
165 beginLastSpan = prevIndex;
166 }
167 }
168 }
169
170 if (left < right) {
171 dst.add(Rect(left, top, right, bottom));
172 }
173
174 current--;
175 }
176}
177
178/**
179 * Creates a new region with the same data as the argument, but divides rectangles as necessary to
180 * remove T-Junctions
181 *
182 * Note: the output will not necessarily be a very efficient representation of the region, since it
183 * may be that a triangle-based approach would generate significantly simpler geometry
184 */
185Region Region::createTJunctionFreeRegion(const Region& r) {
186 if (r.isEmpty()) return r;
187 if (r.isRect()) return r;
188
189 Vector<Rect> reversed;
190 reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL);
191
192 Region outputRegion;
193 reverseRectsResolvingJunctions(reversed.begin(), reversed.end(),
194 outputRegion.mStorage, direction_LTR);
195 outputRegion.mStorage.add(r.getBounds()); // to make region valid, mStorage must end with bounds
196
197#if VALIDATE_REGIONS
198 validate(outputRegion, "T-Junction free region");
199#endif
200
201 return outputRegion;
202}
203
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800204Region& Region::operator = (const Region& rhs)
205{
Mathias Agopian20f68782009-05-11 00:03:41 -0700206#if VALIDATE_REGIONS
Mathias Agopiand0b55c02011-03-16 23:18:07 -0700207 validate(*this, "this->operator=");
208 validate(rhs, "rhs.operator=");
Mathias Agopian20f68782009-05-11 00:03:41 -0700209#endif
Mathias Agopian20f68782009-05-11 00:03:41 -0700210 mStorage = rhs.mStorage;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800211 return *this;
212}
213
Mathias Agopian9f961452009-06-29 18:46:37 -0700214Region& Region::makeBoundsSelf()
215{
Mathias Agopian3ab68552012-08-31 14:31:40 -0700216 if (mStorage.size() >= 2) {
217 const Rect bounds(getBounds());
218 mStorage.clear();
219 mStorage.add(bounds);
220 }
Mathias Agopian9f961452009-06-29 18:46:37 -0700221 return *this;
222}
223
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800224void Region::clear()
225{
Mathias Agopian20f68782009-05-11 00:03:41 -0700226 mStorage.clear();
Mathias Agopian3ab68552012-08-31 14:31:40 -0700227 mStorage.add(Rect(0,0));
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800228}
229
230void Region::set(const Rect& r)
231{
Mathias Agopian20f68782009-05-11 00:03:41 -0700232 mStorage.clear();
Mathias Agopian3ab68552012-08-31 14:31:40 -0700233 mStorage.add(r);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800234}
235
Mathias Agopian0926f502009-05-04 14:17:04 -0700236void Region::set(uint32_t w, uint32_t h)
237{
Mathias Agopian20f68782009-05-11 00:03:41 -0700238 mStorage.clear();
Mathias Agopian3ab68552012-08-31 14:31:40 -0700239 mStorage.add(Rect(w,h));
Mathias Agopian0926f502009-05-04 14:17:04 -0700240}
241
Mathias Agopian2ca79392013-04-02 18:30:32 -0700242bool Region::isTriviallyEqual(const Region& region) const {
243 return begin() == region.begin();
244}
245
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800246// ----------------------------------------------------------------------------
247
Mathias Agopian20f68782009-05-11 00:03:41 -0700248void Region::addRectUnchecked(int l, int t, int r, int b)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800249{
Mathias Agopian3ab68552012-08-31 14:31:40 -0700250 Rect rect(l,t,r,b);
251 size_t where = mStorage.size() - 1;
252 mStorage.insertAt(rect, where, 1);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800253}
254
Mathias Agopian20f68782009-05-11 00:03:41 -0700255// ----------------------------------------------------------------------------
256
257Region& Region::orSelf(const Rect& r) {
258 return operationSelf(r, op_or);
259}
Romain Guyb8a2e982012-02-07 17:04:34 -0800260Region& Region::xorSelf(const Rect& r) {
261 return operationSelf(r, op_xor);
262}
Mathias Agopian20f68782009-05-11 00:03:41 -0700263Region& Region::andSelf(const Rect& r) {
264 return operationSelf(r, op_and);
265}
266Region& Region::subtractSelf(const Rect& r) {
267 return operationSelf(r, op_nand);
268}
269Region& Region::operationSelf(const Rect& r, int op) {
270 Region lhs(*this);
271 boolean_operation(op, *this, lhs, r);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800272 return *this;
273}
274
275// ----------------------------------------------------------------------------
276
277Region& Region::orSelf(const Region& rhs) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700278 return operationSelf(rhs, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800279}
Romain Guyb8a2e982012-02-07 17:04:34 -0800280Region& Region::xorSelf(const Region& rhs) {
281 return operationSelf(rhs, op_xor);
282}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800283Region& Region::andSelf(const Region& rhs) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700284 return operationSelf(rhs, op_and);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800285}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800286Region& Region::subtractSelf(const Region& rhs) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700287 return operationSelf(rhs, op_nand);
288}
289Region& Region::operationSelf(const Region& rhs, int op) {
290 Region lhs(*this);
291 boolean_operation(op, *this, lhs, rhs);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800292 return *this;
293}
294
295Region& Region::translateSelf(int x, int y) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700296 if (x|y) translate(*this, x, y);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800297 return *this;
298}
299
Mathias Agopian20f68782009-05-11 00:03:41 -0700300// ----------------------------------------------------------------------------
301
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700302const Region Region::merge(const Rect& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700303 return operation(rhs, op_or);
304}
Romain Guyb8a2e982012-02-07 17:04:34 -0800305const Region Region::mergeExclusive(const Rect& rhs) const {
306 return operation(rhs, op_xor);
307}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700308const Region Region::intersect(const Rect& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700309 return operation(rhs, op_and);
310}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700311const Region Region::subtract(const Rect& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700312 return operation(rhs, op_nand);
313}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700314const Region Region::operation(const Rect& rhs, int op) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700315 Region result;
316 boolean_operation(op, result, *this, rhs);
317 return result;
318}
319
320// ----------------------------------------------------------------------------
321
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700322const Region Region::merge(const Region& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700323 return operation(rhs, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800324}
Romain Guyb8a2e982012-02-07 17:04:34 -0800325const Region Region::mergeExclusive(const Region& rhs) const {
326 return operation(rhs, op_xor);
327}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700328const Region Region::intersect(const Region& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700329 return operation(rhs, op_and);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800330}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700331const Region Region::subtract(const Region& rhs) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700332 return operation(rhs, op_nand);
333}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700334const Region Region::operation(const Region& rhs, int op) const {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800335 Region result;
Mathias Agopian20f68782009-05-11 00:03:41 -0700336 boolean_operation(op, result, *this, rhs);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800337 return result;
338}
339
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700340const Region Region::translate(int x, int y) const {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800341 Region result;
Mathias Agopian20f68782009-05-11 00:03:41 -0700342 translate(result, *this, x, y);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800343 return result;
344}
345
346// ----------------------------------------------------------------------------
347
348Region& Region::orSelf(const Region& rhs, int dx, int dy) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700349 return operationSelf(rhs, dx, dy, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800350}
Romain Guyb8a2e982012-02-07 17:04:34 -0800351Region& Region::xorSelf(const Region& rhs, int dx, int dy) {
352 return operationSelf(rhs, dx, dy, op_xor);
353}
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800354Region& Region::andSelf(const Region& rhs, int dx, int dy) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700355 return operationSelf(rhs, dx, dy, op_and);
356}
357Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
358 return operationSelf(rhs, dx, dy, op_nand);
359}
360Region& Region::operationSelf(const Region& rhs, int dx, int dy, int op) {
361 Region lhs(*this);
362 boolean_operation(op, *this, lhs, rhs, dx, dy);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800363 return *this;
364}
365
Mathias Agopian20f68782009-05-11 00:03:41 -0700366// ----------------------------------------------------------------------------
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800367
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700368const Region Region::merge(const Region& rhs, int dx, int dy) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700369 return operation(rhs, dx, dy, op_or);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800370}
Romain Guyb8a2e982012-02-07 17:04:34 -0800371const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const {
372 return operation(rhs, dx, dy, op_xor);
373}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700374const Region Region::intersect(const Region& rhs, int dx, int dy) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700375 return operation(rhs, dx, dy, op_and);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800376}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700377const Region Region::subtract(const Region& rhs, int dx, int dy) const {
Mathias Agopian20f68782009-05-11 00:03:41 -0700378 return operation(rhs, dx, dy, op_nand);
379}
Mathias Agopianbed9dd12009-05-27 17:01:58 -0700380const Region Region::operation(const Region& rhs, int dx, int dy, int op) const {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800381 Region result;
Mathias Agopian20f68782009-05-11 00:03:41 -0700382 boolean_operation(op, result, *this, rhs, dx, dy);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800383 return result;
384}
385
386// ----------------------------------------------------------------------------
387
Mathias Agopian20f68782009-05-11 00:03:41 -0700388// This is our region rasterizer, which merges rects and spans together
389// to obtain an optimal region.
390class Region::rasterizer : public region_operator<Rect>::region_rasterizer
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800391{
Mathias Agopian3ab68552012-08-31 14:31:40 -0700392 Rect bounds;
Mathias Agopian20f68782009-05-11 00:03:41 -0700393 Vector<Rect>& storage;
394 Rect* head;
395 Rect* tail;
396 Vector<Rect> span;
397 Rect* cur;
398public:
399 rasterizer(Region& reg)
Mathias Agopian3ab68552012-08-31 14:31:40 -0700400 : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() {
Mathias Agopian20f68782009-05-11 00:03:41 -0700401 storage.clear();
402 }
403
404 ~rasterizer() {
405 if (span.size()) {
406 flushSpan();
407 }
408 if (storage.size()) {
409 bounds.top = storage.itemAt(0).top;
410 bounds.bottom = storage.top().bottom;
411 if (storage.size() == 1) {
412 storage.clear();
413 }
414 } else {
415 bounds.left = 0;
416 bounds.right = 0;
417 }
Mathias Agopian3ab68552012-08-31 14:31:40 -0700418 storage.add(bounds);
Mathias Agopian20f68782009-05-11 00:03:41 -0700419 }
420
421 virtual void operator()(const Rect& rect) {
Steve Block9d453682011-12-20 16:23:08 +0000422 //ALOGD(">>> %3d, %3d, %3d, %3d",
Mathias Agopian20f68782009-05-11 00:03:41 -0700423 // rect.left, rect.top, rect.right, rect.bottom);
424 if (span.size()) {
425 if (cur->top != rect.top) {
426 flushSpan();
427 } else if (cur->right == rect.left) {
428 cur->right = rect.right;
429 return;
430 }
431 }
432 span.add(rect);
433 cur = span.editArray() + (span.size() - 1);
434 }
435private:
436 template<typename T>
437 static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; }
438 template<typename T>
439 static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; }
440 void flushSpan() {
441 bool merge = false;
442 if (tail-head == ssize_t(span.size())) {
Romain Guyb8016242010-10-27 18:57:51 -0700443 Rect const* p = span.editArray();
Mathias Agopian20f68782009-05-11 00:03:41 -0700444 Rect const* q = head;
445 if (p->top == q->bottom) {
446 merge = true;
447 while (q != tail) {
448 if ((p->left != q->left) || (p->right != q->right)) {
449 merge = false;
450 break;
451 }
452 p++, q++;
453 }
454 }
455 }
456 if (merge) {
457 const int bottom = span[0].bottom;
458 Rect* r = head;
459 while (r != tail) {
460 r->bottom = bottom;
461 r++;
462 }
463 } else {
464 bounds.left = min(span.itemAt(0).left, bounds.left);
465 bounds.right = max(span.top().right, bounds.right);
466 storage.appendVector(span);
467 tail = storage.editArray() + storage.size();
468 head = tail - span.size();
469 }
470 span.clear();
471 }
472};
473
Mathias Agopian068d47f2012-09-11 18:56:23 -0700474bool Region::validate(const Region& reg, const char* name, bool silent)
Mathias Agopian20f68782009-05-11 00:03:41 -0700475{
476 bool result = true;
477 const_iterator cur = reg.begin();
478 const_iterator const tail = reg.end();
Mathias Agopian068d47f2012-09-11 18:56:23 -0700479 const_iterator prev = cur;
Mathias Agopian20f68782009-05-11 00:03:41 -0700480 Rect b(*prev);
481 while (cur != tail) {
Mathias Agopian068d47f2012-09-11 18:56:23 -0700482 if (cur->isValid() == false) {
483 ALOGE_IF(!silent, "%s: region contains an invalid Rect", name);
484 result = false;
485 }
486 if (cur->right > region_operator<Rect>::max_value) {
487 ALOGE_IF(!silent, "%s: rect->right > max_value", name);
488 result = false;
489 }
490 if (cur->bottom > region_operator<Rect>::max_value) {
491 ALOGE_IF(!silent, "%s: rect->right > max_value", name);
492 result = false;
493 }
494 if (prev != cur) {
495 b.left = b.left < cur->left ? b.left : cur->left;
496 b.top = b.top < cur->top ? b.top : cur->top;
497 b.right = b.right > cur->right ? b.right : cur->right;
498 b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
499 if ((*prev < *cur) == false) {
500 ALOGE_IF(!silent, "%s: region's Rects not sorted", name);
Mathias Agopian20f68782009-05-11 00:03:41 -0700501 result = false;
Mathias Agopian068d47f2012-09-11 18:56:23 -0700502 }
503 if (cur->top == prev->top) {
504 if (cur->bottom != prev->bottom) {
505 ALOGE_IF(!silent, "%s: invalid span %p", name, cur);
506 result = false;
507 } else if (cur->left < prev->right) {
508 ALOGE_IF(!silent,
509 "%s: spans overlap horizontally prev=%p, cur=%p",
510 name, prev, cur);
511 result = false;
512 }
513 } else if (cur->top < prev->bottom) {
514 ALOGE_IF(!silent,
515 "%s: spans overlap vertically prev=%p, cur=%p",
Mathias Agopian20f68782009-05-11 00:03:41 -0700516 name, prev, cur);
517 result = false;
518 }
Mathias Agopian068d47f2012-09-11 18:56:23 -0700519 prev = cur;
Mathias Agopian20f68782009-05-11 00:03:41 -0700520 }
Mathias Agopian20f68782009-05-11 00:03:41 -0700521 cur++;
522 }
523 if (b != reg.getBounds()) {
524 result = false;
Mathias Agopian068d47f2012-09-11 18:56:23 -0700525 ALOGE_IF(!silent,
526 "%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
Mathias Agopian20f68782009-05-11 00:03:41 -0700527 b.left, b.top, b.right, b.bottom,
528 reg.getBounds().left, reg.getBounds().top,
529 reg.getBounds().right, reg.getBounds().bottom);
530 }
Mathias Agopian3ab68552012-08-31 14:31:40 -0700531 if (reg.mStorage.size() == 2) {
Mathias Agopian068d47f2012-09-11 18:56:23 -0700532 result = false;
533 ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name);
Mathias Agopian3ab68552012-08-31 14:31:40 -0700534 }
Mathias Agopian068d47f2012-09-11 18:56:23 -0700535 if (result == false && !silent) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700536 reg.dump(name);
Mathias Agopiancab25d62013-03-21 17:12:40 -0700537 CallStack stack(LOG_TAG);
Mathias Agopian20f68782009-05-11 00:03:41 -0700538 }
539 return result;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800540}
541
Mathias Agopian20f68782009-05-11 00:03:41 -0700542void Region::boolean_operation(int op, Region& dst,
543 const Region& lhs,
544 const Region& rhs, int dx, int dy)
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800545{
Mathias Agopiand0b55c02011-03-16 23:18:07 -0700546#if VALIDATE_REGIONS
547 validate(lhs, "boolean_operation (before): lhs");
548 validate(rhs, "boolean_operation (before): rhs");
549 validate(dst, "boolean_operation (before): dst");
550#endif
551
Mathias Agopian20f68782009-05-11 00:03:41 -0700552 size_t lhs_count;
553 Rect const * const lhs_rects = lhs.getArray(&lhs_count);
554
555 size_t rhs_count;
556 Rect const * const rhs_rects = rhs.getArray(&rhs_count);
557
558 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
559 region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy);
560 region_operator<Rect> operation(op, lhs_region, rhs_region);
561 { // scope for rasterizer (dtor has side effects)
562 rasterizer r(dst);
563 operation(r);
564 }
565
566#if VALIDATE_REGIONS
567 validate(lhs, "boolean_operation: lhs");
568 validate(rhs, "boolean_operation: rhs");
569 validate(dst, "boolean_operation: dst");
570#endif
571
572#if VALIDATE_WITH_CORECG
573 SkRegion sk_lhs;
574 SkRegion sk_rhs;
575 SkRegion sk_dst;
576
577 for (size_t i=0 ; i<lhs_count ; i++)
578 sk_lhs.op(
579 lhs_rects[i].left + dx,
580 lhs_rects[i].top + dy,
581 lhs_rects[i].right + dx,
582 lhs_rects[i].bottom + dy,
583 SkRegion::kUnion_Op);
584
585 for (size_t i=0 ; i<rhs_count ; i++)
586 sk_rhs.op(
587 rhs_rects[i].left + dx,
588 rhs_rects[i].top + dy,
589 rhs_rects[i].right + dx,
590 rhs_rects[i].bottom + dy,
591 SkRegion::kUnion_Op);
592
593 const char* name = "---";
594 SkRegion::Op sk_op;
595 switch (op) {
596 case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
Romain Guyb8a2e982012-02-07 17:04:34 -0800597 case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break;
Mathias Agopian20f68782009-05-11 00:03:41 -0700598 case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
599 case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
600 }
601 sk_dst.op(sk_lhs, sk_rhs, sk_op);
602
603 if (sk_dst.isEmpty() && dst.isEmpty())
604 return;
605
606 bool same = true;
607 Region::const_iterator head = dst.begin();
608 Region::const_iterator const tail = dst.end();
609 SkRegion::Iterator it(sk_dst);
610 while (!it.done()) {
611 if (head != tail) {
612 if (
613 head->left != it.rect().fLeft ||
614 head->top != it.rect().fTop ||
615 head->right != it.rect().fRight ||
616 head->bottom != it.rect().fBottom
617 ) {
618 same = false;
619 break;
620 }
621 } else {
622 same = false;
623 break;
624 }
625 head++;
626 it.next();
627 }
628
629 if (head != tail) {
630 same = false;
631 }
632
633 if(!same) {
Steve Block9d453682011-12-20 16:23:08 +0000634 ALOGD("---\nregion boolean %s failed", name);
Mathias Agopian20f68782009-05-11 00:03:41 -0700635 lhs.dump("lhs");
636 rhs.dump("rhs");
637 dst.dump("dst");
Steve Block9d453682011-12-20 16:23:08 +0000638 ALOGD("should be");
Mathias Agopian20f68782009-05-11 00:03:41 -0700639 SkRegion::Iterator it(sk_dst);
640 while (!it.done()) {
Steve Block9d453682011-12-20 16:23:08 +0000641 ALOGD(" [%3d, %3d, %3d, %3d]",
Mathias Agopian20f68782009-05-11 00:03:41 -0700642 it.rect().fLeft,
643 it.rect().fTop,
644 it.rect().fRight,
645 it.rect().fBottom);
646 it.next();
647 }
648 }
649#endif
650}
651
652void Region::boolean_operation(int op, Region& dst,
653 const Region& lhs,
654 const Rect& rhs, int dx, int dy)
655{
Mathias Agopian04504522011-09-19 16:12:08 -0700656 if (!rhs.isValid()) {
Steve Blocke6f43dd2012-01-06 19:20:56 +0000657 ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}",
Mathias Agopian04504522011-09-19 16:12:08 -0700658 op, rhs.left, rhs.top, rhs.right, rhs.bottom);
Mathias Agopian0857c8f2011-09-26 15:58:20 -0700659 return;
Mathias Agopian04504522011-09-19 16:12:08 -0700660 }
661
Mathias Agopian20f68782009-05-11 00:03:41 -0700662#if VALIDATE_WITH_CORECG || VALIDATE_REGIONS
663 boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
664#else
665 size_t lhs_count;
666 Rect const * const lhs_rects = lhs.getArray(&lhs_count);
667
668 region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
669 region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy);
670 region_operator<Rect> operation(op, lhs_region, rhs_region);
671 { // scope for rasterizer (dtor has side effects)
672 rasterizer r(dst);
673 operation(r);
674 }
675
676#endif
677}
678
679void Region::boolean_operation(int op, Region& dst,
680 const Region& lhs, const Region& rhs)
681{
682 boolean_operation(op, dst, lhs, rhs, 0, 0);
683}
684
685void Region::boolean_operation(int op, Region& dst,
686 const Region& lhs, const Rect& rhs)
687{
688 boolean_operation(op, dst, lhs, rhs, 0, 0);
689}
690
691void Region::translate(Region& reg, int dx, int dy)
692{
Mathias Agopian4c0a1702012-08-31 12:45:33 -0700693 if ((dx || dy) && !reg.isEmpty()) {
Mathias Agopian20f68782009-05-11 00:03:41 -0700694#if VALIDATE_REGIONS
695 validate(reg, "translate (before)");
696#endif
Mathias Agopian20f68782009-05-11 00:03:41 -0700697 size_t count = reg.mStorage.size();
698 Rect* rects = reg.mStorage.editArray();
699 while (count) {
Mathias Agopian6c7f25a2013-05-09 20:37:10 -0700700 rects->offsetBy(dx, dy);
Mathias Agopian20f68782009-05-11 00:03:41 -0700701 rects++;
702 count--;
703 }
704#if VALIDATE_REGIONS
705 validate(reg, "translate (after)");
706#endif
707 }
708}
709
710void Region::translate(Region& dst, const Region& reg, int dx, int dy)
711{
712 dst = reg;
713 translate(dst, dx, dy);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800714}
715
716// ----------------------------------------------------------------------------
717
Mathias Agopiane1424282013-07-29 21:24:40 -0700718size_t Region::getFlattenedSize() const {
Mathias Agopian3ab68552012-08-31 14:31:40 -0700719 return mStorage.size() * sizeof(Rect);
Mathias Agopian8683fca2012-08-12 19:37:16 -0700720}
721
Mathias Agopiane1424282013-07-29 21:24:40 -0700722status_t Region::flatten(void* buffer, size_t size) const {
Mathias Agopian068d47f2012-09-11 18:56:23 -0700723#if VALIDATE_REGIONS
724 validate(*this, "Region::flatten");
725#endif
Mathias Agopiane1424282013-07-29 21:24:40 -0700726 if (size < mStorage.size() * sizeof(Rect)) {
727 return NO_MEMORY;
728 }
Mathias Agopian8683fca2012-08-12 19:37:16 -0700729 Rect* rects = reinterpret_cast<Rect*>(buffer);
Mathias Agopian8683fca2012-08-12 19:37:16 -0700730 memcpy(rects, mStorage.array(), mStorage.size() * sizeof(Rect));
731 return NO_ERROR;
732}
733
734status_t Region::unflatten(void const* buffer, size_t size) {
Mathias Agopian068d47f2012-09-11 18:56:23 -0700735 Region result;
Mathias Agopian8683fca2012-08-12 19:37:16 -0700736 if (size >= sizeof(Rect)) {
737 Rect const* rects = reinterpret_cast<Rect const*>(buffer);
Mathias Agopian8683fca2012-08-12 19:37:16 -0700738 size_t count = size / sizeof(Rect);
739 if (count > 0) {
Mathias Agopian068d47f2012-09-11 18:56:23 -0700740 result.mStorage.clear();
741 ssize_t err = result.mStorage.insertAt(0, count);
Mathias Agopian8683fca2012-08-12 19:37:16 -0700742 if (err < 0) {
743 return status_t(err);
744 }
Mathias Agopian068d47f2012-09-11 18:56:23 -0700745 memcpy(result.mStorage.editArray(), rects, count*sizeof(Rect));
Mathias Agopianb6121422010-02-17 20:22:26 -0800746 }
Mathias Agopian20f68782009-05-11 00:03:41 -0700747 }
Mathias Agopian3ab68552012-08-31 14:31:40 -0700748#if VALIDATE_REGIONS
Mathias Agopian068d47f2012-09-11 18:56:23 -0700749 validate(result, "Region::unflatten");
Mathias Agopian3ab68552012-08-31 14:31:40 -0700750#endif
Mathias Agopian068d47f2012-09-11 18:56:23 -0700751
752 if (!result.validate(result, "Region::unflatten", true)) {
753 ALOGE("Region::unflatten() failed, invalid region");
754 return BAD_VALUE;
755 }
756 mStorage = result.mStorage;
Mathias Agopian8683fca2012-08-12 19:37:16 -0700757 return NO_ERROR;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800758}
759
Mathias Agopian20f68782009-05-11 00:03:41 -0700760// ----------------------------------------------------------------------------
761
762Region::const_iterator Region::begin() const {
Mathias Agopian3ab68552012-08-31 14:31:40 -0700763 return mStorage.array();
Mathias Agopian20f68782009-05-11 00:03:41 -0700764}
765
766Region::const_iterator Region::end() const {
Mathias Agopian3ab68552012-08-31 14:31:40 -0700767 size_t numRects = isRect() ? 1 : mStorage.size() - 1;
768 return mStorage.array() + numRects;
Mathias Agopian20f68782009-05-11 00:03:41 -0700769}
770
771Rect const* Region::getArray(size_t* count) const {
772 const_iterator const b(begin());
773 const_iterator const e(end());
774 if (count) *count = e-b;
775 return b;
776}
777
Mathias Agopian2401ead2012-08-31 15:41:24 -0700778SharedBuffer const* Region::getSharedBuffer(size_t* count) const {
779 // We can get to the SharedBuffer of a Vector<Rect> because Rect has
780 // a trivial destructor.
781 SharedBuffer const* sb = SharedBuffer::bufferFromData(mStorage.array());
782 if (count) {
783 size_t numRects = isRect() ? 1 : mStorage.size() - 1;
784 count[0] = numRects;
785 }
786 sb->acquire();
787 return sb;
788}
789
Mathias Agopian20f68782009-05-11 00:03:41 -0700790// ----------------------------------------------------------------------------
791
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800792void Region::dump(String8& out, const char* what, uint32_t flags) const
793{
794 (void)flags;
Mathias Agopian20f68782009-05-11 00:03:41 -0700795 const_iterator head = begin();
796 const_iterator const tail = end();
797
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800798 size_t SIZE = 256;
799 char buffer[SIZE];
Mathias Agopian20f68782009-05-11 00:03:41 -0700800
801 snprintf(buffer, SIZE, " Region %s (this=%p, count=%d)\n",
802 what, this, tail-head);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800803 out.append(buffer);
Mathias Agopian20f68782009-05-11 00:03:41 -0700804 while (head != tail) {
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800805 snprintf(buffer, SIZE, " [%3d, %3d, %3d, %3d]\n",
Mathias Agopian20f68782009-05-11 00:03:41 -0700806 head->left, head->top, head->right, head->bottom);
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800807 out.append(buffer);
Mathias Agopian20f68782009-05-11 00:03:41 -0700808 head++;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800809 }
810}
811
812void Region::dump(const char* what, uint32_t flags) const
813{
814 (void)flags;
Mathias Agopian20f68782009-05-11 00:03:41 -0700815 const_iterator head = begin();
816 const_iterator const tail = end();
Steve Block9d453682011-12-20 16:23:08 +0000817 ALOGD(" Region %s (this=%p, count=%d)\n", what, this, tail-head);
Mathias Agopian20f68782009-05-11 00:03:41 -0700818 while (head != tail) {
Steve Block9d453682011-12-20 16:23:08 +0000819 ALOGD(" [%3d, %3d, %3d, %3d]\n",
Mathias Agopian20f68782009-05-11 00:03:41 -0700820 head->left, head->top, head->right, head->bottom);
821 head++;
The Android Open Source Projectedbf3b62009-03-03 19:31:44 -0800822 }
823}
824
825// ----------------------------------------------------------------------------
826
827}; // namespace android