Bug 1735097 - Geolocation: use EpochTimeStamp instead of DOMTimeStamp r=saschanaz...
[gecko.git] / gfx / 2d / RectAbsolute.h
blob68ac88a2af2365b5257914399d3201d45a457a79
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_
10 #include <algorithm>
11 #include <cstdint>
13 #include "mozilla/Attributes.h"
14 #include "Point.h"
15 #include "Rect.h"
16 #include "Types.h"
18 namespace mozilla {
20 template <typename>
21 struct IsPixel;
23 namespace gfx {
25 /**
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 {
39 protected:
40 T left, top, right, bottom;
42 public:
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) {
65 left -= aDx;
66 top -= aDy;
67 right += aDx;
68 bottom += aDy;
71 MOZ_ALWAYS_INLINE void SetBox(T aLeft, T aTop, T aRight, T aBottom) {
72 left = aLeft;
73 top = aTop;
74 right = aRight;
75 bottom = 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()) {
84 return Sub();
86 return Sub(aRect.x, aRect.y, aRect.XMost(), aRect.YMost());
89 [[nodiscard]] Sub Intersect(const Sub& aOther) const {
90 Sub result;
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) {
96 result.SizeTo(0, 0);
98 return result;
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) {
113 left += aDx;
114 right += aDx;
115 top += aDy;
116 bottom += aDy;
118 MOZ_ALWAYS_INLINE void MoveBy(const Point& aPoint) {
119 left += aPoint.x;
120 right += aPoint.x;
121 top += aPoint.y;
122 bottom += aPoint.y;
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
145 // this and aRect2.
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 {
151 if (IsEmpty()) {
152 return aRect;
153 } else if (aRect.IsEmpty()) {
154 return *static_cast<const Sub*>(this);
155 } else {
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 {
165 Sub result;
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());
170 return result;
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;
180 top = top * aYScale;
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
185 // rectangle
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
189 // unrounded result.
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
199 // unrounded result.
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
213 // rectangle
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
229 // unrounded result.
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);
257 return rect;
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>>,
272 public 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>>
277 Super;
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>>,
289 public Units {
290 static_assert(IsPixel<Units>::value,
291 "'units' must be a coordinate system tag");
292 typedef BaseRectAbsolute<Float, RectAbsoluteTyped<Units>, PointTyped<Units>,
293 RectTyped<Units>>
294 Super;
296 RectAbsoluteTyped() : Super() {}
297 RectAbsoluteTyped(Float aLeft, Float aTop, Float aRight, Float aBottom)
298 : Super(aLeft, aTop, aRight, aBottom) {}
301 typedef IntRectAbsoluteTyped<UnknownUnits> IntRectAbsolute;
303 } // namespace gfx
304 } // namespace mozilla
306 #endif /* MOZILLA_GFX_RECT_ABSOLUTE_H_ */