1*635a8641SAndroid Build Coastguard Worker // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2*635a8641SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*635a8641SAndroid Build Coastguard Worker // found in the LICENSE file.
4*635a8641SAndroid Build Coastguard Worker
5*635a8641SAndroid Build Coastguard Worker // Defines a simple integer rectangle class. The containment semantics
6*635a8641SAndroid Build Coastguard Worker // are array-like; that is, the coordinate (x, y) is considered to be
7*635a8641SAndroid Build Coastguard Worker // contained by the rectangle, but the coordinate (x + width, y) is not.
8*635a8641SAndroid Build Coastguard Worker // The class will happily let you create malformed rectangles (that is,
9*635a8641SAndroid Build Coastguard Worker // rectangles with negative width and/or height), but there will be assertions
10*635a8641SAndroid Build Coastguard Worker // in the operations (such as Contains()) to complain in this case.
11*635a8641SAndroid Build Coastguard Worker
12*635a8641SAndroid Build Coastguard Worker #ifndef UI_GFX_GEOMETRY_RECT_H_
13*635a8641SAndroid Build Coastguard Worker #define UI_GFX_GEOMETRY_RECT_H_
14*635a8641SAndroid Build Coastguard Worker
15*635a8641SAndroid Build Coastguard Worker #include <cmath>
16*635a8641SAndroid Build Coastguard Worker #include <iosfwd>
17*635a8641SAndroid Build Coastguard Worker #include <string>
18*635a8641SAndroid Build Coastguard Worker
19*635a8641SAndroid Build Coastguard Worker #include "base/logging.h"
20*635a8641SAndroid Build Coastguard Worker #include "build/build_config.h"
21*635a8641SAndroid Build Coastguard Worker #include "ui/gfx/geometry/point.h"
22*635a8641SAndroid Build Coastguard Worker #include "ui/gfx/geometry/safe_integer_conversions.h"
23*635a8641SAndroid Build Coastguard Worker #include "ui/gfx/geometry/size.h"
24*635a8641SAndroid Build Coastguard Worker #include "ui/gfx/geometry/vector2d.h"
25*635a8641SAndroid Build Coastguard Worker
26*635a8641SAndroid Build Coastguard Worker #if defined(OS_WIN)
27*635a8641SAndroid Build Coastguard Worker typedef struct tagRECT RECT;
28*635a8641SAndroid Build Coastguard Worker #elif defined(OS_MACOSX)
29*635a8641SAndroid Build Coastguard Worker typedef struct CGRect CGRect;
30*635a8641SAndroid Build Coastguard Worker #endif
31*635a8641SAndroid Build Coastguard Worker
32*635a8641SAndroid Build Coastguard Worker namespace gfx {
33*635a8641SAndroid Build Coastguard Worker
34*635a8641SAndroid Build Coastguard Worker class Insets;
35*635a8641SAndroid Build Coastguard Worker
36*635a8641SAndroid Build Coastguard Worker class GFX_EXPORT Rect {
37*635a8641SAndroid Build Coastguard Worker public:
38*635a8641SAndroid Build Coastguard Worker constexpr Rect() = default;
Rect(int width,int height)39*635a8641SAndroid Build Coastguard Worker constexpr Rect(int width, int height) : size_(width, height) {}
Rect(int x,int y,int width,int height)40*635a8641SAndroid Build Coastguard Worker constexpr Rect(int x, int y, int width, int height)
41*635a8641SAndroid Build Coastguard Worker : origin_(x, y),
42*635a8641SAndroid Build Coastguard Worker size_(GetClampedValue(x, width), GetClampedValue(y, height)) {}
Rect(const Size & size)43*635a8641SAndroid Build Coastguard Worker constexpr explicit Rect(const Size& size) : size_(size) {}
Rect(const Point & origin,const Size & size)44*635a8641SAndroid Build Coastguard Worker constexpr Rect(const Point& origin, const Size& size)
45*635a8641SAndroid Build Coastguard Worker : origin_(origin),
46*635a8641SAndroid Build Coastguard Worker size_(GetClampedValue(origin.x(), size.width()),
47*635a8641SAndroid Build Coastguard Worker GetClampedValue(origin.y(), size.height())) {}
48*635a8641SAndroid Build Coastguard Worker
49*635a8641SAndroid Build Coastguard Worker #if defined(OS_WIN)
50*635a8641SAndroid Build Coastguard Worker explicit Rect(const RECT& r);
51*635a8641SAndroid Build Coastguard Worker #elif defined(OS_MACOSX)
52*635a8641SAndroid Build Coastguard Worker explicit Rect(const CGRect& r);
53*635a8641SAndroid Build Coastguard Worker #endif
54*635a8641SAndroid Build Coastguard Worker
55*635a8641SAndroid Build Coastguard Worker #if defined(OS_WIN)
56*635a8641SAndroid Build Coastguard Worker // Construct an equivalent Win32 RECT object.
57*635a8641SAndroid Build Coastguard Worker RECT ToRECT() const;
58*635a8641SAndroid Build Coastguard Worker #elif defined(OS_MACOSX)
59*635a8641SAndroid Build Coastguard Worker // Construct an equivalent CoreGraphics object.
60*635a8641SAndroid Build Coastguard Worker CGRect ToCGRect() const;
61*635a8641SAndroid Build Coastguard Worker #endif
62*635a8641SAndroid Build Coastguard Worker
x()63*635a8641SAndroid Build Coastguard Worker constexpr int x() const { return origin_.x(); }
64*635a8641SAndroid Build Coastguard Worker // Sets the X position while preserving the width.
set_x(int x)65*635a8641SAndroid Build Coastguard Worker void set_x(int x) {
66*635a8641SAndroid Build Coastguard Worker origin_.set_x(x);
67*635a8641SAndroid Build Coastguard Worker size_.set_width(GetClampedValue(x, width()));
68*635a8641SAndroid Build Coastguard Worker }
69*635a8641SAndroid Build Coastguard Worker
y()70*635a8641SAndroid Build Coastguard Worker constexpr int y() const { return origin_.y(); }
71*635a8641SAndroid Build Coastguard Worker // Sets the Y position while preserving the height.
set_y(int y)72*635a8641SAndroid Build Coastguard Worker void set_y(int y) {
73*635a8641SAndroid Build Coastguard Worker origin_.set_y(y);
74*635a8641SAndroid Build Coastguard Worker size_.set_height(GetClampedValue(y, height()));
75*635a8641SAndroid Build Coastguard Worker }
76*635a8641SAndroid Build Coastguard Worker
width()77*635a8641SAndroid Build Coastguard Worker constexpr int width() const { return size_.width(); }
set_width(int width)78*635a8641SAndroid Build Coastguard Worker void set_width(int width) { size_.set_width(GetClampedValue(x(), width)); }
79*635a8641SAndroid Build Coastguard Worker
height()80*635a8641SAndroid Build Coastguard Worker constexpr int height() const { return size_.height(); }
set_height(int height)81*635a8641SAndroid Build Coastguard Worker void set_height(int height) {
82*635a8641SAndroid Build Coastguard Worker size_.set_height(GetClampedValue(y(), height));
83*635a8641SAndroid Build Coastguard Worker }
84*635a8641SAndroid Build Coastguard Worker
origin()85*635a8641SAndroid Build Coastguard Worker constexpr const Point& origin() const { return origin_; }
set_origin(const Point & origin)86*635a8641SAndroid Build Coastguard Worker void set_origin(const Point& origin) {
87*635a8641SAndroid Build Coastguard Worker origin_ = origin;
88*635a8641SAndroid Build Coastguard Worker // Ensure that width and height remain valid.
89*635a8641SAndroid Build Coastguard Worker set_width(width());
90*635a8641SAndroid Build Coastguard Worker set_height(height());
91*635a8641SAndroid Build Coastguard Worker }
92*635a8641SAndroid Build Coastguard Worker
size()93*635a8641SAndroid Build Coastguard Worker constexpr const Size& size() const { return size_; }
set_size(const Size & size)94*635a8641SAndroid Build Coastguard Worker void set_size(const Size& size) {
95*635a8641SAndroid Build Coastguard Worker set_width(size.width());
96*635a8641SAndroid Build Coastguard Worker set_height(size.height());
97*635a8641SAndroid Build Coastguard Worker }
98*635a8641SAndroid Build Coastguard Worker
right()99*635a8641SAndroid Build Coastguard Worker constexpr int right() const { return x() + width(); }
bottom()100*635a8641SAndroid Build Coastguard Worker constexpr int bottom() const { return y() + height(); }
101*635a8641SAndroid Build Coastguard Worker
top_right()102*635a8641SAndroid Build Coastguard Worker constexpr Point top_right() const { return Point(right(), y()); }
bottom_left()103*635a8641SAndroid Build Coastguard Worker constexpr Point bottom_left() const { return Point(x(), bottom()); }
bottom_right()104*635a8641SAndroid Build Coastguard Worker constexpr Point bottom_right() const { return Point(right(), bottom()); }
105*635a8641SAndroid Build Coastguard Worker
OffsetFromOrigin()106*635a8641SAndroid Build Coastguard Worker Vector2d OffsetFromOrigin() const { return Vector2d(x(), y()); }
107*635a8641SAndroid Build Coastguard Worker
SetRect(int x,int y,int width,int height)108*635a8641SAndroid Build Coastguard Worker void SetRect(int x, int y, int width, int height) {
109*635a8641SAndroid Build Coastguard Worker origin_.SetPoint(x, y);
110*635a8641SAndroid Build Coastguard Worker // Ensure that width and height remain valid.
111*635a8641SAndroid Build Coastguard Worker set_width(width);
112*635a8641SAndroid Build Coastguard Worker set_height(height);
113*635a8641SAndroid Build Coastguard Worker }
114*635a8641SAndroid Build Coastguard Worker
115*635a8641SAndroid Build Coastguard Worker // Use in place of SetRect() when you know the edges of the rectangle instead
116*635a8641SAndroid Build Coastguard Worker // of the dimensions, rather than trying to determine the width/height
117*635a8641SAndroid Build Coastguard Worker // yourself. This safely handles cases where the width/height would overflow.
118*635a8641SAndroid Build Coastguard Worker void SetByBounds(int left, int top, int right, int bottom);
119*635a8641SAndroid Build Coastguard Worker
120*635a8641SAndroid Build Coastguard Worker // Shrink the rectangle by a horizontal and vertical distance on all sides.
Inset(int horizontal,int vertical)121*635a8641SAndroid Build Coastguard Worker void Inset(int horizontal, int vertical) {
122*635a8641SAndroid Build Coastguard Worker Inset(horizontal, vertical, horizontal, vertical);
123*635a8641SAndroid Build Coastguard Worker }
124*635a8641SAndroid Build Coastguard Worker
125*635a8641SAndroid Build Coastguard Worker // Shrink the rectangle by the given insets.
126*635a8641SAndroid Build Coastguard Worker void Inset(const Insets& insets);
127*635a8641SAndroid Build Coastguard Worker
128*635a8641SAndroid Build Coastguard Worker // Shrink the rectangle by the specified amount on each side.
129*635a8641SAndroid Build Coastguard Worker void Inset(int left, int top, int right, int bottom);
130*635a8641SAndroid Build Coastguard Worker
131*635a8641SAndroid Build Coastguard Worker // Move the rectangle by a horizontal and vertical distance.
132*635a8641SAndroid Build Coastguard Worker void Offset(int horizontal, int vertical);
Offset(const Vector2d & distance)133*635a8641SAndroid Build Coastguard Worker void Offset(const Vector2d& distance) { Offset(distance.x(), distance.y()); }
134*635a8641SAndroid Build Coastguard Worker void operator+=(const Vector2d& offset);
135*635a8641SAndroid Build Coastguard Worker void operator-=(const Vector2d& offset);
136*635a8641SAndroid Build Coastguard Worker
137*635a8641SAndroid Build Coastguard Worker Insets InsetsFrom(const Rect& inner) const;
138*635a8641SAndroid Build Coastguard Worker
139*635a8641SAndroid Build Coastguard Worker // Returns true if the area of the rectangle is zero.
IsEmpty()140*635a8641SAndroid Build Coastguard Worker bool IsEmpty() const { return size_.IsEmpty(); }
141*635a8641SAndroid Build Coastguard Worker
142*635a8641SAndroid Build Coastguard Worker // A rect is less than another rect if its origin is less than
143*635a8641SAndroid Build Coastguard Worker // the other rect's origin. If the origins are equal, then the
144*635a8641SAndroid Build Coastguard Worker // shortest rect is less than the other. If the origin and the
145*635a8641SAndroid Build Coastguard Worker // height are equal, then the narrowest rect is less than.
146*635a8641SAndroid Build Coastguard Worker // This comparison is required to use Rects in sets, or sorted
147*635a8641SAndroid Build Coastguard Worker // vectors.
148*635a8641SAndroid Build Coastguard Worker bool operator<(const Rect& other) const;
149*635a8641SAndroid Build Coastguard Worker
150*635a8641SAndroid Build Coastguard Worker // Returns true if the point identified by point_x and point_y falls inside
151*635a8641SAndroid Build Coastguard Worker // this rectangle. The point (x, y) is inside the rectangle, but the
152*635a8641SAndroid Build Coastguard Worker // point (x + width, y + height) is not.
153*635a8641SAndroid Build Coastguard Worker bool Contains(int point_x, int point_y) const;
154*635a8641SAndroid Build Coastguard Worker
155*635a8641SAndroid Build Coastguard Worker // Returns true if the specified point is contained by this rectangle.
Contains(const Point & point)156*635a8641SAndroid Build Coastguard Worker bool Contains(const Point& point) const {
157*635a8641SAndroid Build Coastguard Worker return Contains(point.x(), point.y());
158*635a8641SAndroid Build Coastguard Worker }
159*635a8641SAndroid Build Coastguard Worker
160*635a8641SAndroid Build Coastguard Worker // Returns true if this rectangle contains the specified rectangle.
161*635a8641SAndroid Build Coastguard Worker bool Contains(const Rect& rect) const;
162*635a8641SAndroid Build Coastguard Worker
163*635a8641SAndroid Build Coastguard Worker // Returns true if this rectangle intersects the specified rectangle.
164*635a8641SAndroid Build Coastguard Worker // An empty rectangle doesn't intersect any rectangle.
165*635a8641SAndroid Build Coastguard Worker bool Intersects(const Rect& rect) const;
166*635a8641SAndroid Build Coastguard Worker
167*635a8641SAndroid Build Coastguard Worker // Computes the intersection of this rectangle with the given rectangle.
168*635a8641SAndroid Build Coastguard Worker void Intersect(const Rect& rect);
169*635a8641SAndroid Build Coastguard Worker
170*635a8641SAndroid Build Coastguard Worker // Computes the union of this rectangle with the given rectangle. The union
171*635a8641SAndroid Build Coastguard Worker // is the smallest rectangle containing both rectangles.
172*635a8641SAndroid Build Coastguard Worker void Union(const Rect& rect);
173*635a8641SAndroid Build Coastguard Worker
174*635a8641SAndroid Build Coastguard Worker // Computes the rectangle resulting from subtracting |rect| from |*this|,
175*635a8641SAndroid Build Coastguard Worker // i.e. the bounding rect of |Region(*this) - Region(rect)|.
176*635a8641SAndroid Build Coastguard Worker void Subtract(const Rect& rect);
177*635a8641SAndroid Build Coastguard Worker
178*635a8641SAndroid Build Coastguard Worker // Fits as much of the receiving rectangle into the supplied rectangle as
179*635a8641SAndroid Build Coastguard Worker // possible, becoming the result. For example, if the receiver had
180*635a8641SAndroid Build Coastguard Worker // a x-location of 2 and a width of 4, and the supplied rectangle had
181*635a8641SAndroid Build Coastguard Worker // an x-location of 0 with a width of 5, the returned rectangle would have
182*635a8641SAndroid Build Coastguard Worker // an x-location of 1 with a width of 4.
183*635a8641SAndroid Build Coastguard Worker void AdjustToFit(const Rect& rect);
184*635a8641SAndroid Build Coastguard Worker
185*635a8641SAndroid Build Coastguard Worker // Returns the center of this rectangle.
186*635a8641SAndroid Build Coastguard Worker Point CenterPoint() const;
187*635a8641SAndroid Build Coastguard Worker
188*635a8641SAndroid Build Coastguard Worker // Becomes a rectangle that has the same center point but with a size capped
189*635a8641SAndroid Build Coastguard Worker // at given |size|.
190*635a8641SAndroid Build Coastguard Worker void ClampToCenteredSize(const Size& size);
191*635a8641SAndroid Build Coastguard Worker
192*635a8641SAndroid Build Coastguard Worker // Splits |this| in two halves, |left_half| and |right_half|.
193*635a8641SAndroid Build Coastguard Worker void SplitVertically(Rect* left_half, Rect* right_half) const;
194*635a8641SAndroid Build Coastguard Worker
195*635a8641SAndroid Build Coastguard Worker // Returns true if this rectangle shares an entire edge (i.e., same width or
196*635a8641SAndroid Build Coastguard Worker // same height) with the given rectangle, and the rectangles do not overlap.
197*635a8641SAndroid Build Coastguard Worker bool SharesEdgeWith(const Rect& rect) const;
198*635a8641SAndroid Build Coastguard Worker
199*635a8641SAndroid Build Coastguard Worker // Returns the manhattan distance from the rect to the point. If the point is
200*635a8641SAndroid Build Coastguard Worker // inside the rect, returns 0.
201*635a8641SAndroid Build Coastguard Worker int ManhattanDistanceToPoint(const Point& point) const;
202*635a8641SAndroid Build Coastguard Worker
203*635a8641SAndroid Build Coastguard Worker // Returns the manhattan distance between the contents of this rect and the
204*635a8641SAndroid Build Coastguard Worker // contents of the given rect. That is, if the intersection of the two rects
205*635a8641SAndroid Build Coastguard Worker // is non-empty then the function returns 0. If the rects share a side, it
206*635a8641SAndroid Build Coastguard Worker // returns the smallest non-zero value appropriate for int.
207*635a8641SAndroid Build Coastguard Worker int ManhattanInternalDistance(const Rect& rect) const;
208*635a8641SAndroid Build Coastguard Worker
209*635a8641SAndroid Build Coastguard Worker std::string ToString() const;
210*635a8641SAndroid Build Coastguard Worker
211*635a8641SAndroid Build Coastguard Worker bool ApproximatelyEqual(const Rect& rect, int tolerance) const;
212*635a8641SAndroid Build Coastguard Worker
213*635a8641SAndroid Build Coastguard Worker private:
214*635a8641SAndroid Build Coastguard Worker gfx::Point origin_;
215*635a8641SAndroid Build Coastguard Worker gfx::Size size_;
216*635a8641SAndroid Build Coastguard Worker
217*635a8641SAndroid Build Coastguard Worker // Returns true iff a+b would overflow max int.
AddWouldOverflow(int a,int b)218*635a8641SAndroid Build Coastguard Worker static constexpr bool AddWouldOverflow(int a, int b) {
219*635a8641SAndroid Build Coastguard Worker // In this function, GCC tries to make optimizations that would only work if
220*635a8641SAndroid Build Coastguard Worker // max - a wouldn't overflow but it isn't smart enough to notice that a > 0.
221*635a8641SAndroid Build Coastguard Worker // So cast everything to unsigned to avoid this. As it is guaranteed that
222*635a8641SAndroid Build Coastguard Worker // max - a and b are both already positive, the cast is a noop.
223*635a8641SAndroid Build Coastguard Worker //
224*635a8641SAndroid Build Coastguard Worker // This is intended to be: a > 0 && max - a < b
225*635a8641SAndroid Build Coastguard Worker return a > 0 && b > 0 &&
226*635a8641SAndroid Build Coastguard Worker static_cast<unsigned>(std::numeric_limits<int>::max() - a) <
227*635a8641SAndroid Build Coastguard Worker static_cast<unsigned>(b);
228*635a8641SAndroid Build Coastguard Worker }
229*635a8641SAndroid Build Coastguard Worker
230*635a8641SAndroid Build Coastguard Worker // Clamp the size to avoid integer overflow in bottom() and right().
231*635a8641SAndroid Build Coastguard Worker // This returns the width given an origin and a width.
232*635a8641SAndroid Build Coastguard Worker // TODO(enne): this should probably use base::ClampAdd, but that
233*635a8641SAndroid Build Coastguard Worker // function is not a constexpr.
GetClampedValue(int origin,int size)234*635a8641SAndroid Build Coastguard Worker static constexpr int GetClampedValue(int origin, int size) {
235*635a8641SAndroid Build Coastguard Worker return AddWouldOverflow(origin, size)
236*635a8641SAndroid Build Coastguard Worker ? std::numeric_limits<int>::max() - origin
237*635a8641SAndroid Build Coastguard Worker : size;
238*635a8641SAndroid Build Coastguard Worker }
239*635a8641SAndroid Build Coastguard Worker };
240*635a8641SAndroid Build Coastguard Worker
241*635a8641SAndroid Build Coastguard Worker inline bool operator==(const Rect& lhs, const Rect& rhs) {
242*635a8641SAndroid Build Coastguard Worker return lhs.origin() == rhs.origin() && lhs.size() == rhs.size();
243*635a8641SAndroid Build Coastguard Worker }
244*635a8641SAndroid Build Coastguard Worker
245*635a8641SAndroid Build Coastguard Worker inline bool operator!=(const Rect& lhs, const Rect& rhs) {
246*635a8641SAndroid Build Coastguard Worker return !(lhs == rhs);
247*635a8641SAndroid Build Coastguard Worker }
248*635a8641SAndroid Build Coastguard Worker
249*635a8641SAndroid Build Coastguard Worker GFX_EXPORT Rect operator+(const Rect& lhs, const Vector2d& rhs);
250*635a8641SAndroid Build Coastguard Worker GFX_EXPORT Rect operator-(const Rect& lhs, const Vector2d& rhs);
251*635a8641SAndroid Build Coastguard Worker
252*635a8641SAndroid Build Coastguard Worker inline Rect operator+(const Vector2d& lhs, const Rect& rhs) {
253*635a8641SAndroid Build Coastguard Worker return rhs + lhs;
254*635a8641SAndroid Build Coastguard Worker }
255*635a8641SAndroid Build Coastguard Worker
256*635a8641SAndroid Build Coastguard Worker GFX_EXPORT Rect IntersectRects(const Rect& a, const Rect& b);
257*635a8641SAndroid Build Coastguard Worker GFX_EXPORT Rect UnionRects(const Rect& a, const Rect& b);
258*635a8641SAndroid Build Coastguard Worker GFX_EXPORT Rect SubtractRects(const Rect& a, const Rect& b);
259*635a8641SAndroid Build Coastguard Worker
260*635a8641SAndroid Build Coastguard Worker // Constructs a rectangle with |p1| and |p2| as opposite corners.
261*635a8641SAndroid Build Coastguard Worker //
262*635a8641SAndroid Build Coastguard Worker // This could also be thought of as "the smallest rect that contains both
263*635a8641SAndroid Build Coastguard Worker // points", except that we consider points on the right/bottom edges of the
264*635a8641SAndroid Build Coastguard Worker // rect to be outside the rect. So technically one or both points will not be
265*635a8641SAndroid Build Coastguard Worker // contained within the rect, because they will appear on one of these edges.
266*635a8641SAndroid Build Coastguard Worker GFX_EXPORT Rect BoundingRect(const Point& p1, const Point& p2);
267*635a8641SAndroid Build Coastguard Worker
268*635a8641SAndroid Build Coastguard Worker // Scales the rect and returns the enclosing rect. Use this only the inputs are
269*635a8641SAndroid Build Coastguard Worker // known to not overflow. Use ScaleToEnclosingRectSafe if the inputs are
270*635a8641SAndroid Build Coastguard Worker // unknown and need to use saturated math.
ScaleToEnclosingRect(const Rect & rect,float x_scale,float y_scale)271*635a8641SAndroid Build Coastguard Worker inline Rect ScaleToEnclosingRect(const Rect& rect,
272*635a8641SAndroid Build Coastguard Worker float x_scale,
273*635a8641SAndroid Build Coastguard Worker float y_scale) {
274*635a8641SAndroid Build Coastguard Worker if (x_scale == 1.f && y_scale == 1.f)
275*635a8641SAndroid Build Coastguard Worker return rect;
276*635a8641SAndroid Build Coastguard Worker // These next functions cast instead of using e.g. ToFlooredInt() because we
277*635a8641SAndroid Build Coastguard Worker // haven't checked to ensure that the clamping behavior of the helper
278*635a8641SAndroid Build Coastguard Worker // functions doesn't degrade performance, and callers shouldn't be passing
279*635a8641SAndroid Build Coastguard Worker // values that cause overflow anyway.
280*635a8641SAndroid Build Coastguard Worker DCHECK(base::IsValueInRangeForNumericType<int>(
281*635a8641SAndroid Build Coastguard Worker std::floor(rect.x() * x_scale)));
282*635a8641SAndroid Build Coastguard Worker DCHECK(base::IsValueInRangeForNumericType<int>(
283*635a8641SAndroid Build Coastguard Worker std::floor(rect.y() * y_scale)));
284*635a8641SAndroid Build Coastguard Worker DCHECK(base::IsValueInRangeForNumericType<int>(
285*635a8641SAndroid Build Coastguard Worker std::ceil(rect.right() * x_scale)));
286*635a8641SAndroid Build Coastguard Worker DCHECK(base::IsValueInRangeForNumericType<int>(
287*635a8641SAndroid Build Coastguard Worker std::ceil(rect.bottom() * y_scale)));
288*635a8641SAndroid Build Coastguard Worker int x = static_cast<int>(std::floor(rect.x() * x_scale));
289*635a8641SAndroid Build Coastguard Worker int y = static_cast<int>(std::floor(rect.y() * y_scale));
290*635a8641SAndroid Build Coastguard Worker int r = rect.width() == 0 ?
291*635a8641SAndroid Build Coastguard Worker x : static_cast<int>(std::ceil(rect.right() * x_scale));
292*635a8641SAndroid Build Coastguard Worker int b = rect.height() == 0 ?
293*635a8641SAndroid Build Coastguard Worker y : static_cast<int>(std::ceil(rect.bottom() * y_scale));
294*635a8641SAndroid Build Coastguard Worker return Rect(x, y, r - x, b - y);
295*635a8641SAndroid Build Coastguard Worker }
296*635a8641SAndroid Build Coastguard Worker
ScaleToEnclosingRect(const Rect & rect,float scale)297*635a8641SAndroid Build Coastguard Worker inline Rect ScaleToEnclosingRect(const Rect& rect, float scale) {
298*635a8641SAndroid Build Coastguard Worker return ScaleToEnclosingRect(rect, scale, scale);
299*635a8641SAndroid Build Coastguard Worker }
300*635a8641SAndroid Build Coastguard Worker
301*635a8641SAndroid Build Coastguard Worker // ScaleToEnclosingRect but clamping instead of asserting if the resulting rect
302*635a8641SAndroid Build Coastguard Worker // would overflow.
ScaleToEnclosingRectSafe(const Rect & rect,float x_scale,float y_scale)303*635a8641SAndroid Build Coastguard Worker inline Rect ScaleToEnclosingRectSafe(const Rect& rect,
304*635a8641SAndroid Build Coastguard Worker float x_scale,
305*635a8641SAndroid Build Coastguard Worker float y_scale) {
306*635a8641SAndroid Build Coastguard Worker if (x_scale == 1.f && y_scale == 1.f)
307*635a8641SAndroid Build Coastguard Worker return rect;
308*635a8641SAndroid Build Coastguard Worker int x = base::saturated_cast<int>(std::floor(rect.x() * x_scale));
309*635a8641SAndroid Build Coastguard Worker int y = base::saturated_cast<int>(std::floor(rect.y() * y_scale));
310*635a8641SAndroid Build Coastguard Worker int w = base::saturated_cast<int>(std::ceil(rect.width() * x_scale));
311*635a8641SAndroid Build Coastguard Worker int h = base::saturated_cast<int>(std::ceil(rect.height() * y_scale));
312*635a8641SAndroid Build Coastguard Worker return Rect(x, y, w, h);
313*635a8641SAndroid Build Coastguard Worker }
314*635a8641SAndroid Build Coastguard Worker
ScaleToEnclosingRectSafe(const Rect & rect,float scale)315*635a8641SAndroid Build Coastguard Worker inline Rect ScaleToEnclosingRectSafe(const Rect& rect, float scale) {
316*635a8641SAndroid Build Coastguard Worker return ScaleToEnclosingRectSafe(rect, scale, scale);
317*635a8641SAndroid Build Coastguard Worker }
318*635a8641SAndroid Build Coastguard Worker
ScaleToEnclosedRect(const Rect & rect,float x_scale,float y_scale)319*635a8641SAndroid Build Coastguard Worker inline Rect ScaleToEnclosedRect(const Rect& rect,
320*635a8641SAndroid Build Coastguard Worker float x_scale,
321*635a8641SAndroid Build Coastguard Worker float y_scale) {
322*635a8641SAndroid Build Coastguard Worker if (x_scale == 1.f && y_scale == 1.f)
323*635a8641SAndroid Build Coastguard Worker return rect;
324*635a8641SAndroid Build Coastguard Worker DCHECK(base::IsValueInRangeForNumericType<int>(
325*635a8641SAndroid Build Coastguard Worker std::ceil(rect.x() * x_scale)));
326*635a8641SAndroid Build Coastguard Worker DCHECK(base::IsValueInRangeForNumericType<int>(
327*635a8641SAndroid Build Coastguard Worker std::ceil(rect.y() * y_scale)));
328*635a8641SAndroid Build Coastguard Worker DCHECK(base::IsValueInRangeForNumericType<int>(
329*635a8641SAndroid Build Coastguard Worker std::floor(rect.right() * x_scale)));
330*635a8641SAndroid Build Coastguard Worker DCHECK(base::IsValueInRangeForNumericType<int>(
331*635a8641SAndroid Build Coastguard Worker std::floor(rect.bottom() * y_scale)));
332*635a8641SAndroid Build Coastguard Worker int x = static_cast<int>(std::ceil(rect.x() * x_scale));
333*635a8641SAndroid Build Coastguard Worker int y = static_cast<int>(std::ceil(rect.y() * y_scale));
334*635a8641SAndroid Build Coastguard Worker int r = rect.width() == 0 ?
335*635a8641SAndroid Build Coastguard Worker x : static_cast<int>(std::floor(rect.right() * x_scale));
336*635a8641SAndroid Build Coastguard Worker int b = rect.height() == 0 ?
337*635a8641SAndroid Build Coastguard Worker y : static_cast<int>(std::floor(rect.bottom() * y_scale));
338*635a8641SAndroid Build Coastguard Worker return Rect(x, y, r - x, b - y);
339*635a8641SAndroid Build Coastguard Worker }
340*635a8641SAndroid Build Coastguard Worker
ScaleToEnclosedRect(const Rect & rect,float scale)341*635a8641SAndroid Build Coastguard Worker inline Rect ScaleToEnclosedRect(const Rect& rect, float scale) {
342*635a8641SAndroid Build Coastguard Worker return ScaleToEnclosedRect(rect, scale, scale);
343*635a8641SAndroid Build Coastguard Worker }
344*635a8641SAndroid Build Coastguard Worker
345*635a8641SAndroid Build Coastguard Worker // Scales |rect| by scaling its four corner points. If the corner points lie on
346*635a8641SAndroid Build Coastguard Worker // non-integral coordinate after scaling, their values are rounded to the
347*635a8641SAndroid Build Coastguard Worker // nearest integer.
348*635a8641SAndroid Build Coastguard Worker // This is helpful during layout when relative positions of multiple gfx::Rect
349*635a8641SAndroid Build Coastguard Worker // in a given coordinate space needs to be same after scaling as it was before
350*635a8641SAndroid Build Coastguard Worker // scaling. ie. this gives a lossless relative positioning of rects.
ScaleToRoundedRect(const Rect & rect,float x_scale,float y_scale)351*635a8641SAndroid Build Coastguard Worker inline Rect ScaleToRoundedRect(const Rect& rect, float x_scale, float y_scale) {
352*635a8641SAndroid Build Coastguard Worker if (x_scale == 1.f && y_scale == 1.f)
353*635a8641SAndroid Build Coastguard Worker return rect;
354*635a8641SAndroid Build Coastguard Worker
355*635a8641SAndroid Build Coastguard Worker DCHECK(
356*635a8641SAndroid Build Coastguard Worker base::IsValueInRangeForNumericType<int>(std::round(rect.x() * x_scale)));
357*635a8641SAndroid Build Coastguard Worker DCHECK(
358*635a8641SAndroid Build Coastguard Worker base::IsValueInRangeForNumericType<int>(std::round(rect.y() * y_scale)));
359*635a8641SAndroid Build Coastguard Worker DCHECK(base::IsValueInRangeForNumericType<int>(
360*635a8641SAndroid Build Coastguard Worker std::round(rect.right() * x_scale)));
361*635a8641SAndroid Build Coastguard Worker DCHECK(base::IsValueInRangeForNumericType<int>(
362*635a8641SAndroid Build Coastguard Worker std::round(rect.bottom() * y_scale)));
363*635a8641SAndroid Build Coastguard Worker
364*635a8641SAndroid Build Coastguard Worker int x = static_cast<int>(std::round(rect.x() * x_scale));
365*635a8641SAndroid Build Coastguard Worker int y = static_cast<int>(std::round(rect.y() * y_scale));
366*635a8641SAndroid Build Coastguard Worker int r = rect.width() == 0
367*635a8641SAndroid Build Coastguard Worker ? x
368*635a8641SAndroid Build Coastguard Worker : static_cast<int>(std::round(rect.right() * x_scale));
369*635a8641SAndroid Build Coastguard Worker int b = rect.height() == 0
370*635a8641SAndroid Build Coastguard Worker ? y
371*635a8641SAndroid Build Coastguard Worker : static_cast<int>(std::round(rect.bottom() * y_scale));
372*635a8641SAndroid Build Coastguard Worker
373*635a8641SAndroid Build Coastguard Worker return Rect(x, y, r - x, b - y);
374*635a8641SAndroid Build Coastguard Worker }
375*635a8641SAndroid Build Coastguard Worker
ScaleToRoundedRect(const Rect & rect,float scale)376*635a8641SAndroid Build Coastguard Worker inline Rect ScaleToRoundedRect(const Rect& rect, float scale) {
377*635a8641SAndroid Build Coastguard Worker return ScaleToRoundedRect(rect, scale, scale);
378*635a8641SAndroid Build Coastguard Worker }
379*635a8641SAndroid Build Coastguard Worker
380*635a8641SAndroid Build Coastguard Worker // This is declared here for use in gtest-based unit tests but is defined in
381*635a8641SAndroid Build Coastguard Worker // the //ui/gfx:test_support target. Depend on that to use this in your unit
382*635a8641SAndroid Build Coastguard Worker // test. This should not be used in production code - call ToString() instead.
383*635a8641SAndroid Build Coastguard Worker void PrintTo(const Rect& rect, ::std::ostream* os);
384*635a8641SAndroid Build Coastguard Worker
385*635a8641SAndroid Build Coastguard Worker } // namespace gfx
386*635a8641SAndroid Build Coastguard Worker
387*635a8641SAndroid Build Coastguard Worker #endif // UI_GFX_GEOMETRY_RECT_H_
388