1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef MOZILLA_GFX_RECT_ABSOLUTE_H_
8 #define MOZILLA_GFX_RECT_ABSOLUTE_H_
13 #include "mozilla/Attributes.h"
26 * A RectAbsolute is similar to a Rect (see BaseRect.h), but represented as
27 * (x1, y1, x2, y2) instead of (x, y, width, height).
29 * Unless otherwise indicated, methods on this class correspond
30 * to methods on BaseRect.
32 * The API is currently very bare-bones; it may be extended as needed.
34 * Do not use this class directly. Subclass it, pass that subclass as the
35 * Sub parameter, and only use that subclass.
37 template <class T
, class Sub
, class Point
, class Rect
>
38 struct BaseRectAbsolute
{
40 T left
, top
, right
, bottom
;
43 BaseRectAbsolute() : left(0), top(0), right(0), bottom(0) {}
44 BaseRectAbsolute(T aLeft
, T aTop
, T aRight
, T aBottom
)
45 : left(aLeft
), top(aTop
), right(aRight
), bottom(aBottom
) {}
47 MOZ_ALWAYS_INLINE T
X() const { return left
; }
48 MOZ_ALWAYS_INLINE T
Y() const { return top
; }
49 MOZ_ALWAYS_INLINE T
Width() const { return right
- left
; }
50 MOZ_ALWAYS_INLINE T
Height() const { return bottom
- top
; }
51 MOZ_ALWAYS_INLINE T
XMost() const { return right
; }
52 MOZ_ALWAYS_INLINE T
YMost() const { return bottom
; }
53 MOZ_ALWAYS_INLINE
const T
& Left() const { return left
; }
54 MOZ_ALWAYS_INLINE
const T
& Right() const { return right
; }
55 MOZ_ALWAYS_INLINE
const T
& Top() const { return top
; }
56 MOZ_ALWAYS_INLINE
const T
& Bottom() const { return bottom
; }
57 MOZ_ALWAYS_INLINE T
& Left() { return left
; }
58 MOZ_ALWAYS_INLINE T
& Right() { return right
; }
59 MOZ_ALWAYS_INLINE T
& Top() { return top
; }
60 MOZ_ALWAYS_INLINE T
& Bottom() { return bottom
; }
61 T
Area() const { return Width() * Height(); }
63 void Inflate(T aD
) { Inflate(aD
, aD
); }
64 void Inflate(T aDx
, T aDy
) {
71 MOZ_ALWAYS_INLINE
void SetBox(T aLeft
, T aTop
, T aRight
, T aBottom
) {
77 void SetLeftEdge(T aLeft
) { left
= aLeft
; }
78 void SetRightEdge(T aRight
) { right
= aRight
; }
79 void SetTopEdge(T aTop
) { top
= aTop
; }
80 void SetBottomEdge(T aBottom
) { bottom
= aBottom
; }
82 static Sub
FromRect(const Rect
& aRect
) {
83 if (aRect
.Overflows()) {
86 return Sub(aRect
.x
, aRect
.y
, aRect
.XMost(), aRect
.YMost());
89 [[nodiscard
]] Sub
Intersect(const Sub
& aOther
) const {
91 result
.left
= std::max
<T
>(left
, aOther
.left
);
92 result
.top
= std::max
<T
>(top
, aOther
.top
);
93 result
.right
= std::min
<T
>(right
, aOther
.right
);
94 result
.bottom
= std::min
<T
>(bottom
, aOther
.bottom
);
95 if (result
.right
< result
.left
|| result
.bottom
< result
.top
) {
101 bool IsEmpty() const { return right
<= left
|| bottom
<= top
; }
103 bool IsEqualEdges(const Sub
& aOther
) const {
104 return left
== aOther
.left
&& top
== aOther
.top
&& right
== aOther
.right
&&
105 bottom
== aOther
.bottom
;
108 bool IsEqualInterior(const Sub
& aRect
) const {
109 return IsEqualEdges(aRect
) || (IsEmpty() && aRect
.IsEmpty());
112 MOZ_ALWAYS_INLINE
void MoveBy(T aDx
, T aDy
) {
118 MOZ_ALWAYS_INLINE
void MoveBy(const Point
& aPoint
) {
124 MOZ_ALWAYS_INLINE
void SizeTo(T aWidth
, T aHeight
) {
125 right
= left
+ aWidth
;
126 bottom
= top
+ aHeight
;
129 bool Contains(const Sub
& aRect
) const {
130 return aRect
.IsEmpty() || (left
<= aRect
.left
&& aRect
.right
<= right
&&
131 top
<= aRect
.top
&& aRect
.bottom
<= bottom
);
133 bool Contains(T aX
, T aY
) const {
134 return (left
<= aX
&& aX
< right
&& top
<= aY
&& aY
< bottom
);
137 bool Intersects(const Sub
& aRect
) const {
138 return !IsEmpty() && !aRect
.IsEmpty() && left
< aRect
.right
&&
139 aRect
.left
< right
&& top
< aRect
.bottom
&& aRect
.top
< bottom
;
142 void SetEmpty() { left
= right
= top
= bottom
= 0; }
144 // Returns the smallest rectangle that contains both the area of both
146 // Thus, empty input rectangles are ignored.
147 // If both rectangles are empty, returns this.
148 // WARNING! This is not safe against overflow, prefer using SafeUnion instead
149 // when dealing with int-based rects.
150 [[nodiscard
]] Sub
Union(const Sub
& aRect
) const {
153 } else if (aRect
.IsEmpty()) {
154 return *static_cast<const Sub
*>(this);
156 return UnionEdges(aRect
);
159 // Returns the smallest rectangle that contains both the points (including
160 // edges) of both aRect1 and aRect2.
161 // Thus, empty input rectangles are allowed to affect the result.
162 // WARNING! This is not safe against overflow, prefer using SafeUnionEdges
163 // instead when dealing with int-based rects.
164 [[nodiscard
]] Sub
UnionEdges(const Sub
& aRect
) const {
166 result
.left
= std::min(left
, aRect
.left
);
167 result
.top
= std::min(top
, aRect
.top
);
168 result
.right
= std::max(XMost(), aRect
.XMost());
169 result
.bottom
= std::max(YMost(), aRect
.YMost());
173 // Scale 'this' by aScale without doing any rounding.
174 void Scale(T aScale
) { Scale(aScale
, aScale
); }
175 // Scale 'this' by aXScale and aYScale, without doing any rounding.
176 void Scale(T aXScale
, T aYScale
) {
177 right
= XMost() * aXScale
;
178 bottom
= YMost() * aYScale
;
179 left
= left
* aXScale
;
182 // Scale 'this' by aScale, converting coordinates to integers so that the
183 // result is the smallest integer-coordinate rectangle containing the
184 // unrounded result. Note: this can turn an empty rectangle into a non-empty
186 void ScaleRoundOut(double aScale
) { ScaleRoundOut(aScale
, aScale
); }
187 // Scale 'this' by aXScale and aYScale, converting coordinates to integers so
188 // that the result is the smallest integer-coordinate rectangle containing the
190 // Note: this can turn an empty rectangle into a non-empty rectangle
191 void ScaleRoundOut(double aXScale
, double aYScale
) {
192 right
= static_cast<T
>(ceil(double(XMost()) * aXScale
));
193 bottom
= static_cast<T
>(ceil(double(YMost()) * aYScale
));
194 left
= static_cast<T
>(floor(double(left
) * aXScale
));
195 top
= static_cast<T
>(floor(double(top
) * aYScale
));
197 // Scale 'this' by aScale, converting coordinates to integers so that the
198 // result is the largest integer-coordinate rectangle contained by the
200 void ScaleRoundIn(double aScale
) { ScaleRoundIn(aScale
, aScale
); }
201 // Scale 'this' by aXScale and aYScale, converting coordinates to integers so
202 // that the result is the largest integer-coordinate rectangle contained by
203 // the unrounded result.
204 void ScaleRoundIn(double aXScale
, double aYScale
) {
205 right
= static_cast<T
>(floor(double(XMost()) * aXScale
));
206 bottom
= static_cast<T
>(floor(double(YMost()) * aYScale
));
207 left
= static_cast<T
>(ceil(double(left
) * aXScale
));
208 top
= static_cast<T
>(ceil(double(top
) * aYScale
));
210 // Scale 'this' by 1/aScale, converting coordinates to integers so that the
211 // result is the smallest integer-coordinate rectangle containing the
212 // unrounded result. Note: this can turn an empty rectangle into a non-empty
214 void ScaleInverseRoundOut(double aScale
) {
215 ScaleInverseRoundOut(aScale
, aScale
);
217 // Scale 'this' by 1/aXScale and 1/aYScale, converting coordinates to integers
218 // so that the result is the smallest integer-coordinate rectangle containing
219 // the unrounded result. Note: this can turn an empty rectangle into a
220 // non-empty rectangle
221 void ScaleInverseRoundOut(double aXScale
, double aYScale
) {
222 right
= static_cast<T
>(ceil(double(XMost()) / aXScale
));
223 bottom
= static_cast<T
>(ceil(double(YMost()) / aYScale
));
224 left
= static_cast<T
>(floor(double(left
) / aXScale
));
225 top
= static_cast<T
>(floor(double(top
) / aYScale
));
227 // Scale 'this' by 1/aScale, converting coordinates to integers so that the
228 // result is the largest integer-coordinate rectangle contained by the
230 void ScaleInverseRoundIn(double aScale
) {
231 ScaleInverseRoundIn(aScale
, aScale
);
233 // Scale 'this' by 1/aXScale and 1/aYScale, converting coordinates to integers
234 // so that the result is the largest integer-coordinate rectangle contained by
235 // the unrounded result.
236 void ScaleInverseRoundIn(double aXScale
, double aYScale
) {
237 right
= static_cast<T
>(floor(double(XMost()) / aXScale
));
238 bottom
= static_cast<T
>(floor(double(YMost()) / aYScale
));
239 left
= static_cast<T
>(ceil(double(left
) / aXScale
));
240 top
= static_cast<T
>(ceil(double(top
) / aYScale
));
244 * Translate this rectangle to be inside aRect. If it doesn't fit inside
245 * aRect then the dimensions that don't fit will be shrunk so that they
246 * do fit. The resulting rect is returned.
248 [[nodiscard
]] Sub
MoveInsideAndClamp(const Sub
& aRect
) const {
249 T newLeft
= std::max(aRect
.left
, left
);
250 T newTop
= std::max(aRect
.top
, top
);
251 T width
= std::min(aRect
.Width(), Width());
252 T height
= std::min(aRect
.Height(), Height());
253 Sub
rect(newLeft
, newTop
, newLeft
+ width
, newTop
+ height
);
254 newLeft
= std::min(rect
.right
, aRect
.right
) - width
;
255 newTop
= std::min(rect
.bottom
, aRect
.bottom
) - height
;
256 rect
.MoveBy(newLeft
- rect
.left
, newTop
- rect
.top
);
260 friend std::ostream
& operator<<(
261 std::ostream
& stream
,
262 const BaseRectAbsolute
<T
, Sub
, Point
, Rect
>& aRect
) {
263 return stream
<< "(l=" << aRect
.left
<< ", t=" << aRect
.top
264 << ", r=" << aRect
.right
<< ", b=" << aRect
.bottom
<< ')';
268 template <class Units
>
269 struct IntRectAbsoluteTyped
270 : public BaseRectAbsolute
<int32_t, IntRectAbsoluteTyped
<Units
>,
271 IntPointTyped
<Units
>, IntRectTyped
<Units
>>,
273 static_assert(IsPixel
<Units
>::value
,
274 "'units' must be a coordinate system tag");
275 typedef BaseRectAbsolute
<int32_t, IntRectAbsoluteTyped
<Units
>,
276 IntPointTyped
<Units
>, IntRectTyped
<Units
>>
278 typedef IntParam
<int32_t> ToInt
;
280 IntRectAbsoluteTyped() : Super() {}
281 IntRectAbsoluteTyped(ToInt aLeft
, ToInt aTop
, ToInt aRight
, ToInt aBottom
)
282 : Super(aLeft
.value
, aTop
.value
, aRight
.value
, aBottom
.value
) {}
285 template <class Units
>
286 struct RectAbsoluteTyped
287 : public BaseRectAbsolute
<Float
, RectAbsoluteTyped
<Units
>,
288 PointTyped
<Units
>, RectTyped
<Units
>>,
290 static_assert(IsPixel
<Units
>::value
,
291 "'units' must be a coordinate system tag");
292 typedef BaseRectAbsolute
<Float
, RectAbsoluteTyped
<Units
>, PointTyped
<Units
>,
296 RectAbsoluteTyped() : Super() {}
297 RectAbsoluteTyped(Float aLeft
, Float aTop
, Float aRight
, Float aBottom
)
298 : Super(aLeft
, aTop
, aRight
, aBottom
) {}
301 typedef IntRectAbsoluteTyped
<UnknownUnits
> IntRectAbsolute
;
304 } // namespace mozilla
306 #endif /* MOZILLA_GFX_RECT_ABSOLUTE_H_ */