xref: /aosp_15_r20/frameworks/base/libs/hwui/Rect.h (revision d57664e9bc4670b3ecf6748a746a57c557b6bc9e)
1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker  * Copyright (C) 2010 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker  *
4*d57664e9SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker  *
8*d57664e9SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker  *
10*d57664e9SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker  * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker  */
16*d57664e9SAndroid Build Coastguard Worker 
17*d57664e9SAndroid Build Coastguard Worker #pragma once
18*d57664e9SAndroid Build Coastguard Worker 
19*d57664e9SAndroid Build Coastguard Worker #include "Vertex.h"
20*d57664e9SAndroid Build Coastguard Worker 
21*d57664e9SAndroid Build Coastguard Worker #include <utils/Log.h>
22*d57664e9SAndroid Build Coastguard Worker 
23*d57664e9SAndroid Build Coastguard Worker #include <SkRect.h>
24*d57664e9SAndroid Build Coastguard Worker #include <algorithm>
25*d57664e9SAndroid Build Coastguard Worker #include <cmath>
26*d57664e9SAndroid Build Coastguard Worker #include <iomanip>
27*d57664e9SAndroid Build Coastguard Worker #include <ostream>
28*d57664e9SAndroid Build Coastguard Worker 
29*d57664e9SAndroid Build Coastguard Worker namespace android {
30*d57664e9SAndroid Build Coastguard Worker namespace uirenderer {
31*d57664e9SAndroid Build Coastguard Worker 
32*d57664e9SAndroid Build Coastguard Worker #define RECT_STRING "%5.2f %5.2f %5.2f %5.2f"
33*d57664e9SAndroid Build Coastguard Worker #define RECT_ARGS(r) (r).left, (r).top, (r).right, (r).bottom
34*d57664e9SAndroid Build Coastguard Worker #define SK_RECT_ARGS(r) (r).left(), (r).top(), (r).right(), (r).bottom()
35*d57664e9SAndroid Build Coastguard Worker 
36*d57664e9SAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
37*d57664e9SAndroid Build Coastguard Worker // Structs
38*d57664e9SAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
39*d57664e9SAndroid Build Coastguard Worker 
40*d57664e9SAndroid Build Coastguard Worker class Rect {
41*d57664e9SAndroid Build Coastguard Worker public:
42*d57664e9SAndroid Build Coastguard Worker     float left;
43*d57664e9SAndroid Build Coastguard Worker     float top;
44*d57664e9SAndroid Build Coastguard Worker     float right;
45*d57664e9SAndroid Build Coastguard Worker     float bottom;
46*d57664e9SAndroid Build Coastguard Worker 
47*d57664e9SAndroid Build Coastguard Worker     // Used by Region
48*d57664e9SAndroid Build Coastguard Worker     typedef float value_type;
49*d57664e9SAndroid Build Coastguard Worker 
50*d57664e9SAndroid Build Coastguard Worker     // we don't provide copy-ctor and operator= on purpose
51*d57664e9SAndroid Build Coastguard Worker     // because we want the compiler generated versions
52*d57664e9SAndroid Build Coastguard Worker 
Rect()53*d57664e9SAndroid Build Coastguard Worker     inline Rect() : left(0), top(0), right(0), bottom(0) {}
54*d57664e9SAndroid Build Coastguard Worker 
Rect(float left,float top,float right,float bottom)55*d57664e9SAndroid Build Coastguard Worker     inline Rect(float left, float top, float right, float bottom)
56*d57664e9SAndroid Build Coastguard Worker             : left(left), top(top), right(right), bottom(bottom) {}
57*d57664e9SAndroid Build Coastguard Worker 
Rect(float width,float height)58*d57664e9SAndroid Build Coastguard Worker     inline Rect(float width, float height) : left(0.0f), top(0.0f), right(width), bottom(height) {}
59*d57664e9SAndroid Build Coastguard Worker 
Rect(const SkIRect & rect)60*d57664e9SAndroid Build Coastguard Worker     inline Rect(const SkIRect& rect) // NOLINT(google-explicit-constructor)
61*d57664e9SAndroid Build Coastguard Worker             :
62*d57664e9SAndroid Build Coastguard Worker             left(rect.fLeft)
63*d57664e9SAndroid Build Coastguard Worker             , top(rect.fTop)
64*d57664e9SAndroid Build Coastguard Worker             , right(rect.fRight)
65*d57664e9SAndroid Build Coastguard Worker             , bottom(rect.fBottom) {}
66*d57664e9SAndroid Build Coastguard Worker 
Rect(const SkRect & rect)67*d57664e9SAndroid Build Coastguard Worker     inline Rect(const SkRect& rect) // NOLINT(google-explicit-constructor)
68*d57664e9SAndroid Build Coastguard Worker             :
69*d57664e9SAndroid Build Coastguard Worker             left(rect.fLeft)
70*d57664e9SAndroid Build Coastguard Worker             , top(rect.fTop)
71*d57664e9SAndroid Build Coastguard Worker             , right(rect.fRight)
72*d57664e9SAndroid Build Coastguard Worker             , bottom(rect.fBottom) {}
73*d57664e9SAndroid Build Coastguard Worker 
74*d57664e9SAndroid Build Coastguard Worker     friend int operator==(const Rect& a, const Rect& b) {
75*d57664e9SAndroid Build Coastguard Worker         return a.left == b.left &&
76*d57664e9SAndroid Build Coastguard Worker                a.top == b.top &&
77*d57664e9SAndroid Build Coastguard Worker                a.right == b.right &&
78*d57664e9SAndroid Build Coastguard Worker                a.bottom == b.bottom;
79*d57664e9SAndroid Build Coastguard Worker     }
80*d57664e9SAndroid Build Coastguard Worker 
81*d57664e9SAndroid Build Coastguard Worker     friend int operator!=(const Rect& a, const Rect& b) { return !(a == b); }
82*d57664e9SAndroid Build Coastguard Worker 
clear()83*d57664e9SAndroid Build Coastguard Worker     inline void clear() { left = top = right = bottom = 0.0f; }
84*d57664e9SAndroid Build Coastguard Worker 
isEmpty()85*d57664e9SAndroid Build Coastguard Worker     inline bool isEmpty() const {
86*d57664e9SAndroid Build Coastguard Worker         // this is written in such way this it'll handle NANs to return
87*d57664e9SAndroid Build Coastguard Worker         // true (empty)
88*d57664e9SAndroid Build Coastguard Worker         return !((left < right) && (top < bottom));
89*d57664e9SAndroid Build Coastguard Worker     }
90*d57664e9SAndroid Build Coastguard Worker 
setEmpty()91*d57664e9SAndroid Build Coastguard Worker     inline void setEmpty() { left = top = right = bottom = 0.0f; }
92*d57664e9SAndroid Build Coastguard Worker 
set(float left,float top,float right,float bottom)93*d57664e9SAndroid Build Coastguard Worker     inline void set(float left, float top, float right, float bottom) {
94*d57664e9SAndroid Build Coastguard Worker         this->left = left;
95*d57664e9SAndroid Build Coastguard Worker         this->right = right;
96*d57664e9SAndroid Build Coastguard Worker         this->top = top;
97*d57664e9SAndroid Build Coastguard Worker         this->bottom = bottom;
98*d57664e9SAndroid Build Coastguard Worker     }
99*d57664e9SAndroid Build Coastguard Worker 
set(const Rect & r)100*d57664e9SAndroid Build Coastguard Worker     inline void set(const Rect& r) { set(r.left, r.top, r.right, r.bottom); }
101*d57664e9SAndroid Build Coastguard Worker 
set(const SkIRect & r)102*d57664e9SAndroid Build Coastguard Worker     inline void set(const SkIRect& r) { set(r.left(), r.top(), r.right(), r.bottom()); }
103*d57664e9SAndroid Build Coastguard Worker 
getWidth()104*d57664e9SAndroid Build Coastguard Worker     inline float getWidth() const { return right - left; }
105*d57664e9SAndroid Build Coastguard Worker 
getHeight()106*d57664e9SAndroid Build Coastguard Worker     inline float getHeight() const { return bottom - top; }
107*d57664e9SAndroid Build Coastguard Worker 
intersects(float l,float t,float r,float b)108*d57664e9SAndroid Build Coastguard Worker     bool intersects(float l, float t, float r, float b) const {
109*d57664e9SAndroid Build Coastguard Worker         float tempLeft = std::max(left, l);
110*d57664e9SAndroid Build Coastguard Worker         float tempTop = std::max(top, t);
111*d57664e9SAndroid Build Coastguard Worker         float tempRight = std::min(right, r);
112*d57664e9SAndroid Build Coastguard Worker         float tempBottom = std::min(bottom, b);
113*d57664e9SAndroid Build Coastguard Worker 
114*d57664e9SAndroid Build Coastguard Worker         return ((tempLeft < tempRight) && (tempTop < tempBottom));  // !isEmpty
115*d57664e9SAndroid Build Coastguard Worker     }
116*d57664e9SAndroid Build Coastguard Worker 
intersects(const Rect & r)117*d57664e9SAndroid Build Coastguard Worker     bool intersects(const Rect& r) const { return intersects(r.left, r.top, r.right, r.bottom); }
118*d57664e9SAndroid Build Coastguard Worker 
119*d57664e9SAndroid Build Coastguard Worker     /**
120*d57664e9SAndroid Build Coastguard Worker      * This method is named 'doIntersect' instead of 'intersect' so as not to be confused with
121*d57664e9SAndroid Build Coastguard Worker      * SkRect::intersect / android.graphics.Rect#intersect behavior, which do not modify the object
122*d57664e9SAndroid Build Coastguard Worker      * if the intersection of the rects would be empty.
123*d57664e9SAndroid Build Coastguard Worker      */
doIntersect(float l,float t,float r,float b)124*d57664e9SAndroid Build Coastguard Worker     void doIntersect(float l, float t, float r, float b) {
125*d57664e9SAndroid Build Coastguard Worker         left = std::max(left, l);
126*d57664e9SAndroid Build Coastguard Worker         top = std::max(top, t);
127*d57664e9SAndroid Build Coastguard Worker         right = std::min(right, r);
128*d57664e9SAndroid Build Coastguard Worker         bottom = std::min(bottom, b);
129*d57664e9SAndroid Build Coastguard Worker     }
130*d57664e9SAndroid Build Coastguard Worker 
doIntersect(const Rect & r)131*d57664e9SAndroid Build Coastguard Worker     void doIntersect(const Rect& r) { doIntersect(r.left, r.top, r.right, r.bottom); }
132*d57664e9SAndroid Build Coastguard Worker 
contains(float l,float t,float r,float b)133*d57664e9SAndroid Build Coastguard Worker     inline bool contains(float l, float t, float r, float b) const {
134*d57664e9SAndroid Build Coastguard Worker         return l >= left && t >= top && r <= right && b <= bottom;
135*d57664e9SAndroid Build Coastguard Worker     }
136*d57664e9SAndroid Build Coastguard Worker 
contains(const Rect & r)137*d57664e9SAndroid Build Coastguard Worker     inline bool contains(const Rect& r) const { return contains(r.left, r.top, r.right, r.bottom); }
138*d57664e9SAndroid Build Coastguard Worker 
unionWith(const Rect & r)139*d57664e9SAndroid Build Coastguard Worker     bool unionWith(const Rect& r) {
140*d57664e9SAndroid Build Coastguard Worker         if (r.left < r.right && r.top < r.bottom) {
141*d57664e9SAndroid Build Coastguard Worker             if (left < right && top < bottom) {
142*d57664e9SAndroid Build Coastguard Worker                 if (left > r.left) left = r.left;
143*d57664e9SAndroid Build Coastguard Worker                 if (top > r.top) top = r.top;
144*d57664e9SAndroid Build Coastguard Worker                 if (right < r.right) right = r.right;
145*d57664e9SAndroid Build Coastguard Worker                 if (bottom < r.bottom) bottom = r.bottom;
146*d57664e9SAndroid Build Coastguard Worker                 return true;
147*d57664e9SAndroid Build Coastguard Worker             } else {
148*d57664e9SAndroid Build Coastguard Worker                 left = r.left;
149*d57664e9SAndroid Build Coastguard Worker                 top = r.top;
150*d57664e9SAndroid Build Coastguard Worker                 right = r.right;
151*d57664e9SAndroid Build Coastguard Worker                 bottom = r.bottom;
152*d57664e9SAndroid Build Coastguard Worker                 return true;
153*d57664e9SAndroid Build Coastguard Worker             }
154*d57664e9SAndroid Build Coastguard Worker         }
155*d57664e9SAndroid Build Coastguard Worker         return false;
156*d57664e9SAndroid Build Coastguard Worker     }
157*d57664e9SAndroid Build Coastguard Worker 
translate(float dx,float dy)158*d57664e9SAndroid Build Coastguard Worker     void translate(float dx, float dy) {
159*d57664e9SAndroid Build Coastguard Worker         left += dx;
160*d57664e9SAndroid Build Coastguard Worker         right += dx;
161*d57664e9SAndroid Build Coastguard Worker         top += dy;
162*d57664e9SAndroid Build Coastguard Worker         bottom += dy;
163*d57664e9SAndroid Build Coastguard Worker     }
164*d57664e9SAndroid Build Coastguard Worker 
inset(float delta)165*d57664e9SAndroid Build Coastguard Worker     void inset(float delta) { outset(-delta); }
166*d57664e9SAndroid Build Coastguard Worker 
outset(float delta)167*d57664e9SAndroid Build Coastguard Worker     void outset(float delta) {
168*d57664e9SAndroid Build Coastguard Worker         left -= delta;
169*d57664e9SAndroid Build Coastguard Worker         top -= delta;
170*d57664e9SAndroid Build Coastguard Worker         right += delta;
171*d57664e9SAndroid Build Coastguard Worker         bottom += delta;
172*d57664e9SAndroid Build Coastguard Worker     }
173*d57664e9SAndroid Build Coastguard Worker 
outset(float xdelta,float ydelta)174*d57664e9SAndroid Build Coastguard Worker     void outset(float xdelta, float ydelta) {
175*d57664e9SAndroid Build Coastguard Worker         left -= xdelta;
176*d57664e9SAndroid Build Coastguard Worker         top -= ydelta;
177*d57664e9SAndroid Build Coastguard Worker         right += xdelta;
178*d57664e9SAndroid Build Coastguard Worker         bottom += ydelta;
179*d57664e9SAndroid Build Coastguard Worker     }
180*d57664e9SAndroid Build Coastguard Worker 
181*d57664e9SAndroid Build Coastguard Worker     /**
182*d57664e9SAndroid Build Coastguard Worker      * Similar to snapToPixelBoundaries, but estimates bounds conservatively to handle GL rounding
183*d57664e9SAndroid Build Coastguard Worker      * errors.
184*d57664e9SAndroid Build Coastguard Worker      *
185*d57664e9SAndroid Build Coastguard Worker      * This function should be used whenever estimating the damage rect of geometry already mapped
186*d57664e9SAndroid Build Coastguard Worker      * into layer space.
187*d57664e9SAndroid Build Coastguard Worker      */
snapGeometryToPixelBoundaries(bool snapOut)188*d57664e9SAndroid Build Coastguard Worker     void snapGeometryToPixelBoundaries(bool snapOut) {
189*d57664e9SAndroid Build Coastguard Worker         if (snapOut) {
190*d57664e9SAndroid Build Coastguard Worker             /* For AA geometry with a ramp perimeter, don't snap by rounding - AA geometry will have
191*d57664e9SAndroid Build Coastguard Worker              * a 0.5 pixel perimeter not accounted for in its bounds. Instead, snap by
192*d57664e9SAndroid Build Coastguard Worker              * conservatively rounding out the bounds with floor/ceil.
193*d57664e9SAndroid Build Coastguard Worker              *
194*d57664e9SAndroid Build Coastguard Worker              * In order to avoid changing integer bounds with floor/ceil due to rounding errors
195*d57664e9SAndroid Build Coastguard Worker              * inset the bounds first by the fudge factor. Very small fraction-of-a-pixel errors
196*d57664e9SAndroid Build Coastguard Worker              * from this inset will only incur similarly small errors in output, due to transparency
197*d57664e9SAndroid Build Coastguard Worker              * in extreme outside of the geometry.
198*d57664e9SAndroid Build Coastguard Worker              */
199*d57664e9SAndroid Build Coastguard Worker             left = floorf(left + Vertex::GeometryFudgeFactor());
200*d57664e9SAndroid Build Coastguard Worker             top = floorf(top + Vertex::GeometryFudgeFactor());
201*d57664e9SAndroid Build Coastguard Worker             right = ceilf(right - Vertex::GeometryFudgeFactor());
202*d57664e9SAndroid Build Coastguard Worker             bottom = ceilf(bottom - Vertex::GeometryFudgeFactor());
203*d57664e9SAndroid Build Coastguard Worker         } else {
204*d57664e9SAndroid Build Coastguard Worker             /* For other geometry, we do the regular rounding in order to snap, but also outset the
205*d57664e9SAndroid Build Coastguard Worker              * bounds by a fudge factor. This ensures that ambiguous geometry (e.g. a non-AA Rect
206*d57664e9SAndroid Build Coastguard Worker              * with top left at (0.5, 0.5)) will err on the side of a larger damage rect.
207*d57664e9SAndroid Build Coastguard Worker              */
208*d57664e9SAndroid Build Coastguard Worker             left = floorf(left + 0.5f - Vertex::GeometryFudgeFactor());
209*d57664e9SAndroid Build Coastguard Worker             top = floorf(top + 0.5f - Vertex::GeometryFudgeFactor());
210*d57664e9SAndroid Build Coastguard Worker             right = floorf(right + 0.5f + Vertex::GeometryFudgeFactor());
211*d57664e9SAndroid Build Coastguard Worker             bottom = floorf(bottom + 0.5f + Vertex::GeometryFudgeFactor());
212*d57664e9SAndroid Build Coastguard Worker         }
213*d57664e9SAndroid Build Coastguard Worker     }
214*d57664e9SAndroid Build Coastguard Worker 
snapToPixelBoundaries()215*d57664e9SAndroid Build Coastguard Worker     void snapToPixelBoundaries() {
216*d57664e9SAndroid Build Coastguard Worker         left = floorf(left + 0.5f);
217*d57664e9SAndroid Build Coastguard Worker         top = floorf(top + 0.5f);
218*d57664e9SAndroid Build Coastguard Worker         right = floorf(right + 0.5f);
219*d57664e9SAndroid Build Coastguard Worker         bottom = floorf(bottom + 0.5f);
220*d57664e9SAndroid Build Coastguard Worker     }
221*d57664e9SAndroid Build Coastguard Worker 
roundOut()222*d57664e9SAndroid Build Coastguard Worker     void roundOut() {
223*d57664e9SAndroid Build Coastguard Worker         left = floorf(left);
224*d57664e9SAndroid Build Coastguard Worker         top = floorf(top);
225*d57664e9SAndroid Build Coastguard Worker         right = ceilf(right);
226*d57664e9SAndroid Build Coastguard Worker         bottom = ceilf(bottom);
227*d57664e9SAndroid Build Coastguard Worker     }
228*d57664e9SAndroid Build Coastguard Worker 
229*d57664e9SAndroid Build Coastguard Worker     /*
230*d57664e9SAndroid Build Coastguard Worker      * Similar to unionWith, except this makes the assumption that both rects are non-empty
231*d57664e9SAndroid Build Coastguard Worker      * to avoid both emptiness checks.
232*d57664e9SAndroid Build Coastguard Worker      */
expandToCover(const Rect & other)233*d57664e9SAndroid Build Coastguard Worker     void expandToCover(const Rect& other) {
234*d57664e9SAndroid Build Coastguard Worker         left = std::min(left, other.left);
235*d57664e9SAndroid Build Coastguard Worker         top = std::min(top, other.top);
236*d57664e9SAndroid Build Coastguard Worker         right = std::max(right, other.right);
237*d57664e9SAndroid Build Coastguard Worker         bottom = std::max(bottom, other.bottom);
238*d57664e9SAndroid Build Coastguard Worker     }
239*d57664e9SAndroid Build Coastguard Worker 
expandToCover(float x,float y)240*d57664e9SAndroid Build Coastguard Worker     void expandToCover(float x, float y) {
241*d57664e9SAndroid Build Coastguard Worker         left = std::min(left, x);
242*d57664e9SAndroid Build Coastguard Worker         top = std::min(top, y);
243*d57664e9SAndroid Build Coastguard Worker         right = std::max(right, x);
244*d57664e9SAndroid Build Coastguard Worker         bottom = std::max(bottom, y);
245*d57664e9SAndroid Build Coastguard Worker     }
246*d57664e9SAndroid Build Coastguard Worker 
toSkRect()247*d57664e9SAndroid Build Coastguard Worker     SkRect toSkRect() const { return SkRect::MakeLTRB(left, top, right, bottom); }
248*d57664e9SAndroid Build Coastguard Worker 
toSkIRect()249*d57664e9SAndroid Build Coastguard Worker     SkIRect toSkIRect() const { return SkIRect::MakeLTRB(left, top, right, bottom); }
250*d57664e9SAndroid Build Coastguard Worker 
251*d57664e9SAndroid Build Coastguard Worker     void dump(const char* label = nullptr) const {
252*d57664e9SAndroid Build Coastguard Worker         ALOGD("%s[l=%.2f t=%.2f r=%.2f b=%.2f]", label ? label : "Rect", left, top, right, bottom);
253*d57664e9SAndroid Build Coastguard Worker     }
254*d57664e9SAndroid Build Coastguard Worker 
255*d57664e9SAndroid Build Coastguard Worker     friend std::ostream& operator<<(std::ostream& os, const Rect& rect) {
256*d57664e9SAndroid Build Coastguard Worker         if (rect.isEmpty()) {
257*d57664e9SAndroid Build Coastguard Worker             // Print empty, but continue, since empty rects may still have useful coordinate info
258*d57664e9SAndroid Build Coastguard Worker             os << "(empty)";
259*d57664e9SAndroid Build Coastguard Worker         }
260*d57664e9SAndroid Build Coastguard Worker 
261*d57664e9SAndroid Build Coastguard Worker         if (rect.left == 0 && rect.top == 0) {
262*d57664e9SAndroid Build Coastguard Worker             return os << "[" << rect.right << " x " << rect.bottom << "]";
263*d57664e9SAndroid Build Coastguard Worker         }
264*d57664e9SAndroid Build Coastguard Worker 
265*d57664e9SAndroid Build Coastguard Worker         return os << "[" << rect.left << " " << rect.top << " " << rect.right << " " << rect.bottom
266*d57664e9SAndroid Build Coastguard Worker                   << "]";
267*d57664e9SAndroid Build Coastguard Worker     }
268*d57664e9SAndroid Build Coastguard Worker };  // class Rect
269*d57664e9SAndroid Build Coastguard Worker 
270*d57664e9SAndroid Build Coastguard Worker }  // namespace uirenderer
271*d57664e9SAndroid Build Coastguard Worker }  // namespace android
272