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