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 :
7 : #ifndef NSRECT_H
8 : #define NSRECT_H
9 :
10 : #include <stdio.h> // for FILE
11 : #include <stdint.h> // for int32_t, int64_t
12 : #include <algorithm> // for min/max
13 : #include "mozilla/Likely.h" // for MOZ_UNLIKELY
14 : #include "mozilla/gfx/Rect.h"
15 : #include "nsCoord.h" // for nscoord, etc
16 : #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
17 : #include "nsPoint.h" // for nsIntPoint, nsPoint
18 : #include "nsMargin.h" // for nsIntMargin, nsMargin
19 : #include "nsSize.h" // for IntSize, nsSize
20 : #include "nscore.h" // for NS_BUILD_REFCNT_LOGGING
21 :
22 : typedef mozilla::gfx::IntRect nsIntRect;
23 :
24 : struct nsRect :
25 : public mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize, nsMargin> {
26 : typedef mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize, nsMargin> Super;
27 :
28 : static void VERIFY_COORD(nscoord aValue) { ::VERIFY_COORD(aValue); }
29 :
30 : // Constructors
31 82803 : nsRect() : Super()
32 : {
33 82803 : MOZ_COUNT_CTOR(nsRect);
34 82803 : }
35 75180 : nsRect(const nsRect& aRect) : Super(aRect)
36 : {
37 75180 : MOZ_COUNT_CTOR(nsRect);
38 75180 : }
39 23752 : nsRect(const nsPoint& aOrigin, const nsSize &aSize) : Super(aOrigin, aSize)
40 : {
41 23752 : MOZ_COUNT_CTOR(nsRect);
42 23752 : }
43 35168 : nsRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) :
44 35168 : Super(aX, aY, aWidth, aHeight)
45 : {
46 35168 : MOZ_COUNT_CTOR(nsRect);
47 35168 : }
48 :
49 : #ifdef NS_BUILD_REFCNT_LOGGING
50 431038 : ~nsRect() {
51 215520 : MOZ_COUNT_DTOR(nsRect);
52 215518 : }
53 : #endif
54 :
55 : // We have saturating versions of all the Union methods. These avoid
56 : // overflowing nscoord values in the 'width' and 'height' fields by
57 : // clamping the width and height values to nscoord_MAX if necessary.
58 :
59 15004 : MOZ_MUST_USE nsRect SaturatingUnion(const nsRect& aRect) const
60 : {
61 15004 : if (IsEmpty()) {
62 3886 : return aRect;
63 11118 : } else if (aRect.IsEmpty()) {
64 3299 : return *static_cast<const nsRect*>(this);
65 : } else {
66 7819 : return SaturatingUnionEdges(aRect);
67 : }
68 : }
69 :
70 11014 : MOZ_MUST_USE nsRect SaturatingUnionEdges(const nsRect& aRect) const
71 : {
72 : #ifdef NS_COORD_IS_FLOAT
73 : return UnionEdges(aRect);
74 : #else
75 11014 : nsRect result;
76 11014 : result.x = std::min(aRect.x, x);
77 11014 : int64_t w = std::max(int64_t(aRect.x) + aRect.width, int64_t(x) + width) - result.x;
78 11014 : if (MOZ_UNLIKELY(w > nscoord_MAX)) {
79 : // Clamp huge negative x to nscoord_MIN / 2 and try again.
80 0 : result.x = std::max(result.x, nscoord_MIN / 2);
81 0 : w = std::max(int64_t(aRect.x) + aRect.width, int64_t(x) + width) - result.x;
82 0 : if (MOZ_UNLIKELY(w > nscoord_MAX)) {
83 0 : w = nscoord_MAX;
84 : }
85 : }
86 11014 : result.width = nscoord(w);
87 :
88 11014 : result.y = std::min(aRect.y, y);
89 11014 : int64_t h = std::max(int64_t(aRect.y) + aRect.height, int64_t(y) + height) - result.y;
90 11014 : if (MOZ_UNLIKELY(h > nscoord_MAX)) {
91 : // Clamp huge negative y to nscoord_MIN / 2 and try again.
92 0 : result.y = std::max(result.y, nscoord_MIN / 2);
93 0 : h = std::max(int64_t(aRect.y) + aRect.height, int64_t(y) + height) - result.y;
94 0 : if (MOZ_UNLIKELY(h > nscoord_MAX)) {
95 0 : h = nscoord_MAX;
96 : }
97 : }
98 11014 : result.height = nscoord(h);
99 11014 : return result;
100 : #endif
101 : }
102 :
103 : #ifndef NS_COORD_IS_FLOAT
104 : // Make all nsRect Union methods be saturating.
105 3195 : MOZ_MUST_USE nsRect UnionEdges(const nsRect& aRect) const
106 : {
107 3195 : return SaturatingUnionEdges(aRect);
108 : }
109 3195 : void UnionRectEdges(const nsRect& aRect1, const nsRect& aRect2)
110 : {
111 3195 : *this = aRect1.UnionEdges(aRect2);
112 3195 : }
113 15004 : MOZ_MUST_USE nsRect Union(const nsRect& aRect) const
114 : {
115 15004 : return SaturatingUnion(aRect);
116 : }
117 13623 : void UnionRect(const nsRect& aRect1, const nsRect& aRect2)
118 : {
119 13623 : *this = aRect1.Union(aRect2);
120 13623 : }
121 : #endif
122 :
123 : void SaturatingUnionRect(const nsRect& aRect1, const nsRect& aRect2)
124 : {
125 : *this = aRect1.SaturatingUnion(aRect2);
126 : }
127 : void SaturatingUnionRectEdges(const nsRect& aRect1, const nsRect& aRect2)
128 : {
129 : *this = aRect1.SaturatingUnionEdges(aRect2);
130 : }
131 :
132 : // Return whether this rect's right or bottom edge overflow int32.
133 : bool Overflows() const;
134 :
135 : /**
136 : * Return this rect scaled to a different appunits per pixel (APP) ratio.
137 : * In the RoundOut version we make the rect the smallest rect containing the
138 : * unrounded result. In the RoundIn version we make the rect the largest rect
139 : * contained in the unrounded result.
140 : * @param aFromAPP the APP to scale from
141 : * @param aToAPP the APP to scale to
142 : * @note this can turn an empty rectangle into a non-empty rectangle
143 : */
144 : MOZ_MUST_USE inline nsRect
145 : ScaleToOtherAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const;
146 : MOZ_MUST_USE inline nsRect
147 : ScaleToOtherAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const;
148 :
149 : MOZ_MUST_USE inline mozilla::gfx::IntRect
150 : ScaleToNearestPixels(float aXScale, float aYScale,
151 : nscoord aAppUnitsPerPixel) const;
152 :
153 : MOZ_MUST_USE inline mozilla::gfx::IntRect
154 : ToNearestPixels(nscoord aAppUnitsPerPixel) const;
155 :
156 : // Note: this can turn an empty rectangle into a non-empty rectangle
157 : MOZ_MUST_USE inline mozilla::gfx::IntRect
158 : ScaleToOutsidePixels(float aXScale, float aYScale,
159 : nscoord aAppUnitsPerPixel) const;
160 :
161 : // Note: this can turn an empty rectangle into a non-empty rectangle
162 : MOZ_MUST_USE inline mozilla::gfx::IntRect
163 : ToOutsidePixels(nscoord aAppUnitsPerPixel) const;
164 :
165 : MOZ_MUST_USE inline mozilla::gfx::IntRect
166 : ScaleToInsidePixels(float aXScale, float aYScale,
167 : nscoord aAppUnitsPerPixel) const;
168 :
169 : MOZ_MUST_USE inline mozilla::gfx::IntRect
170 : ToInsidePixels(nscoord aAppUnitsPerPixel) const;
171 :
172 : // This is here only to keep IPDL-generated code happy. DO NOT USE.
173 344 : bool operator==(const nsRect& aRect) const
174 : {
175 344 : return IsEqualEdges(aRect);
176 : }
177 :
178 : MOZ_MUST_USE inline nsRect RemoveResolution(const float aResolution) const;
179 : };
180 :
181 : /*
182 : * App Unit/Pixel conversions
183 : */
184 :
185 : inline nsRect
186 0 : nsRect::ScaleToOtherAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const
187 : {
188 0 : if (aFromAPP == aToAPP) {
189 0 : return *this;
190 : }
191 :
192 0 : nsRect rect;
193 0 : nscoord right = NSToCoordCeil(NSCoordScale(XMost(), aFromAPP, aToAPP));
194 0 : nscoord bottom = NSToCoordCeil(NSCoordScale(YMost(), aFromAPP, aToAPP));
195 0 : rect.x = NSToCoordFloor(NSCoordScale(x, aFromAPP, aToAPP));
196 0 : rect.y = NSToCoordFloor(NSCoordScale(y, aFromAPP, aToAPP));
197 0 : rect.width = (right - rect.x);
198 0 : rect.height = (bottom - rect.y);
199 :
200 0 : return rect;
201 : }
202 :
203 : inline nsRect
204 0 : nsRect::ScaleToOtherAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const
205 : {
206 0 : if (aFromAPP == aToAPP) {
207 0 : return *this;
208 : }
209 :
210 0 : nsRect rect;
211 0 : nscoord right = NSToCoordFloor(NSCoordScale(XMost(), aFromAPP, aToAPP));
212 0 : nscoord bottom = NSToCoordFloor(NSCoordScale(YMost(), aFromAPP, aToAPP));
213 0 : rect.x = NSToCoordCeil(NSCoordScale(x, aFromAPP, aToAPP));
214 0 : rect.y = NSToCoordCeil(NSCoordScale(y, aFromAPP, aToAPP));
215 0 : rect.width = (right - rect.x);
216 0 : rect.height = (bottom - rect.y);
217 :
218 0 : return rect;
219 : }
220 :
221 : // scale the rect but round to preserve centers
222 : inline mozilla::gfx::IntRect
223 2834 : nsRect::ScaleToNearestPixels(float aXScale, float aYScale,
224 : nscoord aAppUnitsPerPixel) const
225 : {
226 2834 : mozilla::gfx::IntRect rect;
227 2834 : rect.x = NSToIntRoundUp(NSAppUnitsToDoublePixels(x, aAppUnitsPerPixel) * aXScale);
228 2834 : rect.y = NSToIntRoundUp(NSAppUnitsToDoublePixels(y, aAppUnitsPerPixel) * aYScale);
229 : // Avoid negative widths and heights due to overflow
230 5668 : rect.width = std::max(0, NSToIntRoundUp(NSAppUnitsToDoublePixels(XMost(),
231 5668 : aAppUnitsPerPixel) * aXScale) - rect.x);
232 5668 : rect.height = std::max(0, NSToIntRoundUp(NSAppUnitsToDoublePixels(YMost(),
233 5668 : aAppUnitsPerPixel) * aYScale) - rect.y);
234 2834 : return rect;
235 : }
236 :
237 : // scale the rect but round to smallest containing rect
238 : inline mozilla::gfx::IntRect
239 4503 : nsRect::ScaleToOutsidePixels(float aXScale, float aYScale,
240 : nscoord aAppUnitsPerPixel) const
241 : {
242 4503 : mozilla::gfx::IntRect rect;
243 4503 : rect.x = NSToIntFloor(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) * aXScale);
244 4503 : rect.y = NSToIntFloor(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) * aYScale);
245 : // Avoid negative widths and heights due to overflow
246 9006 : rect.width = std::max(0, NSToIntCeil(NSAppUnitsToFloatPixels(XMost(),
247 9006 : float(aAppUnitsPerPixel)) * aXScale) - rect.x);
248 9006 : rect.height = std::max(0, NSToIntCeil(NSAppUnitsToFloatPixels(YMost(),
249 9006 : float(aAppUnitsPerPixel)) * aYScale) - rect.y);
250 4503 : return rect;
251 : }
252 :
253 : // scale the rect but round to largest contained rect
254 : inline mozilla::gfx::IntRect
255 28 : nsRect::ScaleToInsidePixels(float aXScale, float aYScale,
256 : nscoord aAppUnitsPerPixel) const
257 : {
258 28 : mozilla::gfx::IntRect rect;
259 28 : rect.x = NSToIntCeil(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) * aXScale);
260 28 : rect.y = NSToIntCeil(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) * aYScale);
261 : // Avoid negative widths and heights due to overflow
262 56 : rect.width = std::max(0, NSToIntFloor(NSAppUnitsToFloatPixels(XMost(),
263 56 : float(aAppUnitsPerPixel)) * aXScale) - rect.x);
264 56 : rect.height = std::max(0, NSToIntFloor(NSAppUnitsToFloatPixels(YMost(),
265 56 : float(aAppUnitsPerPixel)) * aYScale) - rect.y);
266 28 : return rect;
267 : }
268 :
269 : inline mozilla::gfx::IntRect
270 41 : nsRect::ToNearestPixels(nscoord aAppUnitsPerPixel) const
271 : {
272 41 : return ScaleToNearestPixels(1.0f, 1.0f, aAppUnitsPerPixel);
273 : }
274 :
275 : inline mozilla::gfx::IntRect
276 199 : nsRect::ToOutsidePixels(nscoord aAppUnitsPerPixel) const
277 : {
278 199 : return ScaleToOutsidePixels(1.0f, 1.0f, aAppUnitsPerPixel);
279 : }
280 :
281 : inline mozilla::gfx::IntRect
282 0 : nsRect::ToInsidePixels(nscoord aAppUnitsPerPixel) const
283 : {
284 0 : return ScaleToInsidePixels(1.0f, 1.0f, aAppUnitsPerPixel);
285 : }
286 :
287 : inline nsRect
288 0 : nsRect::RemoveResolution(const float aResolution) const
289 : {
290 0 : MOZ_ASSERT(aResolution > 0.0f);
291 0 : nsRect rect;
292 0 : rect.x = NSToCoordRound(NSCoordToFloat(x) / aResolution);
293 0 : rect.y = NSToCoordRound(NSCoordToFloat(y) / aResolution);
294 : // A 1x1 rect indicates we are just hit testing a point, so pass down a 1x1
295 : // rect as well instead of possibly rounding the width or height to zero.
296 0 : if (width == 1 && height == 1) {
297 0 : rect.width = rect.height = 1;
298 : } else {
299 0 : rect.width = NSToCoordCeil(NSCoordToFloat(width) / aResolution);
300 0 : rect.height = NSToCoordCeil(NSCoordToFloat(height) / aResolution);
301 : }
302 :
303 0 : return rect;
304 : }
305 :
306 : const mozilla::gfx::IntRect& GetMaxSizedIntRect();
307 :
308 : // app units are integer multiples of pixels, so no rounding needed
309 : template<class units>
310 : nsRect
311 246 : ToAppUnits(const mozilla::gfx::IntRectTyped<units>& aRect, nscoord aAppUnitsPerPixel)
312 : {
313 246 : return nsRect(NSIntPixelsToAppUnits(aRect.x, aAppUnitsPerPixel),
314 246 : NSIntPixelsToAppUnits(aRect.y, aAppUnitsPerPixel),
315 246 : NSIntPixelsToAppUnits(aRect.width, aAppUnitsPerPixel),
316 984 : NSIntPixelsToAppUnits(aRect.height, aAppUnitsPerPixel));
317 : }
318 :
319 : #ifdef DEBUG
320 : // Diagnostics
321 : extern FILE* operator<<(FILE* out, const nsRect& rect);
322 : #endif // DEBUG
323 :
324 : #endif /* NSRECT_H */
|