xref: /aosp_15_r20/frameworks/native/libs/ui/Region.cpp (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright (C) 2007 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #define LOG_TAG "Region"
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #include <inttypes.h>
20*38e8c45fSAndroid Build Coastguard Worker #include <limits.h>
21*38e8c45fSAndroid Build Coastguard Worker 
22*38e8c45fSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
23*38e8c45fSAndroid Build Coastguard Worker 
24*38e8c45fSAndroid Build Coastguard Worker #include <utils/Log.h>
25*38e8c45fSAndroid Build Coastguard Worker 
26*38e8c45fSAndroid Build Coastguard Worker #include <ui/Point.h>
27*38e8c45fSAndroid Build Coastguard Worker #include <ui/Rect.h>
28*38e8c45fSAndroid Build Coastguard Worker #include <ui/Region.h>
29*38e8c45fSAndroid Build Coastguard Worker #include <ui/RegionHelper.h>
30*38e8c45fSAndroid Build Coastguard Worker 
31*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
32*38e8c45fSAndroid Build Coastguard Worker 
33*38e8c45fSAndroid Build Coastguard Worker // ### VALIDATE_REGIONS ###
34*38e8c45fSAndroid Build Coastguard Worker // To enable VALIDATE_REGIONS traces, use the "libui-validate-regions-defaults"
35*38e8c45fSAndroid Build Coastguard Worker // in Android.bp. Do not #define VALIDATE_REGIONS here as it requires extra libs.
36*38e8c45fSAndroid Build Coastguard Worker 
37*38e8c45fSAndroid Build Coastguard Worker #define VALIDATE_WITH_CORECG    (false)
38*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
39*38e8c45fSAndroid Build Coastguard Worker 
40*38e8c45fSAndroid Build Coastguard Worker #if defined(VALIDATE_REGIONS)
41*38e8c45fSAndroid Build Coastguard Worker #include <utils/CallStack.h>
42*38e8c45fSAndroid Build Coastguard Worker #endif
43*38e8c45fSAndroid Build Coastguard Worker 
44*38e8c45fSAndroid Build Coastguard Worker #if VALIDATE_WITH_CORECG
45*38e8c45fSAndroid Build Coastguard Worker #include <core/SkRegion.h>
46*38e8c45fSAndroid Build Coastguard Worker #endif
47*38e8c45fSAndroid Build Coastguard Worker 
48*38e8c45fSAndroid Build Coastguard Worker namespace android {
49*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
50*38e8c45fSAndroid Build Coastguard Worker 
51*38e8c45fSAndroid Build Coastguard Worker using base::StringAppendF;
52*38e8c45fSAndroid Build Coastguard Worker 
53*38e8c45fSAndroid Build Coastguard Worker enum {
54*38e8c45fSAndroid Build Coastguard Worker     op_nand = region_operator<Rect>::op_nand,
55*38e8c45fSAndroid Build Coastguard Worker     op_and  = region_operator<Rect>::op_and,
56*38e8c45fSAndroid Build Coastguard Worker     op_or   = region_operator<Rect>::op_or,
57*38e8c45fSAndroid Build Coastguard Worker     op_xor  = region_operator<Rect>::op_xor
58*38e8c45fSAndroid Build Coastguard Worker };
59*38e8c45fSAndroid Build Coastguard Worker 
60*38e8c45fSAndroid Build Coastguard Worker enum {
61*38e8c45fSAndroid Build Coastguard Worker     direction_LTR,
62*38e8c45fSAndroid Build Coastguard Worker     direction_RTL
63*38e8c45fSAndroid Build Coastguard Worker };
64*38e8c45fSAndroid Build Coastguard Worker 
65*38e8c45fSAndroid Build Coastguard Worker const Region Region::INVALID_REGION(Rect::INVALID_RECT);
66*38e8c45fSAndroid Build Coastguard Worker 
67*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
68*38e8c45fSAndroid Build Coastguard Worker 
Region()69*38e8c45fSAndroid Build Coastguard Worker Region::Region() {
70*38e8c45fSAndroid Build Coastguard Worker     mStorage.push_back(Rect(0, 0));
71*38e8c45fSAndroid Build Coastguard Worker }
72*38e8c45fSAndroid Build Coastguard Worker 
Region(const Region & rhs)73*38e8c45fSAndroid Build Coastguard Worker Region::Region(const Region& rhs)
74*38e8c45fSAndroid Build Coastguard Worker {
75*38e8c45fSAndroid Build Coastguard Worker     mStorage.clear();
76*38e8c45fSAndroid Build Coastguard Worker     mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
77*38e8c45fSAndroid Build Coastguard Worker #if defined(VALIDATE_REGIONS)
78*38e8c45fSAndroid Build Coastguard Worker     validate(rhs, "rhs copy-ctor");
79*38e8c45fSAndroid Build Coastguard Worker #endif
80*38e8c45fSAndroid Build Coastguard Worker }
81*38e8c45fSAndroid Build Coastguard Worker 
Region(const Rect & rhs)82*38e8c45fSAndroid Build Coastguard Worker Region::Region(const Rect& rhs) {
83*38e8c45fSAndroid Build Coastguard Worker     mStorage.push_back(rhs);
84*38e8c45fSAndroid Build Coastguard Worker }
85*38e8c45fSAndroid Build Coastguard Worker 
~Region()86*38e8c45fSAndroid Build Coastguard Worker Region::~Region()
87*38e8c45fSAndroid Build Coastguard Worker {
88*38e8c45fSAndroid Build Coastguard Worker }
89*38e8c45fSAndroid Build Coastguard Worker 
90*38e8c45fSAndroid Build Coastguard Worker /**
91*38e8c45fSAndroid Build Coastguard Worker  * Copy rects from the src vector into the dst vector, resolving vertical T-Junctions along the way
92*38e8c45fSAndroid Build Coastguard Worker  *
93*38e8c45fSAndroid Build Coastguard Worker  * First pass through, divideSpanRTL will be set because the 'previous span' (indexing into the dst
94*38e8c45fSAndroid Build Coastguard Worker  * vector) will be reversed. Each rectangle in the original list, starting from the bottom, will be
95*38e8c45fSAndroid Build Coastguard Worker  * compared with the span directly below, and subdivided as needed to resolve T-junctions.
96*38e8c45fSAndroid Build Coastguard Worker  *
97*38e8c45fSAndroid Build Coastguard Worker  * The resulting temporary vector will be a completely reversed copy of the original, without any
98*38e8c45fSAndroid Build Coastguard Worker  * bottom-up T-junctions.
99*38e8c45fSAndroid Build Coastguard Worker  *
100*38e8c45fSAndroid Build Coastguard Worker  * Second pass through, divideSpanRTL will be false since the previous span will index into the
101*38e8c45fSAndroid Build Coastguard Worker  * final, correctly ordered region buffer. Each rectangle will be compared with the span directly
102*38e8c45fSAndroid Build Coastguard Worker  * above it, and subdivided to resolve any remaining T-junctions.
103*38e8c45fSAndroid Build Coastguard Worker  */
reverseRectsResolvingJunctions(const Rect * begin,const Rect * end,FatVector<Rect> & dst,int spanDirection)104*38e8c45fSAndroid Build Coastguard Worker static void reverseRectsResolvingJunctions(const Rect* begin, const Rect* end, FatVector<Rect>& dst,
105*38e8c45fSAndroid Build Coastguard Worker                                            int spanDirection) {
106*38e8c45fSAndroid Build Coastguard Worker     dst.clear();
107*38e8c45fSAndroid Build Coastguard Worker 
108*38e8c45fSAndroid Build Coastguard Worker     const Rect* current = end - 1;
109*38e8c45fSAndroid Build Coastguard Worker     int lastTop = current->top;
110*38e8c45fSAndroid Build Coastguard Worker 
111*38e8c45fSAndroid Build Coastguard Worker     // add first span immediately
112*38e8c45fSAndroid Build Coastguard Worker     do {
113*38e8c45fSAndroid Build Coastguard Worker         dst.push_back(*current);
114*38e8c45fSAndroid Build Coastguard Worker         current--;
115*38e8c45fSAndroid Build Coastguard Worker     } while (current->top == lastTop && current >= begin);
116*38e8c45fSAndroid Build Coastguard Worker 
117*38e8c45fSAndroid Build Coastguard Worker     int beginLastSpan = -1;
118*38e8c45fSAndroid Build Coastguard Worker     int endLastSpan = -1;
119*38e8c45fSAndroid Build Coastguard Worker     int top = -1;
120*38e8c45fSAndroid Build Coastguard Worker     int bottom = -1;
121*38e8c45fSAndroid Build Coastguard Worker 
122*38e8c45fSAndroid Build Coastguard Worker     // for all other spans, split if a t-junction exists in the span directly above
123*38e8c45fSAndroid Build Coastguard Worker     while (current >= begin) {
124*38e8c45fSAndroid Build Coastguard Worker         if (current->top != (current + 1)->top) {
125*38e8c45fSAndroid Build Coastguard Worker             // new span
126*38e8c45fSAndroid Build Coastguard Worker             if ((spanDirection == direction_RTL && current->bottom != (current + 1)->top) ||
127*38e8c45fSAndroid Build Coastguard Worker                     (spanDirection == direction_LTR && current->top != (current + 1)->bottom)) {
128*38e8c45fSAndroid Build Coastguard Worker                 // previous span not directly adjacent, don't check for T junctions
129*38e8c45fSAndroid Build Coastguard Worker                 beginLastSpan = INT_MAX;
130*38e8c45fSAndroid Build Coastguard Worker             } else {
131*38e8c45fSAndroid Build Coastguard Worker                 beginLastSpan = endLastSpan + 1;
132*38e8c45fSAndroid Build Coastguard Worker             }
133*38e8c45fSAndroid Build Coastguard Worker             endLastSpan = static_cast<int>(dst.size()) - 1;
134*38e8c45fSAndroid Build Coastguard Worker 
135*38e8c45fSAndroid Build Coastguard Worker             top = current->top;
136*38e8c45fSAndroid Build Coastguard Worker             bottom = current->bottom;
137*38e8c45fSAndroid Build Coastguard Worker         }
138*38e8c45fSAndroid Build Coastguard Worker         int left = current->left;
139*38e8c45fSAndroid Build Coastguard Worker         int right = current->right;
140*38e8c45fSAndroid Build Coastguard Worker 
141*38e8c45fSAndroid Build Coastguard Worker         for (int prevIndex = beginLastSpan; prevIndex <= endLastSpan; prevIndex++) {
142*38e8c45fSAndroid Build Coastguard Worker             // prevIndex can't be -1 here because if endLastSpan is set to a
143*38e8c45fSAndroid Build Coastguard Worker             // value greater than -1 (allowing the loop to execute),
144*38e8c45fSAndroid Build Coastguard Worker             // beginLastSpan (and therefore prevIndex) will also be increased
145*38e8c45fSAndroid Build Coastguard Worker             const Rect prev = dst[static_cast<size_t>(prevIndex)];
146*38e8c45fSAndroid Build Coastguard Worker             if (spanDirection == direction_RTL) {
147*38e8c45fSAndroid Build Coastguard Worker                 // iterating over previous span RTL, quit if it's too far left
148*38e8c45fSAndroid Build Coastguard Worker                 if (prev.right <= left) break;
149*38e8c45fSAndroid Build Coastguard Worker 
150*38e8c45fSAndroid Build Coastguard Worker                 if (prev.right > left && prev.right < right) {
151*38e8c45fSAndroid Build Coastguard Worker                     dst.push_back(Rect(prev.right, top, right, bottom));
152*38e8c45fSAndroid Build Coastguard Worker                     right = prev.right;
153*38e8c45fSAndroid Build Coastguard Worker                 }
154*38e8c45fSAndroid Build Coastguard Worker 
155*38e8c45fSAndroid Build Coastguard Worker                 if (prev.left > left && prev.left < right) {
156*38e8c45fSAndroid Build Coastguard Worker                     dst.push_back(Rect(prev.left, top, right, bottom));
157*38e8c45fSAndroid Build Coastguard Worker                     right = prev.left;
158*38e8c45fSAndroid Build Coastguard Worker                 }
159*38e8c45fSAndroid Build Coastguard Worker 
160*38e8c45fSAndroid Build Coastguard Worker                 // if an entry in the previous span is too far right, nothing further left in the
161*38e8c45fSAndroid Build Coastguard Worker                 // current span will need it
162*38e8c45fSAndroid Build Coastguard Worker                 if (prev.left >= right) {
163*38e8c45fSAndroid Build Coastguard Worker                     beginLastSpan = prevIndex;
164*38e8c45fSAndroid Build Coastguard Worker                 }
165*38e8c45fSAndroid Build Coastguard Worker             } else {
166*38e8c45fSAndroid Build Coastguard Worker                 // iterating over previous span LTR, quit if it's too far right
167*38e8c45fSAndroid Build Coastguard Worker                 if (prev.left >= right) break;
168*38e8c45fSAndroid Build Coastguard Worker 
169*38e8c45fSAndroid Build Coastguard Worker                 if (prev.left > left && prev.left < right) {
170*38e8c45fSAndroid Build Coastguard Worker                     dst.push_back(Rect(left, top, prev.left, bottom));
171*38e8c45fSAndroid Build Coastguard Worker                     left = prev.left;
172*38e8c45fSAndroid Build Coastguard Worker                 }
173*38e8c45fSAndroid Build Coastguard Worker 
174*38e8c45fSAndroid Build Coastguard Worker                 if (prev.right > left && prev.right < right) {
175*38e8c45fSAndroid Build Coastguard Worker                     dst.push_back(Rect(left, top, prev.right, bottom));
176*38e8c45fSAndroid Build Coastguard Worker                     left = prev.right;
177*38e8c45fSAndroid Build Coastguard Worker                 }
178*38e8c45fSAndroid Build Coastguard Worker                 // if an entry in the previous span is too far left, nothing further right in the
179*38e8c45fSAndroid Build Coastguard Worker                 // current span will need it
180*38e8c45fSAndroid Build Coastguard Worker                 if (prev.right <= left) {
181*38e8c45fSAndroid Build Coastguard Worker                     beginLastSpan = prevIndex;
182*38e8c45fSAndroid Build Coastguard Worker                 }
183*38e8c45fSAndroid Build Coastguard Worker             }
184*38e8c45fSAndroid Build Coastguard Worker         }
185*38e8c45fSAndroid Build Coastguard Worker 
186*38e8c45fSAndroid Build Coastguard Worker         if (left < right) {
187*38e8c45fSAndroid Build Coastguard Worker             dst.push_back(Rect(left, top, right, bottom));
188*38e8c45fSAndroid Build Coastguard Worker         }
189*38e8c45fSAndroid Build Coastguard Worker 
190*38e8c45fSAndroid Build Coastguard Worker         current--;
191*38e8c45fSAndroid Build Coastguard Worker     }
192*38e8c45fSAndroid Build Coastguard Worker }
193*38e8c45fSAndroid Build Coastguard Worker 
194*38e8c45fSAndroid Build Coastguard Worker /**
195*38e8c45fSAndroid Build Coastguard Worker  * Creates a new region with the same data as the argument, but divides rectangles as necessary to
196*38e8c45fSAndroid Build Coastguard Worker  * remove T-Junctions
197*38e8c45fSAndroid Build Coastguard Worker  *
198*38e8c45fSAndroid Build Coastguard Worker  * Note: the output will not necessarily be a very efficient representation of the region, since it
199*38e8c45fSAndroid Build Coastguard Worker  * may be that a triangle-based approach would generate significantly simpler geometry
200*38e8c45fSAndroid Build Coastguard Worker  */
createTJunctionFreeRegion(const Region & r)201*38e8c45fSAndroid Build Coastguard Worker Region Region::createTJunctionFreeRegion(const Region& r) {
202*38e8c45fSAndroid Build Coastguard Worker     if (r.isEmpty()) return r;
203*38e8c45fSAndroid Build Coastguard Worker     if (r.isRect()) return r;
204*38e8c45fSAndroid Build Coastguard Worker 
205*38e8c45fSAndroid Build Coastguard Worker     FatVector<Rect> reversed;
206*38e8c45fSAndroid Build Coastguard Worker     reverseRectsResolvingJunctions(r.begin(), r.end(), reversed, direction_RTL);
207*38e8c45fSAndroid Build Coastguard Worker 
208*38e8c45fSAndroid Build Coastguard Worker     Region outputRegion;
209*38e8c45fSAndroid Build Coastguard Worker     reverseRectsResolvingJunctions(reversed.data(), reversed.data() + reversed.size(),
210*38e8c45fSAndroid Build Coastguard Worker                                    outputRegion.mStorage, direction_LTR);
211*38e8c45fSAndroid Build Coastguard Worker     outputRegion.mStorage.push_back(
212*38e8c45fSAndroid Build Coastguard Worker             r.getBounds()); // to make region valid, mStorage must end with bounds
213*38e8c45fSAndroid Build Coastguard Worker 
214*38e8c45fSAndroid Build Coastguard Worker #if defined(VALIDATE_REGIONS)
215*38e8c45fSAndroid Build Coastguard Worker     validate(outputRegion, "T-Junction free region");
216*38e8c45fSAndroid Build Coastguard Worker #endif
217*38e8c45fSAndroid Build Coastguard Worker 
218*38e8c45fSAndroid Build Coastguard Worker     return outputRegion;
219*38e8c45fSAndroid Build Coastguard Worker }
220*38e8c45fSAndroid Build Coastguard Worker 
operator =(const Region & rhs)221*38e8c45fSAndroid Build Coastguard Worker Region& Region::operator = (const Region& rhs)
222*38e8c45fSAndroid Build Coastguard Worker {
223*38e8c45fSAndroid Build Coastguard Worker #if defined(VALIDATE_REGIONS)
224*38e8c45fSAndroid Build Coastguard Worker     validate(*this, "this->operator=");
225*38e8c45fSAndroid Build Coastguard Worker     validate(rhs, "rhs.operator=");
226*38e8c45fSAndroid Build Coastguard Worker #endif
227*38e8c45fSAndroid Build Coastguard Worker     if (this == &rhs) {
228*38e8c45fSAndroid Build Coastguard Worker         // Already equal to itself
229*38e8c45fSAndroid Build Coastguard Worker         return *this;
230*38e8c45fSAndroid Build Coastguard Worker     }
231*38e8c45fSAndroid Build Coastguard Worker 
232*38e8c45fSAndroid Build Coastguard Worker     mStorage.clear();
233*38e8c45fSAndroid Build Coastguard Worker     mStorage.insert(mStorage.begin(), rhs.mStorage.begin(), rhs.mStorage.end());
234*38e8c45fSAndroid Build Coastguard Worker     return *this;
235*38e8c45fSAndroid Build Coastguard Worker }
236*38e8c45fSAndroid Build Coastguard Worker 
makeBoundsSelf()237*38e8c45fSAndroid Build Coastguard Worker Region& Region::makeBoundsSelf()
238*38e8c45fSAndroid Build Coastguard Worker {
239*38e8c45fSAndroid Build Coastguard Worker     if (mStorage.size() >= 2) {
240*38e8c45fSAndroid Build Coastguard Worker         const Rect bounds(getBounds());
241*38e8c45fSAndroid Build Coastguard Worker         mStorage.clear();
242*38e8c45fSAndroid Build Coastguard Worker         mStorage.push_back(bounds);
243*38e8c45fSAndroid Build Coastguard Worker     }
244*38e8c45fSAndroid Build Coastguard Worker     return *this;
245*38e8c45fSAndroid Build Coastguard Worker }
246*38e8c45fSAndroid Build Coastguard Worker 
contains(const Point & point) const247*38e8c45fSAndroid Build Coastguard Worker bool Region::contains(const Point& point) const {
248*38e8c45fSAndroid Build Coastguard Worker     return contains(point.x, point.y);
249*38e8c45fSAndroid Build Coastguard Worker }
250*38e8c45fSAndroid Build Coastguard Worker 
contains(int x,int y) const251*38e8c45fSAndroid Build Coastguard Worker bool Region::contains(int x, int y) const {
252*38e8c45fSAndroid Build Coastguard Worker     const_iterator cur = begin();
253*38e8c45fSAndroid Build Coastguard Worker     const_iterator const tail = end();
254*38e8c45fSAndroid Build Coastguard Worker     while (cur != tail) {
255*38e8c45fSAndroid Build Coastguard Worker         if (y >= cur->top && y < cur->bottom && x >= cur->left && x < cur->right) {
256*38e8c45fSAndroid Build Coastguard Worker             return true;
257*38e8c45fSAndroid Build Coastguard Worker         }
258*38e8c45fSAndroid Build Coastguard Worker         cur++;
259*38e8c45fSAndroid Build Coastguard Worker     }
260*38e8c45fSAndroid Build Coastguard Worker     return false;
261*38e8c45fSAndroid Build Coastguard Worker }
262*38e8c45fSAndroid Build Coastguard Worker 
clear()263*38e8c45fSAndroid Build Coastguard Worker void Region::clear()
264*38e8c45fSAndroid Build Coastguard Worker {
265*38e8c45fSAndroid Build Coastguard Worker     mStorage.clear();
266*38e8c45fSAndroid Build Coastguard Worker     mStorage.push_back(Rect(0, 0));
267*38e8c45fSAndroid Build Coastguard Worker }
268*38e8c45fSAndroid Build Coastguard Worker 
set(const Rect & r)269*38e8c45fSAndroid Build Coastguard Worker void Region::set(const Rect& r)
270*38e8c45fSAndroid Build Coastguard Worker {
271*38e8c45fSAndroid Build Coastguard Worker     mStorage.clear();
272*38e8c45fSAndroid Build Coastguard Worker     mStorage.push_back(r);
273*38e8c45fSAndroid Build Coastguard Worker }
274*38e8c45fSAndroid Build Coastguard Worker 
set(int32_t w,int32_t h)275*38e8c45fSAndroid Build Coastguard Worker void Region::set(int32_t w, int32_t h)
276*38e8c45fSAndroid Build Coastguard Worker {
277*38e8c45fSAndroid Build Coastguard Worker     mStorage.clear();
278*38e8c45fSAndroid Build Coastguard Worker     mStorage.push_back(Rect(w, h));
279*38e8c45fSAndroid Build Coastguard Worker }
280*38e8c45fSAndroid Build Coastguard Worker 
set(uint32_t w,uint32_t h)281*38e8c45fSAndroid Build Coastguard Worker void Region::set(uint32_t w, uint32_t h)
282*38e8c45fSAndroid Build Coastguard Worker {
283*38e8c45fSAndroid Build Coastguard Worker     mStorage.clear();
284*38e8c45fSAndroid Build Coastguard Worker     mStorage.push_back(Rect(w, h));
285*38e8c45fSAndroid Build Coastguard Worker }
286*38e8c45fSAndroid Build Coastguard Worker 
isTriviallyEqual(const Region & region) const287*38e8c45fSAndroid Build Coastguard Worker bool Region::isTriviallyEqual(const Region& region) const {
288*38e8c45fSAndroid Build Coastguard Worker     return begin() == region.begin();
289*38e8c45fSAndroid Build Coastguard Worker }
290*38e8c45fSAndroid Build Coastguard Worker 
hasSameRects(const Region & other) const291*38e8c45fSAndroid Build Coastguard Worker bool Region::hasSameRects(const Region& other) const {
292*38e8c45fSAndroid Build Coastguard Worker     size_t thisRectCount = 0;
293*38e8c45fSAndroid Build Coastguard Worker     android::Rect const* thisRects = getArray(&thisRectCount);
294*38e8c45fSAndroid Build Coastguard Worker     size_t otherRectCount = 0;
295*38e8c45fSAndroid Build Coastguard Worker     android::Rect const* otherRects = other.getArray(&otherRectCount);
296*38e8c45fSAndroid Build Coastguard Worker 
297*38e8c45fSAndroid Build Coastguard Worker     if (thisRectCount != otherRectCount) return false;
298*38e8c45fSAndroid Build Coastguard Worker 
299*38e8c45fSAndroid Build Coastguard Worker     for (size_t i = 0; i < thisRectCount; i++) {
300*38e8c45fSAndroid Build Coastguard Worker         if (thisRects[i] != otherRects[i]) return false;
301*38e8c45fSAndroid Build Coastguard Worker     }
302*38e8c45fSAndroid Build Coastguard Worker     return true;
303*38e8c45fSAndroid Build Coastguard Worker }
304*38e8c45fSAndroid Build Coastguard Worker 
305*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
306*38e8c45fSAndroid Build Coastguard Worker 
addRectUnchecked(int l,int t,int r,int b)307*38e8c45fSAndroid Build Coastguard Worker void Region::addRectUnchecked(int l, int t, int r, int b)
308*38e8c45fSAndroid Build Coastguard Worker {
309*38e8c45fSAndroid Build Coastguard Worker     Rect rect(l,t,r,b);
310*38e8c45fSAndroid Build Coastguard Worker     mStorage.insert(mStorage.end() - 1, rect);
311*38e8c45fSAndroid Build Coastguard Worker }
312*38e8c45fSAndroid Build Coastguard Worker 
313*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
314*38e8c45fSAndroid Build Coastguard Worker 
orSelf(const Rect & r)315*38e8c45fSAndroid Build Coastguard Worker Region& Region::orSelf(const Rect& r) {
316*38e8c45fSAndroid Build Coastguard Worker     if (isEmpty()) {
317*38e8c45fSAndroid Build Coastguard Worker         set(r);
318*38e8c45fSAndroid Build Coastguard Worker         return *this;
319*38e8c45fSAndroid Build Coastguard Worker     }
320*38e8c45fSAndroid Build Coastguard Worker     return operationSelf(r, op_or);
321*38e8c45fSAndroid Build Coastguard Worker }
xorSelf(const Rect & r)322*38e8c45fSAndroid Build Coastguard Worker Region& Region::xorSelf(const Rect& r) {
323*38e8c45fSAndroid Build Coastguard Worker     return operationSelf(r, op_xor);
324*38e8c45fSAndroid Build Coastguard Worker }
andSelf(const Rect & r)325*38e8c45fSAndroid Build Coastguard Worker Region& Region::andSelf(const Rect& r) {
326*38e8c45fSAndroid Build Coastguard Worker     return operationSelf(r, op_and);
327*38e8c45fSAndroid Build Coastguard Worker }
subtractSelf(const Rect & r)328*38e8c45fSAndroid Build Coastguard Worker Region& Region::subtractSelf(const Rect& r) {
329*38e8c45fSAndroid Build Coastguard Worker     return operationSelf(r, op_nand);
330*38e8c45fSAndroid Build Coastguard Worker }
operationSelf(const Rect & r,uint32_t op)331*38e8c45fSAndroid Build Coastguard Worker Region& Region::operationSelf(const Rect& r, uint32_t op) {
332*38e8c45fSAndroid Build Coastguard Worker     Region lhs(*this);
333*38e8c45fSAndroid Build Coastguard Worker     boolean_operation(op, *this, lhs, r);
334*38e8c45fSAndroid Build Coastguard Worker     return *this;
335*38e8c45fSAndroid Build Coastguard Worker }
336*38e8c45fSAndroid Build Coastguard Worker 
337*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
338*38e8c45fSAndroid Build Coastguard Worker 
orSelf(const Region & rhs)339*38e8c45fSAndroid Build Coastguard Worker Region& Region::orSelf(const Region& rhs) {
340*38e8c45fSAndroid Build Coastguard Worker     if (isEmpty()) {
341*38e8c45fSAndroid Build Coastguard Worker         *this = rhs;
342*38e8c45fSAndroid Build Coastguard Worker         return *this;
343*38e8c45fSAndroid Build Coastguard Worker     }
344*38e8c45fSAndroid Build Coastguard Worker     return operationSelf(rhs, op_or);
345*38e8c45fSAndroid Build Coastguard Worker }
xorSelf(const Region & rhs)346*38e8c45fSAndroid Build Coastguard Worker Region& Region::xorSelf(const Region& rhs) {
347*38e8c45fSAndroid Build Coastguard Worker     return operationSelf(rhs, op_xor);
348*38e8c45fSAndroid Build Coastguard Worker }
andSelf(const Region & rhs)349*38e8c45fSAndroid Build Coastguard Worker Region& Region::andSelf(const Region& rhs) {
350*38e8c45fSAndroid Build Coastguard Worker     return operationSelf(rhs, op_and);
351*38e8c45fSAndroid Build Coastguard Worker }
subtractSelf(const Region & rhs)352*38e8c45fSAndroid Build Coastguard Worker Region& Region::subtractSelf(const Region& rhs) {
353*38e8c45fSAndroid Build Coastguard Worker     return operationSelf(rhs, op_nand);
354*38e8c45fSAndroid Build Coastguard Worker }
operationSelf(const Region & rhs,uint32_t op)355*38e8c45fSAndroid Build Coastguard Worker Region& Region::operationSelf(const Region& rhs, uint32_t op) {
356*38e8c45fSAndroid Build Coastguard Worker     Region lhs(*this);
357*38e8c45fSAndroid Build Coastguard Worker     boolean_operation(op, *this, lhs, rhs);
358*38e8c45fSAndroid Build Coastguard Worker     return *this;
359*38e8c45fSAndroid Build Coastguard Worker }
360*38e8c45fSAndroid Build Coastguard Worker 
translateSelf(int x,int y)361*38e8c45fSAndroid Build Coastguard Worker Region& Region::translateSelf(int x, int y) {
362*38e8c45fSAndroid Build Coastguard Worker     if (x|y) translate(*this, x, y);
363*38e8c45fSAndroid Build Coastguard Worker     return *this;
364*38e8c45fSAndroid Build Coastguard Worker }
365*38e8c45fSAndroid Build Coastguard Worker 
scaleSelf(float sx,float sy)366*38e8c45fSAndroid Build Coastguard Worker Region& Region::scaleSelf(float sx, float sy) {
367*38e8c45fSAndroid Build Coastguard Worker     size_t count = mStorage.size();
368*38e8c45fSAndroid Build Coastguard Worker     Rect* rects = mStorage.data();
369*38e8c45fSAndroid Build Coastguard Worker     while (count) {
370*38e8c45fSAndroid Build Coastguard Worker         rects->left = static_cast<int32_t>(static_cast<float>(rects->left) * sx + 0.5f);
371*38e8c45fSAndroid Build Coastguard Worker         rects->right = static_cast<int32_t>(static_cast<float>(rects->right) * sx + 0.5f);
372*38e8c45fSAndroid Build Coastguard Worker         rects->top = static_cast<int32_t>(static_cast<float>(rects->top) * sy + 0.5f);
373*38e8c45fSAndroid Build Coastguard Worker         rects->bottom = static_cast<int32_t>(static_cast<float>(rects->bottom) * sy + 0.5f);
374*38e8c45fSAndroid Build Coastguard Worker         rects++;
375*38e8c45fSAndroid Build Coastguard Worker         count--;
376*38e8c45fSAndroid Build Coastguard Worker     }
377*38e8c45fSAndroid Build Coastguard Worker     return *this;
378*38e8c45fSAndroid Build Coastguard Worker }
379*38e8c45fSAndroid Build Coastguard Worker 
380*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
381*38e8c45fSAndroid Build Coastguard Worker 
merge(const Rect & rhs) const382*38e8c45fSAndroid Build Coastguard Worker const Region Region::merge(const Rect& rhs) const {
383*38e8c45fSAndroid Build Coastguard Worker     return operation(rhs, op_or);
384*38e8c45fSAndroid Build Coastguard Worker }
mergeExclusive(const Rect & rhs) const385*38e8c45fSAndroid Build Coastguard Worker const Region Region::mergeExclusive(const Rect& rhs) const {
386*38e8c45fSAndroid Build Coastguard Worker     return operation(rhs, op_xor);
387*38e8c45fSAndroid Build Coastguard Worker }
intersect(const Rect & rhs) const388*38e8c45fSAndroid Build Coastguard Worker const Region Region::intersect(const Rect& rhs) const {
389*38e8c45fSAndroid Build Coastguard Worker     return operation(rhs, op_and);
390*38e8c45fSAndroid Build Coastguard Worker }
subtract(const Rect & rhs) const391*38e8c45fSAndroid Build Coastguard Worker const Region Region::subtract(const Rect& rhs) const {
392*38e8c45fSAndroid Build Coastguard Worker     return operation(rhs, op_nand);
393*38e8c45fSAndroid Build Coastguard Worker }
operation(const Rect & rhs,uint32_t op) const394*38e8c45fSAndroid Build Coastguard Worker const Region Region::operation(const Rect& rhs, uint32_t op) const {
395*38e8c45fSAndroid Build Coastguard Worker     Region result;
396*38e8c45fSAndroid Build Coastguard Worker     boolean_operation(op, result, *this, rhs);
397*38e8c45fSAndroid Build Coastguard Worker     return result;
398*38e8c45fSAndroid Build Coastguard Worker }
399*38e8c45fSAndroid Build Coastguard Worker 
400*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
401*38e8c45fSAndroid Build Coastguard Worker 
merge(const Region & rhs) const402*38e8c45fSAndroid Build Coastguard Worker const Region Region::merge(const Region& rhs) const {
403*38e8c45fSAndroid Build Coastguard Worker     return operation(rhs, op_or);
404*38e8c45fSAndroid Build Coastguard Worker }
mergeExclusive(const Region & rhs) const405*38e8c45fSAndroid Build Coastguard Worker const Region Region::mergeExclusive(const Region& rhs) const {
406*38e8c45fSAndroid Build Coastguard Worker     return operation(rhs, op_xor);
407*38e8c45fSAndroid Build Coastguard Worker }
intersect(const Region & rhs) const408*38e8c45fSAndroid Build Coastguard Worker const Region Region::intersect(const Region& rhs) const {
409*38e8c45fSAndroid Build Coastguard Worker     return operation(rhs, op_and);
410*38e8c45fSAndroid Build Coastguard Worker }
subtract(const Region & rhs) const411*38e8c45fSAndroid Build Coastguard Worker const Region Region::subtract(const Region& rhs) const {
412*38e8c45fSAndroid Build Coastguard Worker     return operation(rhs, op_nand);
413*38e8c45fSAndroid Build Coastguard Worker }
operation(const Region & rhs,uint32_t op) const414*38e8c45fSAndroid Build Coastguard Worker const Region Region::operation(const Region& rhs, uint32_t op) const {
415*38e8c45fSAndroid Build Coastguard Worker     Region result;
416*38e8c45fSAndroid Build Coastguard Worker     boolean_operation(op, result, *this, rhs);
417*38e8c45fSAndroid Build Coastguard Worker     return result;
418*38e8c45fSAndroid Build Coastguard Worker }
419*38e8c45fSAndroid Build Coastguard Worker 
translate(int x,int y) const420*38e8c45fSAndroid Build Coastguard Worker const Region Region::translate(int x, int y) const {
421*38e8c45fSAndroid Build Coastguard Worker     Region result;
422*38e8c45fSAndroid Build Coastguard Worker     translate(result, *this, x, y);
423*38e8c45fSAndroid Build Coastguard Worker     return result;
424*38e8c45fSAndroid Build Coastguard Worker }
425*38e8c45fSAndroid Build Coastguard Worker 
426*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
427*38e8c45fSAndroid Build Coastguard Worker 
orSelf(const Region & rhs,int dx,int dy)428*38e8c45fSAndroid Build Coastguard Worker Region& Region::orSelf(const Region& rhs, int dx, int dy) {
429*38e8c45fSAndroid Build Coastguard Worker     return operationSelf(rhs, dx, dy, op_or);
430*38e8c45fSAndroid Build Coastguard Worker }
xorSelf(const Region & rhs,int dx,int dy)431*38e8c45fSAndroid Build Coastguard Worker Region& Region::xorSelf(const Region& rhs, int dx, int dy) {
432*38e8c45fSAndroid Build Coastguard Worker     return operationSelf(rhs, dx, dy, op_xor);
433*38e8c45fSAndroid Build Coastguard Worker }
andSelf(const Region & rhs,int dx,int dy)434*38e8c45fSAndroid Build Coastguard Worker Region& Region::andSelf(const Region& rhs, int dx, int dy) {
435*38e8c45fSAndroid Build Coastguard Worker     return operationSelf(rhs, dx, dy, op_and);
436*38e8c45fSAndroid Build Coastguard Worker }
subtractSelf(const Region & rhs,int dx,int dy)437*38e8c45fSAndroid Build Coastguard Worker Region& Region::subtractSelf(const Region& rhs, int dx, int dy) {
438*38e8c45fSAndroid Build Coastguard Worker     return operationSelf(rhs, dx, dy, op_nand);
439*38e8c45fSAndroid Build Coastguard Worker }
operationSelf(const Region & rhs,int dx,int dy,uint32_t op)440*38e8c45fSAndroid Build Coastguard Worker Region& Region::operationSelf(const Region& rhs, int dx, int dy, uint32_t op) {
441*38e8c45fSAndroid Build Coastguard Worker     Region lhs(*this);
442*38e8c45fSAndroid Build Coastguard Worker     boolean_operation(op, *this, lhs, rhs, dx, dy);
443*38e8c45fSAndroid Build Coastguard Worker     return *this;
444*38e8c45fSAndroid Build Coastguard Worker }
445*38e8c45fSAndroid Build Coastguard Worker 
446*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
447*38e8c45fSAndroid Build Coastguard Worker 
merge(const Region & rhs,int dx,int dy) const448*38e8c45fSAndroid Build Coastguard Worker const Region Region::merge(const Region& rhs, int dx, int dy) const {
449*38e8c45fSAndroid Build Coastguard Worker     return operation(rhs, dx, dy, op_or);
450*38e8c45fSAndroid Build Coastguard Worker }
mergeExclusive(const Region & rhs,int dx,int dy) const451*38e8c45fSAndroid Build Coastguard Worker const Region Region::mergeExclusive(const Region& rhs, int dx, int dy) const {
452*38e8c45fSAndroid Build Coastguard Worker     return operation(rhs, dx, dy, op_xor);
453*38e8c45fSAndroid Build Coastguard Worker }
intersect(const Region & rhs,int dx,int dy) const454*38e8c45fSAndroid Build Coastguard Worker const Region Region::intersect(const Region& rhs, int dx, int dy) const {
455*38e8c45fSAndroid Build Coastguard Worker     return operation(rhs, dx, dy, op_and);
456*38e8c45fSAndroid Build Coastguard Worker }
subtract(const Region & rhs,int dx,int dy) const457*38e8c45fSAndroid Build Coastguard Worker const Region Region::subtract(const Region& rhs, int dx, int dy) const {
458*38e8c45fSAndroid Build Coastguard Worker     return operation(rhs, dx, dy, op_nand);
459*38e8c45fSAndroid Build Coastguard Worker }
operation(const Region & rhs,int dx,int dy,uint32_t op) const460*38e8c45fSAndroid Build Coastguard Worker const Region Region::operation(const Region& rhs, int dx, int dy, uint32_t op) const {
461*38e8c45fSAndroid Build Coastguard Worker     Region result;
462*38e8c45fSAndroid Build Coastguard Worker     boolean_operation(op, result, *this, rhs, dx, dy);
463*38e8c45fSAndroid Build Coastguard Worker     return result;
464*38e8c45fSAndroid Build Coastguard Worker }
465*38e8c45fSAndroid Build Coastguard Worker 
466*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
467*38e8c45fSAndroid Build Coastguard Worker 
468*38e8c45fSAndroid Build Coastguard Worker // This is our region rasterizer, which merges rects and spans together
469*38e8c45fSAndroid Build Coastguard Worker // to obtain an optimal region.
470*38e8c45fSAndroid Build Coastguard Worker class Region::rasterizer : public region_operator<Rect>::region_rasterizer
471*38e8c45fSAndroid Build Coastguard Worker {
472*38e8c45fSAndroid Build Coastguard Worker     Rect bounds;
473*38e8c45fSAndroid Build Coastguard Worker     FatVector<Rect>& storage;
474*38e8c45fSAndroid Build Coastguard Worker     Rect* head;
475*38e8c45fSAndroid Build Coastguard Worker     Rect* tail;
476*38e8c45fSAndroid Build Coastguard Worker     FatVector<Rect> span;
477*38e8c45fSAndroid Build Coastguard Worker     Rect* cur;
478*38e8c45fSAndroid Build Coastguard Worker public:
rasterizer(Region & reg)479*38e8c45fSAndroid Build Coastguard Worker     explicit rasterizer(Region& reg)
480*38e8c45fSAndroid Build Coastguard Worker         : bounds(INT_MAX, 0, INT_MIN, 0), storage(reg.mStorage), head(), tail(), cur() {
481*38e8c45fSAndroid Build Coastguard Worker         storage.clear();
482*38e8c45fSAndroid Build Coastguard Worker     }
483*38e8c45fSAndroid Build Coastguard Worker 
484*38e8c45fSAndroid Build Coastguard Worker     virtual ~rasterizer();
485*38e8c45fSAndroid Build Coastguard Worker 
486*38e8c45fSAndroid Build Coastguard Worker     virtual void operator()(const Rect& rect);
487*38e8c45fSAndroid Build Coastguard Worker 
488*38e8c45fSAndroid Build Coastguard Worker private:
489*38e8c45fSAndroid Build Coastguard Worker     template<typename T>
min(T rhs,T lhs)490*38e8c45fSAndroid Build Coastguard Worker     static inline T min(T rhs, T lhs) { return rhs < lhs ? rhs : lhs; }
491*38e8c45fSAndroid Build Coastguard Worker     template<typename T>
max(T rhs,T lhs)492*38e8c45fSAndroid Build Coastguard Worker     static inline T max(T rhs, T lhs) { return rhs > lhs ? rhs : lhs; }
493*38e8c45fSAndroid Build Coastguard Worker 
494*38e8c45fSAndroid Build Coastguard Worker     void flushSpan();
495*38e8c45fSAndroid Build Coastguard Worker };
496*38e8c45fSAndroid Build Coastguard Worker 
~rasterizer()497*38e8c45fSAndroid Build Coastguard Worker Region::rasterizer::~rasterizer()
498*38e8c45fSAndroid Build Coastguard Worker {
499*38e8c45fSAndroid Build Coastguard Worker     if (span.size()) {
500*38e8c45fSAndroid Build Coastguard Worker         flushSpan();
501*38e8c45fSAndroid Build Coastguard Worker     }
502*38e8c45fSAndroid Build Coastguard Worker     if (storage.size()) {
503*38e8c45fSAndroid Build Coastguard Worker         bounds.top = storage.front().top;
504*38e8c45fSAndroid Build Coastguard Worker         bounds.bottom = storage.back().bottom;
505*38e8c45fSAndroid Build Coastguard Worker         if (storage.size() == 1) {
506*38e8c45fSAndroid Build Coastguard Worker             storage.clear();
507*38e8c45fSAndroid Build Coastguard Worker         }
508*38e8c45fSAndroid Build Coastguard Worker     } else {
509*38e8c45fSAndroid Build Coastguard Worker         bounds.left  = 0;
510*38e8c45fSAndroid Build Coastguard Worker         bounds.right = 0;
511*38e8c45fSAndroid Build Coastguard Worker     }
512*38e8c45fSAndroid Build Coastguard Worker     storage.push_back(bounds);
513*38e8c45fSAndroid Build Coastguard Worker }
514*38e8c45fSAndroid Build Coastguard Worker 
operator ()(const Rect & rect)515*38e8c45fSAndroid Build Coastguard Worker void Region::rasterizer::operator()(const Rect& rect)
516*38e8c45fSAndroid Build Coastguard Worker {
517*38e8c45fSAndroid Build Coastguard Worker     //ALOGD(">>> %3d, %3d, %3d, %3d",
518*38e8c45fSAndroid Build Coastguard Worker     //        rect.left, rect.top, rect.right, rect.bottom);
519*38e8c45fSAndroid Build Coastguard Worker     if (span.size()) {
520*38e8c45fSAndroid Build Coastguard Worker         if (cur->top != rect.top) {
521*38e8c45fSAndroid Build Coastguard Worker             flushSpan();
522*38e8c45fSAndroid Build Coastguard Worker         } else if (cur->right == rect.left) {
523*38e8c45fSAndroid Build Coastguard Worker             cur->right = rect.right;
524*38e8c45fSAndroid Build Coastguard Worker             return;
525*38e8c45fSAndroid Build Coastguard Worker         }
526*38e8c45fSAndroid Build Coastguard Worker     }
527*38e8c45fSAndroid Build Coastguard Worker     span.push_back(rect);
528*38e8c45fSAndroid Build Coastguard Worker     cur = span.data() + (span.size() - 1);
529*38e8c45fSAndroid Build Coastguard Worker }
530*38e8c45fSAndroid Build Coastguard Worker 
flushSpan()531*38e8c45fSAndroid Build Coastguard Worker void Region::rasterizer::flushSpan()
532*38e8c45fSAndroid Build Coastguard Worker {
533*38e8c45fSAndroid Build Coastguard Worker     bool merge = false;
534*38e8c45fSAndroid Build Coastguard Worker     if (tail-head == ssize_t(span.size())) {
535*38e8c45fSAndroid Build Coastguard Worker         Rect const* p = span.data();
536*38e8c45fSAndroid Build Coastguard Worker         Rect const* q = head;
537*38e8c45fSAndroid Build Coastguard Worker         if (p->top == q->bottom) {
538*38e8c45fSAndroid Build Coastguard Worker             merge = true;
539*38e8c45fSAndroid Build Coastguard Worker             while (q != tail) {
540*38e8c45fSAndroid Build Coastguard Worker                 if ((p->left != q->left) || (p->right != q->right)) {
541*38e8c45fSAndroid Build Coastguard Worker                     merge = false;
542*38e8c45fSAndroid Build Coastguard Worker                     break;
543*38e8c45fSAndroid Build Coastguard Worker                 }
544*38e8c45fSAndroid Build Coastguard Worker                 p++;
545*38e8c45fSAndroid Build Coastguard Worker                 q++;
546*38e8c45fSAndroid Build Coastguard Worker             }
547*38e8c45fSAndroid Build Coastguard Worker         }
548*38e8c45fSAndroid Build Coastguard Worker     }
549*38e8c45fSAndroid Build Coastguard Worker     if (merge) {
550*38e8c45fSAndroid Build Coastguard Worker         const int bottom = span.front().bottom;
551*38e8c45fSAndroid Build Coastguard Worker         Rect* r = head;
552*38e8c45fSAndroid Build Coastguard Worker         while (r != tail) {
553*38e8c45fSAndroid Build Coastguard Worker             r->bottom = bottom;
554*38e8c45fSAndroid Build Coastguard Worker             r++;
555*38e8c45fSAndroid Build Coastguard Worker         }
556*38e8c45fSAndroid Build Coastguard Worker     } else {
557*38e8c45fSAndroid Build Coastguard Worker         bounds.left = min(span.front().left, bounds.left);
558*38e8c45fSAndroid Build Coastguard Worker         bounds.right = max(span.back().right, bounds.right);
559*38e8c45fSAndroid Build Coastguard Worker         storage.insert(storage.end(), span.begin(), span.end());
560*38e8c45fSAndroid Build Coastguard Worker         tail = storage.data() + storage.size();
561*38e8c45fSAndroid Build Coastguard Worker         head = tail - span.size();
562*38e8c45fSAndroid Build Coastguard Worker     }
563*38e8c45fSAndroid Build Coastguard Worker     span.clear();
564*38e8c45fSAndroid Build Coastguard Worker }
565*38e8c45fSAndroid Build Coastguard Worker 
validate(const Region & reg,const char * name,bool silent)566*38e8c45fSAndroid Build Coastguard Worker bool Region::validate(const Region& reg, const char* name, bool silent)
567*38e8c45fSAndroid Build Coastguard Worker {
568*38e8c45fSAndroid Build Coastguard Worker     if (reg.mStorage.empty()) {
569*38e8c45fSAndroid Build Coastguard Worker         ALOGE_IF(!silent, "%s: mStorage is empty, which is never valid", name);
570*38e8c45fSAndroid Build Coastguard Worker         // return immediately as the code below assumes mStorage is non-empty
571*38e8c45fSAndroid Build Coastguard Worker         return false;
572*38e8c45fSAndroid Build Coastguard Worker     }
573*38e8c45fSAndroid Build Coastguard Worker 
574*38e8c45fSAndroid Build Coastguard Worker     bool result = true;
575*38e8c45fSAndroid Build Coastguard Worker     const_iterator cur = reg.begin();
576*38e8c45fSAndroid Build Coastguard Worker     const_iterator const tail = reg.end();
577*38e8c45fSAndroid Build Coastguard Worker     const_iterator prev = cur;
578*38e8c45fSAndroid Build Coastguard Worker     Rect b(*prev);
579*38e8c45fSAndroid Build Coastguard Worker     while (cur != tail) {
580*38e8c45fSAndroid Build Coastguard Worker         if (cur->isValid() == false) {
581*38e8c45fSAndroid Build Coastguard Worker             // We allow this particular flavor of invalid Rect, since it is used
582*38e8c45fSAndroid Build Coastguard Worker             // as a signal value in various parts of the system
583*38e8c45fSAndroid Build Coastguard Worker             if (*cur != Rect::INVALID_RECT) {
584*38e8c45fSAndroid Build Coastguard Worker                 ALOGE_IF(!silent, "%s: region contains an invalid Rect", name);
585*38e8c45fSAndroid Build Coastguard Worker                 result = false;
586*38e8c45fSAndroid Build Coastguard Worker             }
587*38e8c45fSAndroid Build Coastguard Worker         }
588*38e8c45fSAndroid Build Coastguard Worker         if (cur->right > region_operator<Rect>::max_value) {
589*38e8c45fSAndroid Build Coastguard Worker             ALOGE_IF(!silent, "%s: rect->right > max_value", name);
590*38e8c45fSAndroid Build Coastguard Worker             result = false;
591*38e8c45fSAndroid Build Coastguard Worker         }
592*38e8c45fSAndroid Build Coastguard Worker         if (cur->bottom > region_operator<Rect>::max_value) {
593*38e8c45fSAndroid Build Coastguard Worker             ALOGE_IF(!silent, "%s: rect->right > max_value", name);
594*38e8c45fSAndroid Build Coastguard Worker             result = false;
595*38e8c45fSAndroid Build Coastguard Worker         }
596*38e8c45fSAndroid Build Coastguard Worker         if (prev != cur) {
597*38e8c45fSAndroid Build Coastguard Worker             b.left   = b.left   < cur->left   ? b.left   : cur->left;
598*38e8c45fSAndroid Build Coastguard Worker             b.top    = b.top    < cur->top    ? b.top    : cur->top;
599*38e8c45fSAndroid Build Coastguard Worker             b.right  = b.right  > cur->right  ? b.right  : cur->right;
600*38e8c45fSAndroid Build Coastguard Worker             b.bottom = b.bottom > cur->bottom ? b.bottom : cur->bottom;
601*38e8c45fSAndroid Build Coastguard Worker             if ((*prev < *cur) == false) {
602*38e8c45fSAndroid Build Coastguard Worker                 ALOGE_IF(!silent, "%s: region's Rects not sorted", name);
603*38e8c45fSAndroid Build Coastguard Worker                 result = false;
604*38e8c45fSAndroid Build Coastguard Worker             }
605*38e8c45fSAndroid Build Coastguard Worker             if (cur->top == prev->top) {
606*38e8c45fSAndroid Build Coastguard Worker                 if (cur->bottom != prev->bottom) {
607*38e8c45fSAndroid Build Coastguard Worker                     ALOGE_IF(!silent, "%s: invalid span %p", name, cur);
608*38e8c45fSAndroid Build Coastguard Worker                     result = false;
609*38e8c45fSAndroid Build Coastguard Worker                 } else if (cur->left < prev->right) {
610*38e8c45fSAndroid Build Coastguard Worker                     ALOGE_IF(!silent,
611*38e8c45fSAndroid Build Coastguard Worker                             "%s: spans overlap horizontally prev=%p, cur=%p",
612*38e8c45fSAndroid Build Coastguard Worker                             name, prev, cur);
613*38e8c45fSAndroid Build Coastguard Worker                     result = false;
614*38e8c45fSAndroid Build Coastguard Worker                 }
615*38e8c45fSAndroid Build Coastguard Worker             } else if (cur->top < prev->bottom) {
616*38e8c45fSAndroid Build Coastguard Worker                 ALOGE_IF(!silent,
617*38e8c45fSAndroid Build Coastguard Worker                         "%s: spans overlap vertically prev=%p, cur=%p",
618*38e8c45fSAndroid Build Coastguard Worker                         name, prev, cur);
619*38e8c45fSAndroid Build Coastguard Worker                 result = false;
620*38e8c45fSAndroid Build Coastguard Worker             }
621*38e8c45fSAndroid Build Coastguard Worker             prev = cur;
622*38e8c45fSAndroid Build Coastguard Worker         }
623*38e8c45fSAndroid Build Coastguard Worker         cur++;
624*38e8c45fSAndroid Build Coastguard Worker     }
625*38e8c45fSAndroid Build Coastguard Worker     if (b != reg.getBounds()) {
626*38e8c45fSAndroid Build Coastguard Worker         result = false;
627*38e8c45fSAndroid Build Coastguard Worker         ALOGE_IF(!silent,
628*38e8c45fSAndroid Build Coastguard Worker                 "%s: invalid bounds [%d,%d,%d,%d] vs. [%d,%d,%d,%d]", name,
629*38e8c45fSAndroid Build Coastguard Worker                 b.left, b.top, b.right, b.bottom,
630*38e8c45fSAndroid Build Coastguard Worker                 reg.getBounds().left, reg.getBounds().top,
631*38e8c45fSAndroid Build Coastguard Worker                 reg.getBounds().right, reg.getBounds().bottom);
632*38e8c45fSAndroid Build Coastguard Worker     }
633*38e8c45fSAndroid Build Coastguard Worker     if (reg.mStorage.size() == 2) {
634*38e8c45fSAndroid Build Coastguard Worker         result = false;
635*38e8c45fSAndroid Build Coastguard Worker         ALOGE_IF(!silent, "%s: mStorage size is 2, which is never valid", name);
636*38e8c45fSAndroid Build Coastguard Worker     }
637*38e8c45fSAndroid Build Coastguard Worker #if defined(VALIDATE_REGIONS)
638*38e8c45fSAndroid Build Coastguard Worker     if (result == false && !silent) {
639*38e8c45fSAndroid Build Coastguard Worker         reg.dump(name);
640*38e8c45fSAndroid Build Coastguard Worker         CallStack stack(LOG_TAG);
641*38e8c45fSAndroid Build Coastguard Worker     }
642*38e8c45fSAndroid Build Coastguard Worker #endif
643*38e8c45fSAndroid Build Coastguard Worker     return result;
644*38e8c45fSAndroid Build Coastguard Worker }
645*38e8c45fSAndroid Build Coastguard Worker 
boolean_operation(uint32_t op,Region & dst,const Region & lhs,const Region & rhs,int dx,int dy)646*38e8c45fSAndroid Build Coastguard Worker void Region::boolean_operation(uint32_t op, Region& dst,
647*38e8c45fSAndroid Build Coastguard Worker         const Region& lhs,
648*38e8c45fSAndroid Build Coastguard Worker         const Region& rhs, int dx, int dy)
649*38e8c45fSAndroid Build Coastguard Worker {
650*38e8c45fSAndroid Build Coastguard Worker #if defined(VALIDATE_REGIONS)
651*38e8c45fSAndroid Build Coastguard Worker     validate(lhs, "boolean_operation (before): lhs");
652*38e8c45fSAndroid Build Coastguard Worker     validate(rhs, "boolean_operation (before): rhs");
653*38e8c45fSAndroid Build Coastguard Worker     validate(dst, "boolean_operation (before): dst");
654*38e8c45fSAndroid Build Coastguard Worker #endif
655*38e8c45fSAndroid Build Coastguard Worker 
656*38e8c45fSAndroid Build Coastguard Worker     size_t lhs_count;
657*38e8c45fSAndroid Build Coastguard Worker     Rect const * const lhs_rects = lhs.getArray(&lhs_count);
658*38e8c45fSAndroid Build Coastguard Worker 
659*38e8c45fSAndroid Build Coastguard Worker     size_t rhs_count;
660*38e8c45fSAndroid Build Coastguard Worker     Rect const * const rhs_rects = rhs.getArray(&rhs_count);
661*38e8c45fSAndroid Build Coastguard Worker 
662*38e8c45fSAndroid Build Coastguard Worker     region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
663*38e8c45fSAndroid Build Coastguard Worker     region_operator<Rect>::region rhs_region(rhs_rects, rhs_count, dx, dy);
664*38e8c45fSAndroid Build Coastguard Worker     region_operator<Rect> operation(op, lhs_region, rhs_region);
665*38e8c45fSAndroid Build Coastguard Worker     { // scope for rasterizer (dtor has side effects)
666*38e8c45fSAndroid Build Coastguard Worker         rasterizer r(dst);
667*38e8c45fSAndroid Build Coastguard Worker         operation(r);
668*38e8c45fSAndroid Build Coastguard Worker     }
669*38e8c45fSAndroid Build Coastguard Worker 
670*38e8c45fSAndroid Build Coastguard Worker #if defined(VALIDATE_REGIONS)
671*38e8c45fSAndroid Build Coastguard Worker     validate(lhs, "boolean_operation: lhs");
672*38e8c45fSAndroid Build Coastguard Worker     validate(rhs, "boolean_operation: rhs");
673*38e8c45fSAndroid Build Coastguard Worker     validate(dst, "boolean_operation: dst");
674*38e8c45fSAndroid Build Coastguard Worker #endif
675*38e8c45fSAndroid Build Coastguard Worker 
676*38e8c45fSAndroid Build Coastguard Worker #if VALIDATE_WITH_CORECG
677*38e8c45fSAndroid Build Coastguard Worker     SkRegion sk_lhs;
678*38e8c45fSAndroid Build Coastguard Worker     SkRegion sk_rhs;
679*38e8c45fSAndroid Build Coastguard Worker     SkRegion sk_dst;
680*38e8c45fSAndroid Build Coastguard Worker 
681*38e8c45fSAndroid Build Coastguard Worker     for (size_t i=0 ; i<lhs_count ; i++)
682*38e8c45fSAndroid Build Coastguard Worker         sk_lhs.op(
683*38e8c45fSAndroid Build Coastguard Worker                 lhs_rects[i].left   + dx,
684*38e8c45fSAndroid Build Coastguard Worker                 lhs_rects[i].top    + dy,
685*38e8c45fSAndroid Build Coastguard Worker                 lhs_rects[i].right  + dx,
686*38e8c45fSAndroid Build Coastguard Worker                 lhs_rects[i].bottom + dy,
687*38e8c45fSAndroid Build Coastguard Worker                 SkRegion::kUnion_Op);
688*38e8c45fSAndroid Build Coastguard Worker 
689*38e8c45fSAndroid Build Coastguard Worker     for (size_t i=0 ; i<rhs_count ; i++)
690*38e8c45fSAndroid Build Coastguard Worker         sk_rhs.op(
691*38e8c45fSAndroid Build Coastguard Worker                 rhs_rects[i].left   + dx,
692*38e8c45fSAndroid Build Coastguard Worker                 rhs_rects[i].top    + dy,
693*38e8c45fSAndroid Build Coastguard Worker                 rhs_rects[i].right  + dx,
694*38e8c45fSAndroid Build Coastguard Worker                 rhs_rects[i].bottom + dy,
695*38e8c45fSAndroid Build Coastguard Worker                 SkRegion::kUnion_Op);
696*38e8c45fSAndroid Build Coastguard Worker 
697*38e8c45fSAndroid Build Coastguard Worker     const char* name = "---";
698*38e8c45fSAndroid Build Coastguard Worker     SkRegion::Op sk_op;
699*38e8c45fSAndroid Build Coastguard Worker     switch (op) {
700*38e8c45fSAndroid Build Coastguard Worker         case op_or: sk_op = SkRegion::kUnion_Op; name="OR"; break;
701*38e8c45fSAndroid Build Coastguard Worker         case op_xor: sk_op = SkRegion::kUnion_XOR; name="XOR"; break;
702*38e8c45fSAndroid Build Coastguard Worker         case op_and: sk_op = SkRegion::kIntersect_Op; name="AND"; break;
703*38e8c45fSAndroid Build Coastguard Worker         case op_nand: sk_op = SkRegion::kDifference_Op; name="NAND"; break;
704*38e8c45fSAndroid Build Coastguard Worker     }
705*38e8c45fSAndroid Build Coastguard Worker     sk_dst.op(sk_lhs, sk_rhs, sk_op);
706*38e8c45fSAndroid Build Coastguard Worker 
707*38e8c45fSAndroid Build Coastguard Worker     if (sk_dst.empty() && dst.empty()) return;
708*38e8c45fSAndroid Build Coastguard Worker 
709*38e8c45fSAndroid Build Coastguard Worker     bool same = true;
710*38e8c45fSAndroid Build Coastguard Worker     Region::const_iterator head = dst.begin();
711*38e8c45fSAndroid Build Coastguard Worker     Region::const_iterator const tail = dst.end();
712*38e8c45fSAndroid Build Coastguard Worker     SkRegion::Iterator it(sk_dst);
713*38e8c45fSAndroid Build Coastguard Worker     while (!it.done()) {
714*38e8c45fSAndroid Build Coastguard Worker         if (head != tail) {
715*38e8c45fSAndroid Build Coastguard Worker             if (
716*38e8c45fSAndroid Build Coastguard Worker                     head->left != it.rect().fLeft ||
717*38e8c45fSAndroid Build Coastguard Worker                     head->top != it.rect().fTop ||
718*38e8c45fSAndroid Build Coastguard Worker                     head->right != it.rect().fRight ||
719*38e8c45fSAndroid Build Coastguard Worker                     head->bottom != it.rect().fBottom
720*38e8c45fSAndroid Build Coastguard Worker             ) {
721*38e8c45fSAndroid Build Coastguard Worker                 same = false;
722*38e8c45fSAndroid Build Coastguard Worker                 break;
723*38e8c45fSAndroid Build Coastguard Worker             }
724*38e8c45fSAndroid Build Coastguard Worker         } else {
725*38e8c45fSAndroid Build Coastguard Worker             same = false;
726*38e8c45fSAndroid Build Coastguard Worker             break;
727*38e8c45fSAndroid Build Coastguard Worker         }
728*38e8c45fSAndroid Build Coastguard Worker         head++;
729*38e8c45fSAndroid Build Coastguard Worker         it.next();
730*38e8c45fSAndroid Build Coastguard Worker     }
731*38e8c45fSAndroid Build Coastguard Worker 
732*38e8c45fSAndroid Build Coastguard Worker     if (head != tail) {
733*38e8c45fSAndroid Build Coastguard Worker         same = false;
734*38e8c45fSAndroid Build Coastguard Worker     }
735*38e8c45fSAndroid Build Coastguard Worker 
736*38e8c45fSAndroid Build Coastguard Worker     if(!same) {
737*38e8c45fSAndroid Build Coastguard Worker         ALOGD("---\nregion boolean %s failed", name);
738*38e8c45fSAndroid Build Coastguard Worker         lhs.dump("lhs");
739*38e8c45fSAndroid Build Coastguard Worker         rhs.dump("rhs");
740*38e8c45fSAndroid Build Coastguard Worker         dst.dump("dst");
741*38e8c45fSAndroid Build Coastguard Worker         ALOGD("should be");
742*38e8c45fSAndroid Build Coastguard Worker         SkRegion::Iterator it(sk_dst);
743*38e8c45fSAndroid Build Coastguard Worker         while (!it.done()) {
744*38e8c45fSAndroid Build Coastguard Worker             ALOGD("    [%3d, %3d, %3d, %3d]",
745*38e8c45fSAndroid Build Coastguard Worker                 it.rect().fLeft,
746*38e8c45fSAndroid Build Coastguard Worker                 it.rect().fTop,
747*38e8c45fSAndroid Build Coastguard Worker                 it.rect().fRight,
748*38e8c45fSAndroid Build Coastguard Worker                 it.rect().fBottom);
749*38e8c45fSAndroid Build Coastguard Worker             it.next();
750*38e8c45fSAndroid Build Coastguard Worker         }
751*38e8c45fSAndroid Build Coastguard Worker     }
752*38e8c45fSAndroid Build Coastguard Worker #endif
753*38e8c45fSAndroid Build Coastguard Worker }
754*38e8c45fSAndroid Build Coastguard Worker 
boolean_operation(uint32_t op,Region & dst,const Region & lhs,const Rect & rhs,int dx,int dy)755*38e8c45fSAndroid Build Coastguard Worker void Region::boolean_operation(uint32_t op, Region& dst,
756*38e8c45fSAndroid Build Coastguard Worker         const Region& lhs,
757*38e8c45fSAndroid Build Coastguard Worker         const Rect& rhs, int dx, int dy)
758*38e8c45fSAndroid Build Coastguard Worker {
759*38e8c45fSAndroid Build Coastguard Worker     // We allow this particular flavor of invalid Rect, since it is used as a
760*38e8c45fSAndroid Build Coastguard Worker     // signal value in various parts of the system
761*38e8c45fSAndroid Build Coastguard Worker     if (!rhs.isValid() && rhs != Rect::INVALID_RECT) {
762*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Region::boolean_operation(op=%d) invalid Rect={%d,%d,%d,%d}",
763*38e8c45fSAndroid Build Coastguard Worker                 op, rhs.left, rhs.top, rhs.right, rhs.bottom);
764*38e8c45fSAndroid Build Coastguard Worker         return;
765*38e8c45fSAndroid Build Coastguard Worker     }
766*38e8c45fSAndroid Build Coastguard Worker 
767*38e8c45fSAndroid Build Coastguard Worker #if VALIDATE_WITH_CORECG || defined(VALIDATE_REGIONS)
768*38e8c45fSAndroid Build Coastguard Worker     boolean_operation(op, dst, lhs, Region(rhs), dx, dy);
769*38e8c45fSAndroid Build Coastguard Worker #else
770*38e8c45fSAndroid Build Coastguard Worker     size_t lhs_count;
771*38e8c45fSAndroid Build Coastguard Worker     Rect const * const lhs_rects = lhs.getArray(&lhs_count);
772*38e8c45fSAndroid Build Coastguard Worker 
773*38e8c45fSAndroid Build Coastguard Worker     region_operator<Rect>::region lhs_region(lhs_rects, lhs_count);
774*38e8c45fSAndroid Build Coastguard Worker     region_operator<Rect>::region rhs_region(&rhs, 1, dx, dy);
775*38e8c45fSAndroid Build Coastguard Worker     region_operator<Rect> operation(op, lhs_region, rhs_region);
776*38e8c45fSAndroid Build Coastguard Worker     { // scope for rasterizer (dtor has side effects)
777*38e8c45fSAndroid Build Coastguard Worker         rasterizer r(dst);
778*38e8c45fSAndroid Build Coastguard Worker         operation(r);
779*38e8c45fSAndroid Build Coastguard Worker     }
780*38e8c45fSAndroid Build Coastguard Worker 
781*38e8c45fSAndroid Build Coastguard Worker #endif
782*38e8c45fSAndroid Build Coastguard Worker }
783*38e8c45fSAndroid Build Coastguard Worker 
boolean_operation(uint32_t op,Region & dst,const Region & lhs,const Region & rhs)784*38e8c45fSAndroid Build Coastguard Worker void Region::boolean_operation(uint32_t op, Region& dst,
785*38e8c45fSAndroid Build Coastguard Worker         const Region& lhs, const Region& rhs)
786*38e8c45fSAndroid Build Coastguard Worker {
787*38e8c45fSAndroid Build Coastguard Worker     boolean_operation(op, dst, lhs, rhs, 0, 0);
788*38e8c45fSAndroid Build Coastguard Worker }
789*38e8c45fSAndroid Build Coastguard Worker 
boolean_operation(uint32_t op,Region & dst,const Region & lhs,const Rect & rhs)790*38e8c45fSAndroid Build Coastguard Worker void Region::boolean_operation(uint32_t op, Region& dst,
791*38e8c45fSAndroid Build Coastguard Worker         const Region& lhs, const Rect& rhs)
792*38e8c45fSAndroid Build Coastguard Worker {
793*38e8c45fSAndroid Build Coastguard Worker     boolean_operation(op, dst, lhs, rhs, 0, 0);
794*38e8c45fSAndroid Build Coastguard Worker }
795*38e8c45fSAndroid Build Coastguard Worker 
translate(Region & reg,int dx,int dy)796*38e8c45fSAndroid Build Coastguard Worker void Region::translate(Region& reg, int dx, int dy)
797*38e8c45fSAndroid Build Coastguard Worker {
798*38e8c45fSAndroid Build Coastguard Worker     if ((dx || dy) && !reg.isEmpty()) {
799*38e8c45fSAndroid Build Coastguard Worker #if defined(VALIDATE_REGIONS)
800*38e8c45fSAndroid Build Coastguard Worker         validate(reg, "translate (before)");
801*38e8c45fSAndroid Build Coastguard Worker #endif
802*38e8c45fSAndroid Build Coastguard Worker         size_t count = reg.mStorage.size();
803*38e8c45fSAndroid Build Coastguard Worker         Rect* rects = reg.mStorage.data();
804*38e8c45fSAndroid Build Coastguard Worker         while (count) {
805*38e8c45fSAndroid Build Coastguard Worker             rects->offsetBy(dx, dy);
806*38e8c45fSAndroid Build Coastguard Worker             rects++;
807*38e8c45fSAndroid Build Coastguard Worker             count--;
808*38e8c45fSAndroid Build Coastguard Worker         }
809*38e8c45fSAndroid Build Coastguard Worker #if defined(VALIDATE_REGIONS)
810*38e8c45fSAndroid Build Coastguard Worker         validate(reg, "translate (after)");
811*38e8c45fSAndroid Build Coastguard Worker #endif
812*38e8c45fSAndroid Build Coastguard Worker     }
813*38e8c45fSAndroid Build Coastguard Worker }
814*38e8c45fSAndroid Build Coastguard Worker 
translate(Region & dst,const Region & reg,int dx,int dy)815*38e8c45fSAndroid Build Coastguard Worker void Region::translate(Region& dst, const Region& reg, int dx, int dy)
816*38e8c45fSAndroid Build Coastguard Worker {
817*38e8c45fSAndroid Build Coastguard Worker     dst = reg;
818*38e8c45fSAndroid Build Coastguard Worker     translate(dst, dx, dy);
819*38e8c45fSAndroid Build Coastguard Worker }
820*38e8c45fSAndroid Build Coastguard Worker 
821*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
822*38e8c45fSAndroid Build Coastguard Worker 
getFlattenedSize() const823*38e8c45fSAndroid Build Coastguard Worker size_t Region::getFlattenedSize() const {
824*38e8c45fSAndroid Build Coastguard Worker     return sizeof(uint32_t) + mStorage.size() * sizeof(Rect);
825*38e8c45fSAndroid Build Coastguard Worker }
826*38e8c45fSAndroid Build Coastguard Worker 
flatten(void * buffer,size_t size) const827*38e8c45fSAndroid Build Coastguard Worker status_t Region::flatten(void* buffer, size_t size) const {
828*38e8c45fSAndroid Build Coastguard Worker #if defined(VALIDATE_REGIONS)
829*38e8c45fSAndroid Build Coastguard Worker     validate(*this, "Region::flatten");
830*38e8c45fSAndroid Build Coastguard Worker #endif
831*38e8c45fSAndroid Build Coastguard Worker     if (size < getFlattenedSize()) {
832*38e8c45fSAndroid Build Coastguard Worker         return NO_MEMORY;
833*38e8c45fSAndroid Build Coastguard Worker     }
834*38e8c45fSAndroid Build Coastguard Worker     // Cast to uint32_t since the size of a size_t can vary between 32- and
835*38e8c45fSAndroid Build Coastguard Worker     // 64-bit processes
836*38e8c45fSAndroid Build Coastguard Worker     FlattenableUtils::write(buffer, size, static_cast<uint32_t>(mStorage.size()));
837*38e8c45fSAndroid Build Coastguard Worker     for (auto rect : mStorage) {
838*38e8c45fSAndroid Build Coastguard Worker         status_t result = rect.flatten(buffer, size);
839*38e8c45fSAndroid Build Coastguard Worker         if (result != NO_ERROR) {
840*38e8c45fSAndroid Build Coastguard Worker             return result;
841*38e8c45fSAndroid Build Coastguard Worker         }
842*38e8c45fSAndroid Build Coastguard Worker         FlattenableUtils::advance(buffer, size, sizeof(rect));
843*38e8c45fSAndroid Build Coastguard Worker     }
844*38e8c45fSAndroid Build Coastguard Worker     return NO_ERROR;
845*38e8c45fSAndroid Build Coastguard Worker }
846*38e8c45fSAndroid Build Coastguard Worker 
unflatten(void const * buffer,size_t size)847*38e8c45fSAndroid Build Coastguard Worker status_t Region::unflatten(void const* buffer, size_t size) {
848*38e8c45fSAndroid Build Coastguard Worker     if (size < sizeof(uint32_t)) {
849*38e8c45fSAndroid Build Coastguard Worker         return NO_MEMORY;
850*38e8c45fSAndroid Build Coastguard Worker     }
851*38e8c45fSAndroid Build Coastguard Worker 
852*38e8c45fSAndroid Build Coastguard Worker     uint32_t numRects = 0;
853*38e8c45fSAndroid Build Coastguard Worker     FlattenableUtils::read(buffer, size, numRects);
854*38e8c45fSAndroid Build Coastguard Worker     if (size < numRects * sizeof(Rect)) {
855*38e8c45fSAndroid Build Coastguard Worker         return NO_MEMORY;
856*38e8c45fSAndroid Build Coastguard Worker     }
857*38e8c45fSAndroid Build Coastguard Worker 
858*38e8c45fSAndroid Build Coastguard Worker     if (numRects > (UINT32_MAX / sizeof(Rect))) {
859*38e8c45fSAndroid Build Coastguard Worker         android_errorWriteWithInfoLog(0x534e4554, "29983260", -1, nullptr, 0);
860*38e8c45fSAndroid Build Coastguard Worker         return NO_MEMORY;
861*38e8c45fSAndroid Build Coastguard Worker     }
862*38e8c45fSAndroid Build Coastguard Worker 
863*38e8c45fSAndroid Build Coastguard Worker     Region result;
864*38e8c45fSAndroid Build Coastguard Worker     result.mStorage.clear();
865*38e8c45fSAndroid Build Coastguard Worker     for (size_t r = 0; r < numRects; ++r) {
866*38e8c45fSAndroid Build Coastguard Worker         Rect rect(Rect::EMPTY_RECT);
867*38e8c45fSAndroid Build Coastguard Worker         status_t status = rect.unflatten(buffer, size);
868*38e8c45fSAndroid Build Coastguard Worker         if (status != NO_ERROR) {
869*38e8c45fSAndroid Build Coastguard Worker             return status;
870*38e8c45fSAndroid Build Coastguard Worker         }
871*38e8c45fSAndroid Build Coastguard Worker         FlattenableUtils::advance(buffer, size, sizeof(rect));
872*38e8c45fSAndroid Build Coastguard Worker         result.mStorage.push_back(rect);
873*38e8c45fSAndroid Build Coastguard Worker     }
874*38e8c45fSAndroid Build Coastguard Worker 
875*38e8c45fSAndroid Build Coastguard Worker #if defined(VALIDATE_REGIONS)
876*38e8c45fSAndroid Build Coastguard Worker     validate(result, "Region::unflatten");
877*38e8c45fSAndroid Build Coastguard Worker #endif
878*38e8c45fSAndroid Build Coastguard Worker 
879*38e8c45fSAndroid Build Coastguard Worker     if (!result.validate(result, "Region::unflatten", true)) {
880*38e8c45fSAndroid Build Coastguard Worker         ALOGE("Region::unflatten() failed, invalid region");
881*38e8c45fSAndroid Build Coastguard Worker         return BAD_VALUE;
882*38e8c45fSAndroid Build Coastguard Worker     }
883*38e8c45fSAndroid Build Coastguard Worker     mStorage.clear();
884*38e8c45fSAndroid Build Coastguard Worker     mStorage.insert(mStorage.begin(), result.mStorage.begin(), result.mStorage.end());
885*38e8c45fSAndroid Build Coastguard Worker     return NO_ERROR;
886*38e8c45fSAndroid Build Coastguard Worker }
887*38e8c45fSAndroid Build Coastguard Worker 
888*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
889*38e8c45fSAndroid Build Coastguard Worker 
begin() const890*38e8c45fSAndroid Build Coastguard Worker Region::const_iterator Region::begin() const {
891*38e8c45fSAndroid Build Coastguard Worker     return mStorage.data();
892*38e8c45fSAndroid Build Coastguard Worker }
893*38e8c45fSAndroid Build Coastguard Worker 
end() const894*38e8c45fSAndroid Build Coastguard Worker Region::const_iterator Region::end() const {
895*38e8c45fSAndroid Build Coastguard Worker     // Workaround for b/77643177
896*38e8c45fSAndroid Build Coastguard Worker     // mStorage should never be empty, but somehow it is and it's causing
897*38e8c45fSAndroid Build Coastguard Worker     // an abort in ubsan
898*38e8c45fSAndroid Build Coastguard Worker     if (mStorage.empty()) return mStorage.data();
899*38e8c45fSAndroid Build Coastguard Worker 
900*38e8c45fSAndroid Build Coastguard Worker     size_t numRects = isRect() ? 1 : mStorage.size() - 1;
901*38e8c45fSAndroid Build Coastguard Worker     return mStorage.data() + numRects;
902*38e8c45fSAndroid Build Coastguard Worker }
903*38e8c45fSAndroid Build Coastguard Worker 
getArray(size_t * count) const904*38e8c45fSAndroid Build Coastguard Worker Rect const* Region::getArray(size_t* count) const {
905*38e8c45fSAndroid Build Coastguard Worker     if (count) *count = static_cast<size_t>(end() - begin());
906*38e8c45fSAndroid Build Coastguard Worker     return begin();
907*38e8c45fSAndroid Build Coastguard Worker }
908*38e8c45fSAndroid Build Coastguard Worker 
909*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
910*38e8c45fSAndroid Build Coastguard Worker 
dump(std::string & out,const char * what,uint32_t) const911*38e8c45fSAndroid Build Coastguard Worker void Region::dump(std::string& out, const char* what, uint32_t /* flags */) const {
912*38e8c45fSAndroid Build Coastguard Worker     const_iterator head = begin();
913*38e8c45fSAndroid Build Coastguard Worker     const_iterator const tail = end();
914*38e8c45fSAndroid Build Coastguard Worker 
915*38e8c45fSAndroid Build Coastguard Worker     StringAppendF(&out, "  Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail - head);
916*38e8c45fSAndroid Build Coastguard Worker     while (head != tail) {
917*38e8c45fSAndroid Build Coastguard Worker         StringAppendF(&out, "    [%3d, %3d, %3d, %3d]\n", head->left, head->top, head->right,
918*38e8c45fSAndroid Build Coastguard Worker                       head->bottom);
919*38e8c45fSAndroid Build Coastguard Worker         ++head;
920*38e8c45fSAndroid Build Coastguard Worker     }
921*38e8c45fSAndroid Build Coastguard Worker }
922*38e8c45fSAndroid Build Coastguard Worker 
dump(const char * what,uint32_t) const923*38e8c45fSAndroid Build Coastguard Worker void Region::dump(const char* what, uint32_t /* flags */) const
924*38e8c45fSAndroid Build Coastguard Worker {
925*38e8c45fSAndroid Build Coastguard Worker     const_iterator head = begin();
926*38e8c45fSAndroid Build Coastguard Worker     const_iterator const tail = end();
927*38e8c45fSAndroid Build Coastguard Worker     ALOGD("  Region %s (this=%p, count=%" PRIdPTR ")\n", what, this, tail-head);
928*38e8c45fSAndroid Build Coastguard Worker     while (head != tail) {
929*38e8c45fSAndroid Build Coastguard Worker         ALOGD("    [%3d, %3d, %3d, %3d]\n",
930*38e8c45fSAndroid Build Coastguard Worker                 head->left, head->top, head->right, head->bottom);
931*38e8c45fSAndroid Build Coastguard Worker         head++;
932*38e8c45fSAndroid Build Coastguard Worker     }
933*38e8c45fSAndroid Build Coastguard Worker }
934*38e8c45fSAndroid Build Coastguard Worker 
935*38e8c45fSAndroid Build Coastguard Worker // ----------------------------------------------------------------------------
936*38e8c45fSAndroid Build Coastguard Worker 
937*38e8c45fSAndroid Build Coastguard Worker }; // namespace android
938