Line data Source code
1 : /* -*- Mode: c++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 : * This Source Code Form is subject to the terms of the Mozilla Public
3 : * License, v. 2.0. If a copy of the MPL was not distributed with this
4 : * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5 :
6 : #ifndef MOZILLA_GFX_RECT_H_
7 : #define MOZILLA_GFX_RECT_H_
8 :
9 : #include "BaseRect.h"
10 : #include "BaseMargin.h"
11 : #include "NumericTools.h"
12 : #include "Point.h"
13 : #include "Tools.h"
14 : #include "mozilla/Maybe.h"
15 :
16 : #include <cmath>
17 :
18 : namespace mozilla {
19 :
20 : template <typename> struct IsPixel;
21 :
22 : namespace gfx {
23 :
24 : template<class units, class F> struct RectTyped;
25 :
26 : template<class units>
27 : struct IntMarginTyped:
28 : public BaseMargin<int32_t, IntMarginTyped<units> >,
29 : public units {
30 : static_assert(IsPixel<units>::value,
31 : "'units' must be a coordinate system tag");
32 :
33 : typedef BaseMargin<int32_t, IntMarginTyped<units> > Super;
34 :
35 1137 : IntMarginTyped() : Super() {}
36 856 : IntMarginTyped(int32_t aTop, int32_t aRight, int32_t aBottom, int32_t aLeft) :
37 856 : Super(aTop, aRight, aBottom, aLeft) {}
38 :
39 : // XXX When all of the code is ported, the following functions to convert
40 : // to and from unknown types should be removed.
41 :
42 0 : static IntMarginTyped<units> FromUnknownMargin(const IntMarginTyped<UnknownUnits>& aMargin) {
43 0 : return IntMarginTyped<units>(aMargin.top, aMargin.right,
44 0 : aMargin.bottom, aMargin.left);
45 : }
46 :
47 : IntMarginTyped<UnknownUnits> ToUnknownMargin() const {
48 : return IntMarginTyped<UnknownUnits>(this->top, this->right,
49 : this->bottom, this->left);
50 : }
51 : };
52 : typedef IntMarginTyped<UnknownUnits> IntMargin;
53 :
54 : template<class units, class F = Float>
55 : struct MarginTyped:
56 : public BaseMargin<F, MarginTyped<units, F> >,
57 : public units {
58 : static_assert(IsPixel<units>::value,
59 : "'units' must be a coordinate system tag");
60 :
61 : typedef BaseMargin<F, MarginTyped<units, F> > Super;
62 :
63 324 : MarginTyped() : Super() {}
64 243 : MarginTyped(F aTop, F aRight, F aBottom, F aLeft) :
65 243 : Super(aTop, aRight, aBottom, aLeft) {}
66 36 : explicit MarginTyped(const IntMarginTyped<units>& aMargin) :
67 72 : Super(F(aMargin.top), F(aMargin.right),
68 108 : F(aMargin.bottom), F(aMargin.left)) {}
69 : };
70 : typedef MarginTyped<UnknownUnits> Margin;
71 : typedef MarginTyped<UnknownUnits, double> MarginDouble;
72 :
73 : template<class units>
74 : IntMarginTyped<units> RoundedToInt(const MarginTyped<units>& aMargin)
75 : {
76 : return IntMarginTyped<units>(int32_t(floorf(aMargin.top + 0.5f)),
77 : int32_t(floorf(aMargin.right + 0.5f)),
78 : int32_t(floorf(aMargin.bottom + 0.5f)),
79 : int32_t(floorf(aMargin.left + 0.5f)));
80 : }
81 :
82 : template<class units>
83 : struct IntRectTyped :
84 : public BaseRect<int32_t, IntRectTyped<units>, IntPointTyped<units>, IntSizeTyped<units>, IntMarginTyped<units> >,
85 : public units {
86 : static_assert(IsPixel<units>::value,
87 : "'units' must be a coordinate system tag");
88 :
89 : typedef BaseRect<int32_t, IntRectTyped<units>, IntPointTyped<units>, IntSizeTyped<units>, IntMarginTyped<units> > Super;
90 : typedef IntRectTyped<units> Self;
91 : typedef IntParam<int32_t> ToInt;
92 :
93 31692 : IntRectTyped() : Super() {}
94 523 : IntRectTyped(const IntPointTyped<units>& aPos, const IntSizeTyped<units>& aSize) :
95 523 : Super(aPos, aSize) {}
96 :
97 12138 : IntRectTyped(ToInt aX, ToInt aY, ToInt aWidth, ToInt aHeight) :
98 12138 : Super(aX.value, aY.value, aWidth.value, aHeight.value) {}
99 :
100 0 : static IntRectTyped<units> RoundIn(float aX, float aY, float aW, float aH) {
101 0 : return IntRectTyped<units>::RoundIn(RectTyped<units, float>(aX, aY, aW, aH));
102 : }
103 :
104 99 : static IntRectTyped<units> RoundOut(float aX, float aY, float aW, float aH) {
105 99 : return IntRectTyped<units>::RoundOut(RectTyped<units, float>(aX, aY, aW, aH));
106 : }
107 :
108 : static IntRectTyped<units> Round(float aX, float aY, float aW, float aH) {
109 : return IntRectTyped<units>::Round(RectTyped<units, float>(aX, aY, aW, aH));
110 : }
111 :
112 2 : static IntRectTyped<units> Truncate(float aX, float aY, float aW, float aH) {
113 4 : return IntRectTyped<units>(IntPointTyped<units>::Truncate(aX, aY),
114 6 : IntSizeTyped<units>::Truncate(aW, aH));
115 : }
116 :
117 35 : static IntRectTyped<units> RoundIn(const RectTyped<units, float>& aRect) {
118 35 : auto tmp(aRect);
119 35 : tmp.RoundIn();
120 70 : return IntRectTyped(int32_t(tmp.x), int32_t(tmp.y),
121 105 : int32_t(tmp.width), int32_t(tmp.height));
122 : }
123 :
124 297 : static IntRectTyped<units> RoundOut(const RectTyped<units, float>& aRect) {
125 297 : auto tmp(aRect);
126 297 : tmp.RoundOut();
127 594 : return IntRectTyped(int32_t(tmp.x), int32_t(tmp.y),
128 891 : int32_t(tmp.width), int32_t(tmp.height));
129 : }
130 :
131 : static IntRectTyped<units> Round(const RectTyped<units, float>& aRect) {
132 : auto tmp(aRect);
133 : tmp.Round();
134 : return IntRectTyped(int32_t(tmp.x), int32_t(tmp.y),
135 : int32_t(tmp.width), int32_t(tmp.height));
136 : }
137 :
138 1 : static IntRectTyped<units> Truncate(const RectTyped<units, float>& aRect) {
139 1 : return IntRectTyped::Truncate(aRect.x, aRect.y, aRect.width, aRect.height);
140 : }
141 :
142 : // Rounding isn't meaningful on an integer rectangle.
143 : void Round() {}
144 : void RoundIn() {}
145 : void RoundOut() {}
146 :
147 : // XXX When all of the code is ported, the following functions to convert
148 : // to and from unknown types should be removed.
149 :
150 160 : static IntRectTyped<units> FromUnknownRect(const IntRectTyped<UnknownUnits>& rect) {
151 160 : return IntRectTyped<units>(rect.x, rect.y, rect.width, rect.height);
152 : }
153 :
154 1898 : IntRectTyped<UnknownUnits> ToUnknownRect() const {
155 1898 : return IntRectTyped<UnknownUnits>(this->x, this->y, this->width, this->height);
156 : }
157 :
158 1498 : bool Overflows() const {
159 1498 : CheckedInt<int32_t> xMost = this->x;
160 1498 : xMost += this->width;
161 1498 : CheckedInt<int32_t> yMost = this->y;
162 1498 : yMost += this->height;
163 1498 : return !xMost.isValid() || !yMost.isValid();
164 : }
165 :
166 : // Same as Union(), but in the cases where aRect is non-empty, the union is
167 : // done while guarding against overflow. If an overflow is detected, Nothing
168 : // is returned.
169 364 : MOZ_MUST_USE Maybe<Self> SafeUnion(const Self& aRect) const
170 : {
171 364 : if (this->IsEmpty()) {
172 206 : return aRect.Overflows() ? Nothing() : Some(aRect);
173 158 : } else if (aRect.IsEmpty()) {
174 0 : return Some(*static_cast<const Self*>(this));
175 : } else {
176 158 : return this->SafeUnionEdges(aRect);
177 : }
178 : }
179 :
180 : // Same as UnionEdges, but guards against overflow. If an overflow is detected,
181 : // Nothing is returned.
182 158 : MOZ_MUST_USE Maybe<Self> SafeUnionEdges(const Self& aRect) const
183 : {
184 158 : if (this->Overflows() || aRect.Overflows()) {
185 0 : return Nothing();
186 : }
187 : // If neither |this| nor |aRect| overflow, then their XMost/YMost values
188 : // should be safe to use.
189 158 : CheckedInt<int32_t> newX = std::min(this->x, aRect.x);
190 158 : CheckedInt<int32_t> newY = std::min(this->y, aRect.y);
191 158 : CheckedInt<int32_t> newXMost = std::max(this->XMost(), aRect.XMost());
192 158 : CheckedInt<int32_t> newYMost = std::max(this->YMost(), aRect.YMost());
193 158 : CheckedInt<int32_t> newW = newXMost - newX;
194 158 : CheckedInt<int32_t> newH = newYMost - newY;
195 158 : if (!newW.isValid() || !newH.isValid()) {
196 0 : return Nothing();
197 : }
198 158 : return Some(Self(newX.value(), newY.value(), newW.value(), newH.value()));
199 : }
200 :
201 : // This is here only to keep IPDL-generated code happy. DO NOT USE.
202 47 : bool operator==(const IntRectTyped<units>& aRect) const
203 : {
204 47 : return IntRectTyped<units>::IsEqualEdges(aRect);
205 : }
206 :
207 0 : void InflateToMultiple(const IntSizeTyped<units>& aTileSize)
208 : {
209 0 : if (this->IsEmpty()) {
210 0 : return;
211 : }
212 :
213 0 : int32_t yMost = this->YMost();
214 0 : int32_t xMost = this->XMost();
215 :
216 0 : this->x = mozilla::RoundDownToMultiple(this->x, aTileSize.width);
217 0 : this->y = mozilla::RoundDownToMultiple(this->y, aTileSize.height);
218 0 : xMost = mozilla::RoundUpToMultiple(xMost, aTileSize.width);
219 0 : yMost = mozilla::RoundUpToMultiple(yMost, aTileSize.height);
220 :
221 0 : this->width = xMost - this->x;
222 0 : this->height = yMost - this->y;
223 : }
224 :
225 : };
226 : typedef IntRectTyped<UnknownUnits> IntRect;
227 :
228 : template<class units, class F = Float>
229 : struct RectTyped :
230 : public BaseRect<F, RectTyped<units, F>, PointTyped<units, F>, SizeTyped<units, F>, MarginTyped<units, F> >,
231 : public units {
232 : static_assert(IsPixel<units>::value,
233 : "'units' must be a coordinate system tag");
234 :
235 : typedef BaseRect<F, RectTyped<units, F>, PointTyped<units, F>, SizeTyped<units, F>, MarginTyped<units, F> > Super;
236 :
237 2446 : RectTyped() : Super() {}
238 486 : RectTyped(const PointTyped<units, F>& aPos, const SizeTyped<units, F>& aSize) :
239 486 : Super(aPos, aSize) {}
240 12223 : RectTyped(F _x, F _y, F _width, F _height) :
241 12223 : Super(_x, _y, _width, _height) {}
242 472 : explicit RectTyped(const IntRectTyped<units>& rect) :
243 944 : Super(F(rect.x), F(rect.y),
244 1416 : F(rect.width), F(rect.height)) {}
245 :
246 718 : void NudgeToIntegers()
247 : {
248 718 : NudgeToInteger(&(this->x));
249 718 : NudgeToInteger(&(this->y));
250 718 : NudgeToInteger(&(this->width));
251 718 : NudgeToInteger(&(this->height));
252 718 : }
253 :
254 674 : bool ToIntRect(IntRectTyped<units> *aOut) const
255 : {
256 1348 : *aOut = IntRectTyped<units>(int32_t(this->X()), int32_t(this->Y()),
257 1348 : int32_t(this->Width()), int32_t(this->Height()));
258 1348 : return RectTyped<units, F>(F(aOut->x), F(aOut->y),
259 1348 : F(aOut->width), F(aOut->height))
260 2696 : .IsEqualEdges(*this);
261 : }
262 :
263 : // XXX When all of the code is ported, the following functions to convert to and from
264 : // unknown types should be removed.
265 :
266 0 : static RectTyped<units, F> FromUnknownRect(const RectTyped<UnknownUnits, F>& rect) {
267 0 : return RectTyped<units, F>(rect.x, rect.y, rect.width, rect.height);
268 : }
269 :
270 6 : RectTyped<UnknownUnits, F> ToUnknownRect() const {
271 6 : return RectTyped<UnknownUnits, F>(this->x, this->y, this->width, this->height);
272 : }
273 :
274 : // This is here only to keep IPDL-generated code happy. DO NOT USE.
275 0 : bool operator==(const RectTyped<units, F>& aRect) const
276 : {
277 0 : return RectTyped<units, F>::IsEqualEdges(aRect);
278 : }
279 : };
280 : typedef RectTyped<UnknownUnits> Rect;
281 : typedef RectTyped<UnknownUnits, double> RectDouble;
282 :
283 : template<class units>
284 176 : IntRectTyped<units> RoundedToInt(const RectTyped<units>& aRect)
285 : {
286 176 : RectTyped<units> copy(aRect);
287 176 : copy.Round();
288 176 : return IntRectTyped<units>(int32_t(copy.x),
289 176 : int32_t(copy.y),
290 176 : int32_t(copy.width),
291 704 : int32_t(copy.height));
292 : }
293 :
294 : template<class units>
295 35 : IntRectTyped<units> RoundedIn(const RectTyped<units>& aRect)
296 : {
297 35 : return IntRectTyped<units>::RoundIn(aRect);
298 : }
299 :
300 : template<class units>
301 198 : IntRectTyped<units> RoundedOut(const RectTyped<units>& aRect)
302 : {
303 198 : return IntRectTyped<units>::RoundOut(aRect);
304 : }
305 :
306 : template<class units>
307 1 : IntRectTyped<units> TruncatedToInt(const RectTyped<units>& aRect) {
308 1 : return IntRectTyped<units>::Truncate(aRect);
309 : }
310 :
311 : template<class units>
312 28 : RectTyped<units> IntRectToRect(const IntRectTyped<units>& aRect)
313 : {
314 28 : return RectTyped<units>(aRect.x, aRect.y, aRect.width, aRect.height);
315 : }
316 :
317 : // Convenience function for intersecting two rectangles wrapped in Maybes.
318 : template <typename T>
319 : Maybe<T>
320 1134 : IntersectMaybeRects(const Maybe<T>& a, const Maybe<T>& b)
321 : {
322 1134 : if (!a) {
323 809 : return b;
324 325 : } else if (!b) {
325 276 : return a;
326 : } else {
327 49 : return Some(a->Intersect(*b));
328 : }
329 : }
330 :
331 : } // namespace gfx
332 : } // namespace mozilla
333 :
334 : #endif /* MOZILLA_GFX_RECT_H_ */
|