1 : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 : /* ***** BEGIN LICENSE BLOCK *****
3 : * Version: MPL 1.1/GPL 2.0/LGPL 2.1
4 : *
5 : * The contents of this file are subject to the Mozilla Public License Version
6 : * 1.1 (the "License"); you may not use this file except in compliance with
7 : * the License. You may obtain a copy of the License at
8 : * http://www.mozilla.org/MPL/
9 : *
10 : * Software distributed under the License is distributed on an "AS IS" basis,
11 : * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
12 : * for the specific language governing rights and limitations under the
13 : * License.
14 : *
15 : * The Original Code is mozilla.org code.
16 : *
17 : * The Initial Developer of the Original Code is
18 : * Netscape Communications Corporation.
19 : * Portions created by the Initial Developer are Copyright (C) 1998
20 : * the Initial Developer. All Rights Reserved.
21 : *
22 : * Contributor(s):
23 : *
24 : * Alternatively, the contents of this file may be used under the terms of
25 : * either of the GNU General Public License Version 2 or later (the "GPL"),
26 : * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
27 : * in which case the provisions of the GPL or the LGPL are applicable instead
28 : * of those above. If you wish to allow use of your version of this file only
29 : * under the terms of either the GPL or the LGPL, and not to allow others to
30 : * use your version of this file under the terms of the MPL, indicate your
31 : * decision by deleting the provisions above and replace them with the notice
32 : * and other provisions required by the GPL or the LGPL. If you do not delete
33 : * the provisions above, a recipient may use your version of this file under
34 : * the terms of any one of the MPL, the GPL or the LGPL.
35 : *
36 : * ***** END LICENSE BLOCK ***** */
37 :
38 :
39 : #ifndef NSRECT_H
40 : #define NSRECT_H
41 :
42 : #include <stdio.h>
43 : #include "nsCoord.h"
44 : #include "nsPoint.h"
45 : #include "nsSize.h"
46 : #include "nsMargin.h"
47 : #include "gfxCore.h"
48 : #include "nsTraceRefcnt.h"
49 : #include "mozilla/gfx/BaseRect.h"
50 :
51 : struct nsIntRect;
52 :
53 : struct NS_GFX nsRect :
54 : public mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize, nsMargin> {
55 : typedef mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize, nsMargin> Super;
56 :
57 : static void VERIFY_COORD(nscoord aValue) { ::VERIFY_COORD(aValue); }
58 :
59 : // Constructors
60 0 : nsRect() : Super()
61 : {
62 0 : MOZ_COUNT_CTOR(nsRect);
63 0 : }
64 0 : nsRect(const nsRect& aRect) : Super(aRect)
65 : {
66 0 : MOZ_COUNT_CTOR(nsRect);
67 0 : }
68 0 : nsRect(const nsPoint& aOrigin, const nsSize &aSize) : Super(aOrigin, aSize)
69 : {
70 0 : MOZ_COUNT_CTOR(nsRect);
71 0 : }
72 2 : nsRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) :
73 2 : Super(aX, aY, aWidth, aHeight)
74 : {
75 2 : MOZ_COUNT_CTOR(nsRect);
76 2 : }
77 :
78 : #ifdef NS_BUILD_REFCNT_LOGGING
79 1409 : ~nsRect() {
80 1409 : MOZ_COUNT_DTOR(nsRect);
81 1409 : }
82 : #endif
83 :
84 : // A version of Inflate that caps the values to the nscoord range.
85 : // x & y is capped at the minimum value nscoord_MIN and
86 : // width & height is capped at the maximum value nscoord_MAX.
87 : void SaturatingInflate(const nsMargin& aMargin)
88 : {
89 : #ifdef NS_COORD_IS_FLOAT
90 : Inflate(aMargin);
91 : #else
92 : PRInt64 nx = PRInt64(x) - aMargin.left;
93 : PRInt64 w = PRInt64(width) + PRInt64(aMargin.left) + aMargin.right;
94 : if (NS_UNLIKELY(w > nscoord_MAX)) {
95 : NS_WARNING("Overflowed nscoord_MAX in conversion to nscoord width");
96 : PRInt64 xdiff = nx - nscoord_MIN / 2;
97 : if (xdiff < 0) {
98 : // Clamp huge negative x to nscoord_MIN / 2 and try again.
99 : nx = nscoord_MIN / 2;
100 : w += xdiff;
101 : }
102 : if (NS_UNLIKELY(w > nscoord_MAX)) {
103 : w = nscoord_MAX;
104 : }
105 : }
106 : width = nscoord(w);
107 : if (NS_UNLIKELY(nx < nscoord_MIN)) {
108 : NS_WARNING("Underflowed nscoord_MIN in conversion to nscoord x");
109 : nx = nscoord_MIN;
110 : }
111 : x = nscoord(nx);
112 :
113 : PRInt64 ny = PRInt64(y) - aMargin.top;
114 : PRInt64 h = PRInt64(height) + PRInt64(aMargin.top) + aMargin.bottom;
115 : if (NS_UNLIKELY(h > nscoord_MAX)) {
116 : NS_WARNING("Overflowed nscoord_MAX in conversion to nscoord height");
117 : PRInt64 ydiff = ny - nscoord_MIN / 2;
118 : if (ydiff < 0) {
119 : // Clamp huge negative y to nscoord_MIN / 2 and try again.
120 : ny = nscoord_MIN / 2;
121 : h += ydiff;
122 : }
123 : if (NS_UNLIKELY(h > nscoord_MAX)) {
124 : h = nscoord_MAX;
125 : }
126 : }
127 : height = nscoord(h);
128 : if (NS_UNLIKELY(ny < nscoord_MIN)) {
129 : NS_WARNING("Underflowed nscoord_MIN in conversion to nscoord y");
130 : ny = nscoord_MIN;
131 : }
132 : y = nscoord(ny);
133 : #endif
134 : }
135 :
136 : // We have saturating versions of all the Union methods. These avoid
137 : // overflowing nscoord values in the 'width' and 'height' fields by
138 : // clamping the width and height values to nscoord_MAX if necessary.
139 :
140 0 : nsRect SaturatingUnion(const nsRect& aRect) const
141 : {
142 0 : if (IsEmpty()) {
143 0 : return aRect;
144 0 : } else if (aRect.IsEmpty()) {
145 0 : return *static_cast<const nsRect*>(this);
146 : } else {
147 0 : return SaturatingUnionEdges(aRect);
148 : }
149 : }
150 :
151 0 : nsRect SaturatingUnionEdges(const nsRect& aRect) const
152 : {
153 : #ifdef NS_COORD_IS_FLOAT
154 : return UnionEdges(aRect);
155 : #else
156 0 : nsRect result;
157 0 : result.x = NS_MIN(aRect.x, x);
158 0 : PRInt64 w = NS_MAX(PRInt64(aRect.x) + aRect.width, PRInt64(x) + width) - result.x;
159 0 : if (NS_UNLIKELY(w > nscoord_MAX)) {
160 0 : NS_WARNING("Overflowed nscoord_MAX in conversion to nscoord width");
161 : // Clamp huge negative x to nscoord_MIN / 2 and try again.
162 0 : result.x = NS_MAX(result.x, nscoord_MIN / 2);
163 0 : w = NS_MAX(PRInt64(aRect.x) + aRect.width, PRInt64(x) + width) - result.x;
164 0 : if (NS_UNLIKELY(w > nscoord_MAX)) {
165 0 : w = nscoord_MAX;
166 : }
167 : }
168 0 : result.width = nscoord(w);
169 :
170 0 : result.y = NS_MIN(aRect.y, y);
171 0 : PRInt64 h = NS_MAX(PRInt64(aRect.y) + aRect.height, PRInt64(y) + height) - result.y;
172 0 : if (NS_UNLIKELY(h > nscoord_MAX)) {
173 0 : NS_WARNING("Overflowed nscoord_MAX in conversion to nscoord height");
174 : // Clamp huge negative y to nscoord_MIN / 2 and try again.
175 0 : result.y = NS_MAX(result.y, nscoord_MIN / 2);
176 0 : h = NS_MAX(PRInt64(aRect.y) + aRect.height, PRInt64(y) + height) - result.y;
177 0 : if (NS_UNLIKELY(h > nscoord_MAX)) {
178 0 : h = nscoord_MAX;
179 : }
180 : }
181 0 : result.height = nscoord(h);
182 : return result;
183 : #endif
184 : }
185 :
186 : #ifndef NS_COORD_IS_FLOAT
187 : // Make all nsRect Union methods be saturating.
188 0 : nsRect UnionEdges(const nsRect& aRect) const
189 : {
190 0 : return SaturatingUnionEdges(aRect);
191 : }
192 0 : void UnionRectEdges(const nsRect& aRect1, const nsRect& aRect2)
193 : {
194 0 : *this = aRect1.UnionEdges(aRect2);
195 0 : }
196 0 : nsRect Union(const nsRect& aRect) const
197 : {
198 0 : return SaturatingUnion(aRect);
199 : }
200 0 : void UnionRect(const nsRect& aRect1, const nsRect& aRect2)
201 : {
202 0 : *this = aRect1.Union(aRect2);
203 0 : }
204 : #endif
205 :
206 : void SaturatingUnionRect(const nsRect& aRect1, const nsRect& aRect2)
207 : {
208 : *this = aRect1.SaturatingUnion(aRect2);
209 : }
210 : void SaturatingUnionRectEdges(const nsRect& aRect1, const nsRect& aRect2)
211 : {
212 : *this = aRect1.SaturatingUnionEdges(aRect2);
213 : }
214 :
215 : // Converts this rect from aFromAPP, an appunits per pixel ratio, to aToAPP.
216 : // In the RoundOut version we make the rect the smallest rect containing the
217 : // unrounded result. In the RoundIn version we make the rect the largest rect
218 : // contained in the unrounded result.
219 : // Note: this can turn an empty rectangle into a non-empty rectangle
220 : inline nsRect ConvertAppUnitsRoundOut(PRInt32 aFromAPP, PRInt32 aToAPP) const;
221 : inline nsRect ConvertAppUnitsRoundIn(PRInt32 aFromAPP, PRInt32 aToAPP) const;
222 :
223 : inline nsIntRect ScaleToNearestPixels(float aXScale, float aYScale,
224 : nscoord aAppUnitsPerPixel) const;
225 : inline nsIntRect ToNearestPixels(nscoord aAppUnitsPerPixel) const;
226 : // Note: this can turn an empty rectangle into a non-empty rectangle
227 : inline nsIntRect ScaleToOutsidePixels(float aXScale, float aYScale,
228 : nscoord aAppUnitsPerPixel) const;
229 : // Note: this can turn an empty rectangle into a non-empty rectangle
230 : inline nsIntRect ToOutsidePixels(nscoord aAppUnitsPerPixel) const;
231 : inline nsIntRect ScaleToInsidePixels(float aXScale, float aYScale,
232 : nscoord aAppUnitsPerPixel) const;
233 : inline nsIntRect ToInsidePixels(nscoord aAppUnitsPerPixel) const;
234 : };
235 :
236 : struct NS_GFX nsIntRect :
237 0 : public mozilla::gfx::BaseRect<PRInt32, nsIntRect, nsIntPoint, nsIntSize, nsIntMargin> {
238 : typedef mozilla::gfx::BaseRect<PRInt32, nsIntRect, nsIntPoint, nsIntSize, nsIntMargin> Super;
239 :
240 : // Constructors
241 269 : nsIntRect() : Super()
242 : {
243 269 : }
244 49 : nsIntRect(const nsIntRect& aRect) : Super(aRect)
245 : {
246 49 : }
247 60 : nsIntRect(const nsIntPoint& aOrigin, const nsIntSize &aSize) : Super(aOrigin, aSize)
248 : {
249 60 : }
250 1704 : nsIntRect(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) :
251 1704 : Super(aX, aY, aWidth, aHeight)
252 : {
253 1704 : }
254 :
255 : inline nsRect ToAppUnits(nscoord aAppUnitsPerPixel) const;
256 :
257 : // Returns a special nsIntRect that's used in some places to signify
258 : // "all available space".
259 0 : static const nsIntRect& GetMaxSizedIntRect() { return kMaxSizedIntRect; }
260 :
261 : // This is here only to keep IPDL-generated code happy. DO NOT USE.
262 0 : bool operator==(const nsIntRect& aRect) const
263 : {
264 0 : return IsEqualEdges(aRect);
265 : }
266 :
267 : protected:
268 : static const nsIntRect kMaxSizedIntRect;
269 : };
270 :
271 : /*
272 : * App Unit/Pixel conversions
273 : */
274 :
275 : inline nsRect
276 0 : nsRect::ConvertAppUnitsRoundOut(PRInt32 aFromAPP, PRInt32 aToAPP) const
277 : {
278 0 : if (aFromAPP == aToAPP) {
279 0 : return *this;
280 : }
281 :
282 0 : nsRect rect;
283 0 : nscoord right = NSToCoordCeil(NSCoordScale(XMost(), aFromAPP, aToAPP));
284 0 : nscoord bottom = NSToCoordCeil(NSCoordScale(YMost(), aFromAPP, aToAPP));
285 0 : rect.x = NSToCoordFloor(NSCoordScale(x, aFromAPP, aToAPP));
286 0 : rect.y = NSToCoordFloor(NSCoordScale(y, aFromAPP, aToAPP));
287 0 : rect.width = (right - rect.x);
288 0 : rect.height = (bottom - rect.y);
289 :
290 0 : return rect;
291 : }
292 :
293 : inline nsRect
294 0 : nsRect::ConvertAppUnitsRoundIn(PRInt32 aFromAPP, PRInt32 aToAPP) const
295 : {
296 0 : if (aFromAPP == aToAPP) {
297 0 : return *this;
298 : }
299 :
300 0 : nsRect rect;
301 0 : nscoord right = NSToCoordFloor(NSCoordScale(XMost(), aFromAPP, aToAPP));
302 0 : nscoord bottom = NSToCoordFloor(NSCoordScale(YMost(), aFromAPP, aToAPP));
303 0 : rect.x = NSToCoordCeil(NSCoordScale(x, aFromAPP, aToAPP));
304 0 : rect.y = NSToCoordCeil(NSCoordScale(y, aFromAPP, aToAPP));
305 0 : rect.width = (right - rect.x);
306 0 : rect.height = (bottom - rect.y);
307 :
308 0 : return rect;
309 : }
310 :
311 : // scale the rect but round to preserve centers
312 : inline nsIntRect
313 0 : nsRect::ScaleToNearestPixels(float aXScale, float aYScale,
314 : nscoord aAppUnitsPerPixel) const
315 : {
316 0 : nsIntRect rect;
317 0 : rect.x = NSToIntRoundUp(NSAppUnitsToDoublePixels(x, aAppUnitsPerPixel) * aXScale);
318 0 : rect.y = NSToIntRoundUp(NSAppUnitsToDoublePixels(y, aAppUnitsPerPixel) * aYScale);
319 : rect.width = NSToIntRoundUp(NSAppUnitsToDoublePixels(XMost(),
320 0 : aAppUnitsPerPixel) * aXScale) - rect.x;
321 : rect.height = NSToIntRoundUp(NSAppUnitsToDoublePixels(YMost(),
322 0 : aAppUnitsPerPixel) * aYScale) - rect.y;
323 : return rect;
324 : }
325 :
326 : // scale the rect but round to smallest containing rect
327 : inline nsIntRect
328 0 : nsRect::ScaleToOutsidePixels(float aXScale, float aYScale,
329 : nscoord aAppUnitsPerPixel) const
330 : {
331 0 : nsIntRect rect;
332 0 : rect.x = NSToIntFloor(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) * aXScale);
333 0 : rect.y = NSToIntFloor(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) * aYScale);
334 : rect.width = NSToIntCeil(NSAppUnitsToFloatPixels(XMost(),
335 0 : float(aAppUnitsPerPixel)) * aXScale) - rect.x;
336 : rect.height = NSToIntCeil(NSAppUnitsToFloatPixels(YMost(),
337 0 : float(aAppUnitsPerPixel)) * aYScale) - rect.y;
338 : return rect;
339 : }
340 :
341 : // scale the rect but round to largest contained rect
342 : inline nsIntRect
343 0 : nsRect::ScaleToInsidePixels(float aXScale, float aYScale,
344 : nscoord aAppUnitsPerPixel) const
345 : {
346 0 : nsIntRect rect;
347 0 : rect.x = NSToIntCeil(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) * aXScale);
348 0 : rect.y = NSToIntCeil(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) * aYScale);
349 : rect.width = NSToIntFloor(NSAppUnitsToFloatPixels(XMost(),
350 0 : float(aAppUnitsPerPixel)) * aXScale) - rect.x;
351 : rect.height = NSToIntFloor(NSAppUnitsToFloatPixels(YMost(),
352 0 : float(aAppUnitsPerPixel)) * aYScale) - rect.y;
353 : return rect;
354 : }
355 :
356 : inline nsIntRect
357 0 : nsRect::ToNearestPixels(nscoord aAppUnitsPerPixel) const
358 : {
359 0 : return ScaleToNearestPixels(1.0f, 1.0f, aAppUnitsPerPixel);
360 : }
361 :
362 : inline nsIntRect
363 0 : nsRect::ToOutsidePixels(nscoord aAppUnitsPerPixel) const
364 : {
365 0 : return ScaleToOutsidePixels(1.0f, 1.0f, aAppUnitsPerPixel);
366 : }
367 :
368 : inline nsIntRect
369 0 : nsRect::ToInsidePixels(nscoord aAppUnitsPerPixel) const
370 : {
371 0 : return ScaleToInsidePixels(1.0f, 1.0f, aAppUnitsPerPixel);
372 : }
373 :
374 : // app units are integer multiples of pixels, so no rounding needed
375 : inline nsRect
376 0 : nsIntRect::ToAppUnits(nscoord aAppUnitsPerPixel) const
377 : {
378 : return nsRect(NSIntPixelsToAppUnits(x, aAppUnitsPerPixel),
379 : NSIntPixelsToAppUnits(y, aAppUnitsPerPixel),
380 : NSIntPixelsToAppUnits(width, aAppUnitsPerPixel),
381 0 : NSIntPixelsToAppUnits(height, aAppUnitsPerPixel));
382 : }
383 :
384 : #ifdef DEBUG
385 : // Diagnostics
386 : extern NS_GFX FILE* operator<<(FILE* out, const nsRect& rect);
387 : #endif // DEBUG
388 :
389 : #endif /* NSRECT_H */
|