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