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 #ifndef ANDROID_HWUI_RECT_H 18 #define ANDROID_HWUI_RECT_H 19 20 #include <cmath> 21 22 #include <utils/Log.h> 23 24 #include "Vertex.h" 25 26 namespace android { 27 namespace uirenderer { 28 29 #define RECT_STRING "%7.2f %7.2f %7.2f %7.2f" 30 #define RECT_ARGS(r) \ 31 (r).left, (r).top, (r).right, (r).bottom 32 33 /////////////////////////////////////////////////////////////////////////////// 34 // Structs 35 /////////////////////////////////////////////////////////////////////////////// 36 37 class Rect { 38 public: 39 float left; 40 float top; 41 float right; 42 float bottom; 43 44 // Used by Region 45 typedef float value_type; 46 47 // we don't provide copy-ctor and operator= on purpose 48 // because we want the compiler generated versions 49 50 inline Rect(): 51 left(0), 52 top(0), 53 right(0), 54 bottom(0) { 55 } 56 57 inline Rect(float left, float top, float right, float bottom): 58 left(left), 59 top(top), 60 right(right), 61 bottom(bottom) { 62 } 63 64 inline Rect(float width, float height): 65 left(0.0f), 66 top(0.0f), 67 right(width), 68 bottom(height) { 69 } 70 71 friend int operator==(const Rect& a, const Rect& b) { 72 return !memcmp(&a, &b, sizeof(a)); 73 } 74 75 friend int operator!=(const Rect& a, const Rect& b) { 76 return memcmp(&a, &b, sizeof(a)); 77 } 78 79 inline void clear() { 80 left = top = right = bottom = 0.0f; 81 } 82 83 inline bool isEmpty() const { 84 // this is written in such way this it'll handle NANs to return 85 // true (empty) 86 return !((left < right) && (top < bottom)); 87 } 88 89 inline void setEmpty() { 90 left = top = right = bottom = 0.0f; 91 } 92 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 100 inline void set(const Rect& r) { 101 set(r.left, r.top, r.right, r.bottom); 102 } 103 104 inline float getWidth() const { 105 return right - left; 106 } 107 108 inline float getHeight() const { 109 return bottom - top; 110 } 111 112 bool intersects(float l, float t, float r, float b) const { 113 return !intersectWith(l, t, r, b).isEmpty(); 114 } 115 116 bool intersects(const Rect& r) const { 117 return intersects(r.left, r.top, r.right, r.bottom); 118 } 119 120 bool intersect(float l, float t, float r, float b) { 121 Rect tmp(l, t, r, b); 122 intersectWith(tmp); 123 if (!tmp.isEmpty()) { 124 set(tmp); 125 return true; 126 } 127 return false; 128 } 129 130 bool intersect(const Rect& r) { 131 return intersect(r.left, r.top, r.right, r.bottom); 132 } 133 134 inline bool contains(float l, float t, float r, float b) const { 135 return l >= left && t >= top && r <= right && b <= bottom; 136 } 137 138 inline bool contains(const Rect& r) const { 139 return contains(r.left, r.top, r.right, r.bottom); 140 } 141 142 bool unionWith(const Rect& r) { 143 if (r.left < r.right && r.top < r.bottom) { 144 if (left < right && top < bottom) { 145 if (left > r.left) left = r.left; 146 if (top > r.top) top = r.top; 147 if (right < r.right) right = r.right; 148 if (bottom < r.bottom) bottom = r.bottom; 149 return true; 150 } else { 151 left = r.left; 152 top = r.top; 153 right = r.right; 154 bottom = r.bottom; 155 return true; 156 } 157 } 158 return false; 159 } 160 161 void translate(float dx, float dy) { 162 left += dx; 163 right += dx; 164 top += dy; 165 bottom += dy; 166 } 167 168 void outset(float delta) { 169 left -= delta; 170 top -= delta; 171 right += delta; 172 bottom += delta; 173 } 174 175 /** 176 * Similar to snapToPixelBoundaries, but estimates bounds conservatively to handle GL rounding 177 * errors. 178 * 179 * This function should be used whenever estimating the damage rect of geometry already mapped 180 * into layer space. 181 */ 182 void snapGeometryToPixelBoundaries(bool snapOut) { 183 if (snapOut) { 184 /* For AA geometry with a ramp perimeter, don't snap by rounding - AA geometry will have 185 * a 0.5 pixel perimeter not accounted for in its bounds. Instead, snap by 186 * conservatively rounding out the bounds with floor/ceil. 187 * 188 * In order to avoid changing integer bounds with floor/ceil due to rounding errors 189 * inset the bounds first by the fudge factor. Very small fraction-of-a-pixel errors 190 * from this inset will only incur similarly small errors in output, due to transparency 191 * in extreme outside of the geometry. 192 */ 193 left = floorf(left + Vertex::gGeometryFudgeFactor); 194 top = floorf(top + Vertex::gGeometryFudgeFactor); 195 right = ceilf(right - Vertex::gGeometryFudgeFactor); 196 bottom = ceilf(bottom - Vertex::gGeometryFudgeFactor); 197 } else { 198 /* For other geometry, we do the regular rounding in order to snap, but also outset the 199 * bounds by a fudge factor. This ensures that ambiguous geometry (e.g. a non-AA Rect 200 * with top left at (0.5, 0.5)) will err on the side of a larger damage rect. 201 */ 202 left = floorf(left + 0.5f - Vertex::gGeometryFudgeFactor); 203 top = floorf(top + 0.5f - Vertex::gGeometryFudgeFactor); 204 right = floorf(right + 0.5f + Vertex::gGeometryFudgeFactor); 205 bottom = floorf(bottom + 0.5f + Vertex::gGeometryFudgeFactor); 206 } 207 } 208 209 void snapToPixelBoundaries() { 210 left = floorf(left + 0.5f); 211 top = floorf(top + 0.5f); 212 right = floorf(right + 0.5f); 213 bottom = floorf(bottom + 0.5f); 214 } 215 216 void dump() const { 217 ALOGD("Rect[l=%f t=%f r=%f b=%f]", left, top, right, bottom); 218 } 219 220 private: 221 void intersectWith(Rect& tmp) const { 222 tmp.left = fmaxf(left, tmp.left); 223 tmp.top = fmaxf(top, tmp.top); 224 tmp.right = fminf(right, tmp.right); 225 tmp.bottom = fminf(bottom, tmp.bottom); 226 } 227 228 Rect intersectWith(float l, float t, float r, float b) const { 229 Rect tmp; 230 tmp.left = fmaxf(left, l); 231 tmp.top = fmaxf(top, t); 232 tmp.right = fminf(right, r); 233 tmp.bottom = fminf(bottom, b); 234 return tmp; 235 } 236 237 }; // class Rect 238 239 }; // namespace uirenderer 240 }; // namespace android 241 242 #endif // ANDROID_HWUI_RECT_H 243