Merge, a=backout
[mozilla-central.git] / gfx / src / nsRect.h
blob5c557aa320fd18c7c260e7702dfdb71f70492fd2
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
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/
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.
15 * The Original Code is mozilla.org code.
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.
22 * Contributor(s):
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.
36 * ***** END LICENSE BLOCK ***** */
39 #ifndef NSRECT_H
40 #define NSRECT_H
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"
50 struct nsIntRect;
52 struct NS_GFX nsRect {
53 nscoord x, y;
54 nscoord width, height;
56 // Constructors
57 nsRect() : x(0), y(0), width(0), height(0) {
58 MOZ_COUNT_CTOR(nsRect);
60 nsRect(const nsRect& aRect) {
61 MOZ_COUNT_CTOR(nsRect);
62 *this = aRect;
64 nsRect(const nsPoint& aOrigin, const nsSize &aSize) {
65 MOZ_COUNT_CTOR(nsRect);
66 x = aOrigin.x; y = aOrigin.y;
67 width = aSize.width; height = aSize.height;
69 nsRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) {
70 MOZ_COUNT_CTOR(nsRect);
71 x = aX; y = aY; width = aWidth; height = aHeight;
72 VERIFY_COORD(x); VERIFY_COORD(y); VERIFY_COORD(width); VERIFY_COORD(height);
75 #ifdef NS_BUILD_REFCNT_LOGGING
76 ~nsRect() {
77 MOZ_COUNT_DTOR(nsRect);
79 #endif
81 // Emptiness. An empty rect is one that has no area, i.e. its height or width
82 // is <= 0
83 PRBool IsEmpty() const {
84 return (PRBool) ((height <= 0) || (width <= 0));
86 void Empty() {width = height = 0;}
88 // Containment
89 PRBool Contains(const nsRect& aRect) const;
90 PRBool Contains(nscoord aX, nscoord aY) const;
91 PRBool Contains(const nsPoint& aPoint) const {return Contains(aPoint.x, aPoint.y);}
93 // Intersection. Returns TRUE if the receiver overlaps aRect and
94 // FALSE otherwise
95 PRBool Intersects(const nsRect& aRect) const;
97 // Computes the area in which aRect1 and aRect2 overlap, and fills 'this' with
98 // the result. Returns FALSE if the rectangles don't intersect, and sets 'this'
99 // rect to be an empty rect.
101 // 'this' can be the same object as either aRect1 or aRect2
102 PRBool IntersectRect(const nsRect& aRect1, const nsRect& aRect2);
104 // Computes the smallest rectangle that contains both aRect1 and aRect2 and
105 // fills 'this' with the result, ignoring empty input rectangles.
106 // Returns FALSE and sets 'this' rect to be an empty rect if both aRect1
107 // and aRect2 are empty.
109 // 'this' can be the same object as either aRect1 or aRect2
110 PRBool UnionRect(const nsRect& aRect1, const nsRect& aRect2);
112 // Computes the smallest rectangle that contains both aRect1 and aRect2,
113 // where empty input rectangles are allowed to affect the result; the
114 // top-left of an empty input rectangle will be inside or on the edge of
115 // the result.
117 // 'this' can be the same object as either aRect1 or aRect2
118 void UnionRectIncludeEmpty(const nsRect& aRect1, const nsRect& aRect2);
120 // Accessors
121 void SetRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) {
122 x = aX; y = aY; width = aWidth; height = aHeight;
124 void SetRect(const nsPoint& aPt, const nsSize& aSize) {
125 SetRect(aPt.x, aPt.y, aSize.width, aSize.height);
127 void MoveTo(nscoord aX, nscoord aY) {x = aX; y = aY;}
128 void MoveTo(const nsPoint& aPoint) {x = aPoint.x; y = aPoint.y;}
129 void MoveBy(nscoord aDx, nscoord aDy) {x += aDx; y += aDy;}
130 void MoveBy(const nsPoint& aPoint) {x += aPoint.x; y += aPoint.y;}
131 void SizeTo(nscoord aWidth, nscoord aHeight) {width = aWidth; height = aHeight;}
132 void SizeTo(const nsSize& aSize) {SizeTo(aSize.width, aSize.height);}
133 void SizeBy(nscoord aDeltaWidth, nscoord aDeltaHeight) {width += aDeltaWidth;
134 height += aDeltaHeight;}
136 // Inflate the rect by the specified width/height or margin
137 void Inflate(nscoord aDx, nscoord aDy);
138 void Inflate(const nsSize& aSize) {Inflate(aSize.width, aSize.height);}
139 void Inflate(const nsMargin& aMargin);
141 // Deflate the rect by the specified width/height or margin
142 void Deflate(nscoord aDx, nscoord aDy);
143 void Deflate(const nsSize& aSize) {Deflate(aSize.width, aSize.height);}
144 void Deflate(const nsMargin& aMargin);
146 // Overloaded operators. Note that '=' isn't defined so we'll get the
147 // compiler generated default assignment operator.
148 PRBool operator==(const nsRect& aRect) const {
149 return (PRBool) ((IsEmpty() && aRect.IsEmpty()) ||
150 ((x == aRect.x) && (y == aRect.y) &&
151 (width == aRect.width) && (height == aRect.height)));
153 PRBool operator!=(const nsRect& aRect) const {
154 return (PRBool) !operator==(aRect);
157 // Useful when we care about the exact x/y/width/height values being
158 // equal (i.e. we care about differences in empty rectangles)
159 PRBool IsExactEqual(const nsRect& aRect) const {
160 return x == aRect.x && y == aRect.y &&
161 width == aRect.width && height == aRect.height;
164 // Arithmetic with nsPoints
165 nsRect operator+(const nsPoint& aPoint) const {
166 return nsRect(x + aPoint.x, y + aPoint.y, width, height);
168 nsRect operator-(const nsPoint& aPoint) const {
169 return nsRect(x - aPoint.x, y - aPoint.y, width, height);
171 nsRect& operator+=(const nsPoint& aPoint) {x += aPoint.x; y += aPoint.y; return *this;}
172 nsRect& operator-=(const nsPoint& aPoint) {x -= aPoint.x; y -= aPoint.y; return *this;}
174 // Arithmetic with nsMargins
175 nsMargin operator-(const nsRect& aRect) const; // Find difference as nsMargin
176 nsRect& operator+=(const nsMargin& aMargin) { Inflate(aMargin); return *this; }
177 nsRect& operator-=(const nsMargin& aMargin) { Deflate(aMargin); return *this; }
178 nsRect operator+(const nsMargin& aMargin) const { return nsRect(*this) += aMargin; }
179 nsRect operator-(const nsMargin& aMargin) const { return nsRect(*this) -= aMargin; }
181 // Scale by aScale, converting coordinates to integers so that the result is
182 // the smallest integer-coordinate rectangle containing the unrounded result.
183 nsRect& ScaleRoundOut(float aScale) { return ScaleRoundOut(aScale, aScale); }
184 nsRect& ScaleRoundOut(float aXScale, float aYScale);
186 // Converts this rect from aFromAPP, an appunits per pixel ratio, to aToAPP.
187 // In the RoundOut version we make the rect the smallest rect containing the
188 // unrounded result. In the RoundIn version we make the rect the largest rect
189 // contained in the unrounded result.
190 inline nsRect ConvertAppUnitsRoundOut(PRInt32 aFromAPP, PRInt32 aToAPP) const;
191 inline nsRect ConvertAppUnitsRoundIn(PRInt32 aFromAPP, PRInt32 aToAPP) const;
193 // Helpers for accessing the vertices
194 nsPoint TopLeft() const { return nsPoint(x, y); }
195 nsPoint TopRight() const { return nsPoint(XMost(), y); }
196 nsPoint BottomLeft() const { return nsPoint(x, YMost()); }
197 nsPoint BottomRight() const { return nsPoint(XMost(), YMost()); }
199 nsSize Size() const { return nsSize(width, height); }
201 // Helper methods for computing the extents
202 nscoord XMost() const {return x + width;}
203 nscoord YMost() const {return y + height;}
205 inline nsIntRect ToNearestPixels(nscoord aAppUnitsPerPixel) const;
206 inline nsIntRect ToOutsidePixels(nscoord aAppUnitsPerPixel) const;
207 inline nsIntRect ToInsidePixels(nscoord aAppUnitsPerPixel) const;
210 struct NS_GFX nsIntRect {
211 PRInt32 x, y;
212 PRInt32 width, height;
214 // Constructors
215 nsIntRect() : x(0), y(0), width(0), height(0) {}
216 nsIntRect(const nsIntRect& aRect) {*this = aRect;}
217 nsIntRect(const nsIntPoint& aOrigin, const nsIntSize &aSize) {
218 x = aOrigin.x; y = aOrigin.y;
219 width = aSize.width; height = aSize.height;
221 nsIntRect(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) {
222 x = aX; y = aY; width = aWidth; height = aHeight;
225 // Emptiness. An empty rect is one that has no area, i.e. its height or width
226 // is <= 0
227 PRBool IsEmpty() const {
228 return (PRBool) ((height <= 0) || (width <= 0));
230 void Empty() {width = height = 0;}
232 // Inflate the rect by the specified width/height or margin
233 void Inflate(PRInt32 aDx, PRInt32 aDy) {
234 x -= aDx;
235 y -= aDy;
236 width += aDx*2;
237 height += aDy*2;
239 void Inflate(const nsIntMargin &aMargin) {
240 x -= aMargin.left;
241 y -= aMargin.top;
242 width += aMargin.left + aMargin.right;
243 height += aMargin.top + aMargin.bottom;
246 // Deflate the rect by the specified width/height or margin
247 void Deflate(PRInt32 aDx, PRInt32 aDy) {
248 x += aDx;
249 y += aDy;
250 width -= aDx*2;
251 height -= aDy*2;
253 void Deflate(const nsIntMargin &aMargin) {
254 x += aMargin.left;
255 y += aMargin.top;
256 width -= (aMargin.left + aMargin.right);
257 height -= (aMargin.top + aMargin.bottom);
260 // Overloaded operators. Note that '=' isn't defined so we'll get the
261 // compiler generated default assignment operator.
262 PRBool operator==(const nsIntRect& aRect) const {
263 return (PRBool) ((IsEmpty() && aRect.IsEmpty()) ||
264 ((x == aRect.x) && (y == aRect.y) &&
265 (width == aRect.width) && (height == aRect.height)));
267 PRBool operator!=(const nsIntRect& aRect) const {
268 return (PRBool) !operator==(aRect);
271 nsIntRect operator+(const nsIntPoint& aPoint) const {
272 return nsIntRect(x + aPoint.x, y + aPoint.y, width, height);
274 nsIntRect operator-(const nsIntPoint& aPoint) const {
275 return nsIntRect(x - aPoint.x, y - aPoint.y, width, height);
277 nsIntRect& operator+=(const nsIntPoint& aPoint) {x += aPoint.x; y += aPoint.y; return *this;}
278 nsIntRect& operator-=(const nsIntPoint& aPoint) {x -= aPoint.x; y -= aPoint.y; return *this;}
280 void SetRect(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) {
281 x = aX; y = aY; width = aWidth; height = aHeight;
284 void MoveTo(PRInt32 aX, PRInt32 aY) {x = aX; y = aY;}
285 void MoveTo(const nsIntPoint& aPoint) {x = aPoint.x; y = aPoint.y;}
286 void MoveBy(PRInt32 aDx, PRInt32 aDy) {x += aDx; y += aDy;}
287 void MoveBy(const nsIntPoint& aPoint) {x += aPoint.x; y += aPoint.y;}
288 void SizeTo(PRInt32 aWidth, PRInt32 aHeight) {width = aWidth; height = aHeight;}
289 void SizeTo(const nsIntSize& aSize) {SizeTo(aSize.width, aSize.height);}
290 void SizeBy(PRInt32 aDeltaWidth, PRInt32 aDeltaHeight) {width += aDeltaWidth;
291 height += aDeltaHeight;}
293 PRBool Contains(const nsIntRect& aRect) const
295 return aRect.IsEmpty() ||
296 (PRBool) ((aRect.x >= x) && (aRect.y >= y) &&
297 (aRect.XMost() <= XMost()) && (aRect.YMost() <= YMost()));
299 PRBool Contains(PRInt32 aX, PRInt32 aY) const
301 return (PRBool) ((aX >= x) && (aY >= y) &&
302 (aX < XMost()) && (aY < YMost()));
304 PRBool Contains(const nsIntPoint& aPoint) const { return Contains(aPoint.x, aPoint.y); }
306 // Intersection. Returns TRUE if the receiver overlaps aRect and
307 // FALSE otherwise
308 PRBool Intersects(const nsIntRect& aRect) const {
309 return (PRBool) ((x < aRect.XMost()) && (y < aRect.YMost()) &&
310 (aRect.x < XMost()) && (aRect.y < YMost()));
313 // Computes the area in which aRect1 and aRect2 overlap, and fills 'this' with
314 // the result. Returns FALSE if the rectangles don't intersect, and sets 'this'
315 // rect to be an empty rect.
317 // 'this' can be the same object as either aRect1 or aRect2
318 PRBool IntersectRect(const nsIntRect& aRect1, const nsIntRect& aRect2);
320 // Computes the smallest rectangle that contains both aRect1 and aRect2 and
321 // fills 'this' with the result. Returns FALSE and sets 'this' rect to be an
322 // empty rect if both aRect1 and aRect2 are empty
324 // 'this' can be the same object as either aRect1 or aRect2
325 PRBool UnionRect(const nsIntRect& aRect1, const nsIntRect& aRect2);
327 // Helpers for accessing the vertices
328 nsIntPoint TopLeft() const { return nsIntPoint(x, y); }
329 nsIntPoint TopRight() const { return nsIntPoint(XMost(), y); }
330 nsIntPoint BottomLeft() const { return nsIntPoint(x, YMost()); }
331 nsIntPoint BottomRight() const { return nsIntPoint(XMost(), YMost()); }
333 nsIntSize Size() const { return nsIntSize(width, height); }
335 // Helper methods for computing the extents
336 PRInt32 XMost() const {return x + width;}
337 PRInt32 YMost() const {return y + height;}
339 inline nsRect ToAppUnits(nscoord aAppUnitsPerPixel) const;
341 // Returns a special nsIntRect that's used in some places to signify
342 // "all available space".
343 static const nsIntRect& GetMaxSizedIntRect() { return kMaxSizedIntRect; }
345 protected:
346 static const nsIntRect kMaxSizedIntRect;
350 * App Unit/Pixel conversions
353 inline nsRect
354 nsRect::ConvertAppUnitsRoundOut(PRInt32 aFromAPP, PRInt32 aToAPP) const
356 if (aFromAPP == aToAPP) {
357 return *this;
360 nsRect rect;
361 nscoord right = NSToCoordCeil(NSCoordScale(XMost(), aFromAPP, aToAPP));
362 nscoord bottom = NSToCoordCeil(NSCoordScale(YMost(), aFromAPP, aToAPP));
363 rect.x = NSToCoordFloor(NSCoordScale(x, aFromAPP, aToAPP));
364 rect.y = NSToCoordFloor(NSCoordScale(y, aFromAPP, aToAPP));
365 rect.width = (right - rect.x);
366 rect.height = (bottom - rect.y);
368 return rect;
371 inline nsRect
372 nsRect::ConvertAppUnitsRoundIn(PRInt32 aFromAPP, PRInt32 aToAPP) const
374 if (aFromAPP == aToAPP) {
375 return *this;
378 nsRect rect;
379 nscoord right = NSToCoordFloor(NSCoordScale(XMost(), aFromAPP, aToAPP));
380 nscoord bottom = NSToCoordFloor(NSCoordScale(YMost(), aFromAPP, aToAPP));
381 rect.x = NSToCoordCeil(NSCoordScale(x, aFromAPP, aToAPP));
382 rect.y = NSToCoordCeil(NSCoordScale(y, aFromAPP, aToAPP));
383 rect.width = (right - rect.x);
384 rect.height = (bottom - rect.y);
386 return rect;
389 // scale the rect but round to preserve centers
390 inline nsIntRect
391 nsRect::ToNearestPixels(nscoord aAppUnitsPerPixel) const
393 nsIntRect rect;
394 rect.x = NSToIntRoundUp(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)));
395 rect.y = NSToIntRoundUp(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)));
396 rect.width = NSToIntRoundUp(NSAppUnitsToFloatPixels(XMost(),
397 float(aAppUnitsPerPixel))) - rect.x;
398 rect.height = NSToIntRoundUp(NSAppUnitsToFloatPixels(YMost(),
399 float(aAppUnitsPerPixel))) - rect.y;
400 return rect;
403 // scale the rect but round to smallest containing rect
404 inline nsIntRect
405 nsRect::ToOutsidePixels(nscoord aAppUnitsPerPixel) const
407 nsIntRect rect;
408 rect.x = NSToIntFloor(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)));
409 rect.y = NSToIntFloor(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)));
410 rect.width = NSToIntCeil(NSAppUnitsToFloatPixels(XMost(),
411 float(aAppUnitsPerPixel))) - rect.x;
412 rect.height = NSToIntCeil(NSAppUnitsToFloatPixels(YMost(),
413 float(aAppUnitsPerPixel))) - rect.y;
414 return rect;
417 // scale the rect but round to largest contained rect
418 inline nsIntRect
419 nsRect::ToInsidePixels(nscoord aAppUnitsPerPixel) const
421 nsIntRect rect;
422 rect.x = NSToIntCeil(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)));
423 rect.y = NSToIntCeil(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)));
424 rect.width = NSToIntFloor(NSAppUnitsToFloatPixels(XMost(),
425 float(aAppUnitsPerPixel))) - rect.x;
426 rect.height = NSToIntFloor(NSAppUnitsToFloatPixels(YMost(),
427 float(aAppUnitsPerPixel))) - rect.y;
428 return rect;
431 // app units are integer multiples of pixels, so no rounding needed
432 inline nsRect
433 nsIntRect::ToAppUnits(nscoord aAppUnitsPerPixel) const
435 return nsRect(NSIntPixelsToAppUnits(x, aAppUnitsPerPixel),
436 NSIntPixelsToAppUnits(y, aAppUnitsPerPixel),
437 NSIntPixelsToAppUnits(width, aAppUnitsPerPixel),
438 NSIntPixelsToAppUnits(height, aAppUnitsPerPixel));
441 #ifdef DEBUG
442 // Diagnostics
443 extern NS_GFX FILE* operator<<(FILE* out, const nsRect& rect);
444 #endif // DEBUG
446 #endif /* NSRECT_H */