Bug 641426. Part 7: Create Rect template. r=joe,sr=cjones
authorRobert O'Callahan <robert@ocallahan.org>
Tue, 19 Apr 2011 15:07:48 +1200
changeset 68282 8d64029c1725afde6439212100ffb392df3722ff
parent 68281 91e75937d34ab641eb593651be6f110f3539c181
child 68283 fc1ed658bf4b8214bc480dc4e005ea56d364c152
push idunknown
push userunknown
push dateunknown
reviewersjoe, cjones
bugs641426
milestone6.0a1
Bug 641426. Part 7: Create Rect template. r=joe,sr=cjones
gfx/src/BaseRect.h
gfx/src/Makefile.in
gfx/src/nsRect.cpp
gfx/src/nsRect.h
gfx/thebes/gfxRect.cpp
gfx/thebes/gfxRect.h
layout/base/nsLayoutUtils.cpp
layout/generic/nsObjectFrame.cpp
layout/xul/base/src/nsMenuPopupFrame.cpp
layout/xul/base/src/nsResizerFrame.cpp
new file mode 100644
--- /dev/null
+++ b/gfx/src/BaseRect.h
@@ -0,0 +1,314 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
+ * ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Corporation code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Robert O'Callahan <robert@ocallahan.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef MOZILLA_BASERECT_H_
+#define MOZILLA_BASERECT_H_
+
+#include "nsAlgorithm.h"
+
+namespace mozilla {
+
+/**
+ * Rectangles have two interpretations: a set of (zero-size) points,
+ * and a rectangular area of the plane. Most rectangle operations behave
+ * the same no matter what interpretation is being used, but some operations
+ * differ:
+ * -- Equality tests behave differently. When a rectangle represents an area,
+ * all zero-width and zero-height rectangles are equal to each other since they
+ * represent the empty area. But when a rectangle represents a set of
+ * mathematical points, zero-width and zero-height rectangles can be unequal.
+ * -- The union operation can behave differently. When rectangles represent
+ * areas, taking the union of a zero-width or zero-height rectangle with
+ * another rectangle can just ignore the empty rectangle. But when rectangles
+ * represent sets of mathematical points, we may need to extend the latter
+ * rectangle to include the points of a zero-width or zero-height rectangle.
+ *
+ * To ensure that these interpretations are explicitly disambiguated, we
+ * deny access to the == and != operators and require use of IsEqualEdges and
+ * IsEqualInterior instead. Similarly we provide separate Union and UnionEdges
+ * methods.
+ *
+ * Do not use this class directly. Subclass it, pass that subclass as the
+ * Sub parameter, and only use that subclass.
+ */
+template <class T, class Sub, class Point, class SizeT, class Margin>
+struct BaseRect {
+  T x, y, width, height;
+
+  // Constructors
+  BaseRect() : x(0), y(0), width(0), height(0) {}
+  BaseRect(const Point& aOrigin, const SizeT &aSize) :
+      x(aOrigin.x), y(aOrigin.y), width(aSize.width), height(aSize.height)
+  {
+  }
+  BaseRect(T aX, T aY, T aWidth, T aHeight) :
+      x(aX), y(aY), width(aWidth), height(aHeight)
+  {
+  }
+
+  // Emptiness. An empty rect is one that has no area, i.e. its height or width
+  // is <= 0
+  bool IsEmpty() const { return height <= 0 || width <= 0; }
+  void SetEmpty() { width = height = 0; }
+
+  // Returns true if this rectangle contains the interior of aRect. Always
+  // returns true if aRect is empty, and always returns false is aRect is
+  // nonempty but this rect is empty.
+  bool Contains(const Sub& aRect) const
+  {
+    return aRect.IsEmpty() ||
+           (x <= aRect.x && aRect.XMost() <= XMost() &&
+            y <= aRect.y && aRect.YMost() <= YMost());
+  }
+  // Returns true if this rectangle contains the rectangle (aX,aY,1,1).
+  bool Contains(T aX, T aY) const
+  {
+    return x <= aX && aX + 1 <= XMost() &&
+           y <= aY && aY + 1 <= YMost();
+  }
+  // Returns true if this rectangle contains the rectangle (aPoint.x,aPoint.y,1,1).
+  bool Contains(const Point& aPoint) const { return Contains(aPoint.x, aPoint.y); }
+
+  // Intersection. Returns TRUE if the receiver's area has non-empty
+  // intersection with aRect's area, and FALSE otherwise.
+  // Always returns false if aRect is empty or 'this' is empty.
+  bool Intersects(const Sub& aRect) const
+  {
+    return x < aRect.XMost() && aRect.x < XMost() &&
+           y < aRect.YMost() && aRect.y < YMost();
+  }
+  // Returns the rectangle containing the intersection of the points
+  // (including edges) of *this and aRect. If there are no points in that
+  // intersection, returns an empty rectangle with x/y set to the max of the x/y
+  // of *this and aRect.
+  Sub Intersect(const Sub& aRect) const
+  {
+    Sub result;
+    result.x = NS_MAX(x, aRect.x);
+    result.y = NS_MAX(y, aRect.y);
+    result.width = NS_MIN(XMost(), aRect.XMost()) - result.x;
+    result.height = NS_MIN(YMost(), aRect.YMost()) - result.y;
+    if (result.width < 0 || result.height < 0) {
+      result.SizeTo(0, 0);
+    }
+    return result;
+  }
+  // Sets *this to be the rectangle containing the intersection of the points
+  // (including edges) of *this and aRect. If there are no points in that
+  // intersection, sets *this to be an empty rectangle with x/y set to the max
+  // of the x/y of *this and aRect.
+  //
+  // 'this' can be the same object as either aRect1 or aRect2
+  bool IntersectRect(const Sub& aRect1, const Sub& aRect2)
+  {
+    *static_cast<Sub*>(this) = aRect1.Intersect(aRect2);
+    return !IsEmpty();
+  }
+
+  // Returns the smallest rectangle that contains both the area of both
+  // this and aRect2.
+  // Thus, empty input rectangles are ignored.
+  // If both rectangles are empty, returns this.
+  Sub Union(const Sub& aRect) const
+  {
+    if (IsEmpty()) {
+      return aRect;
+    } else if (aRect.IsEmpty()) {
+      return *static_cast<const Sub*>(this);
+    } else {
+      return UnionEdges(aRect);
+    }
+  }
+  // Returns the smallest rectangle that contains both the points (including
+  // edges) of both aRect1 and aRect2.
+  // Thus, empty input rectangles are allowed to affect the result.
+  Sub UnionEdges(const Sub& aRect) const
+  {
+    Sub result;
+    result.x = NS_MIN(x, aRect.x);
+    result.y = NS_MIN(y, aRect.y);
+    result.width = NS_MAX(XMost(), aRect.XMost()) - result.x;
+    result.height = NS_MAX(YMost(), aRect.YMost()) - result.y;
+    return result;
+  }
+  // Computes the smallest rectangle that contains both the area of both
+  // aRect1 and aRect2, and fills 'this' with the result.
+  // Thus, empty input rectangles are ignored.
+  // If both rectangles are empty, sets 'this' to aRect2.
+  //
+  // 'this' can be the same object as either aRect1 or aRect2
+  void UnionRect(const Sub& aRect1, const Sub& aRect2)
+  {
+    *static_cast<Sub*>(this) = aRect1.Union(aRect2);
+  }
+
+  // Computes the smallest rectangle that contains both the points (including
+  // edges) of both aRect1 and aRect2.
+  // Thus, empty input rectangles are allowed to affect the result.
+  //
+  // 'this' can be the same object as either aRect1 or aRect2
+  void UnionRectEdges(const Sub& aRect1, const Sub& aRect2)
+  {
+    *static_cast<Sub*>(this) = aRect1.UnionEdges(aRect2);
+  }
+
+  void SetRect(T aX, T aY, T aWidth, T aHeight)
+  {
+    x = aX; y = aY; width = aWidth; height = aHeight;
+  }
+  void SetRect(const Point& aPt, const SizeT& aSize)
+  {
+    SetRect(aPt.x, aPt.y, aSize.width, aSize.height);
+  }
+  void MoveTo(T aX, T aY) { x = aX; y = aY; }
+  void MoveTo(const Point& aPoint) { x = aPoint.x; y = aPoint.y; }
+  void MoveBy(T aDx, T aDy) { x += aDx; y += aDy; }
+  void MoveBy(const Point& aPoint) { x += aPoint.x; y += aPoint.y; }
+  void SizeTo(T aWidth, T aHeight) { width = aWidth; height = aHeight; }
+  void SizeTo(const SizeT& aSize) { width = aSize.width; height = aSize.height; }
+
+  void Inflate(T aDx, T aDy)
+  {
+    x -= aDx;
+    y -= aDy;
+    width += 2 * aDx;
+    height += 2 * aDy;
+  }
+  void Inflate(const Margin& aMargin)
+  {
+    x -= aMargin.left;
+    y -= aMargin.top;
+    width += aMargin.LeftRight();
+    height += aMargin.TopBottom();
+  }
+
+  void Deflate(T aDx, T aDy)
+  {
+    x += aDx;
+    y += aDy;
+    width = NS_MAX(T(0), width - 2 * aDx);
+    height = NS_MAX(T(0), height - 2 * aDy);
+  }
+  void Deflate(const Margin& aMargin)
+  {
+    x += aMargin.left;
+    y += aMargin.top;
+    width = NS_MAX(T(0), width - aMargin.LeftRight());
+    height = NS_MAX(T(0), height - aMargin.TopBottom());
+  }
+
+  // Return true if the rectangles contain the same set of points, including
+  // points on the edges.
+  // Use when we care about the exact x/y/width/height values being
+  // equal (i.e. we care about differences in empty rectangles).
+  bool IsEqualEdges(const Sub& aRect) const
+  {
+    return x == aRect.x && y == aRect.y &&
+           width == aRect.width && height == aRect.height;
+  }
+  // Return true if the rectangles contain the same area of the plane.
+  // Use when we do not care about differences in empty rectangles.
+  bool IsEqualInterior(const Sub& aRect) const
+  {
+    return IsEqualEdges(aRect) || (IsEmpty() && aRect.IsEmpty());
+  }
+
+  Sub operator+(const Point& aPoint) const
+  {
+    return Sub(x + aPoint.x, y + aPoint.y, width, height);
+  }
+  Sub operator-(const Point& aPoint) const
+  {
+    return Sub(x - aPoint.x, y - aPoint.y, width, height);
+  }
+  Sub& operator+=(const Point& aPoint)
+  {
+    MoveBy(aPoint);
+    return *static_cast<Sub*>(this);
+  }
+  Sub& operator-=(const Point& aPoint)
+  {
+    MoveBy(-aPoint);
+    return *static_cast<Sub*>(this);
+  }
+
+  // Find difference as a Margin
+  Margin operator-(const Sub& aRect) const
+  {
+    return Margin(aRect.x - x, aRect.y - y,
+                  XMost() - aRect.XMost(), YMost() - aRect.YMost());
+  }
+
+  // Helpers for accessing the vertices
+  Point TopLeft() const { return Point(x, y); }
+  Point TopRight() const { return Point(XMost(), y); }
+  Point BottomLeft() const { return Point(x, YMost()); }
+  Point BottomRight() const { return Point(XMost(), YMost()); }
+  Point Center() const { return Point(x, y) + Point(width, height)/2; }
+  SizeT Size() const { return SizeT(width, height); }
+
+  // Helper methods for computing the extents
+  T X() const { return x; }
+  T Y() const { return y; }
+  T Width() const { return width; }
+  T Height() const { return height; }
+  T XMost() const { return x + width; }
+  T YMost() const { return y + height; }
+
+  // Scale 'this' by aScale, converting coordinates to integers so that the result is
+  // the smallest integer-coordinate rectangle containing the unrounded result.
+  void ScaleRoundOut(double aScale) { ScaleRoundOut(aScale, aScale); }
+  void ScaleRoundOut(double aXScale, double aYScale)
+  {
+    T right = static_cast<T>(NS_ceil(double(XMost()) * aXScale));
+    T bottom = static_cast<T>(NS_ceil(double(YMost()) * aYScale));
+    x = static_cast<T>(NS_floor(double(x) * aXScale));
+    y = static_cast<T>(NS_floor(double(y) * aYScale));
+    width = right - x;
+    height = bottom - y;
+  }
+
+private:
+  // Do not use the default operator== or operator!= !
+  // Use IsEqualEdges or IsEqualInterior explicitly.
+  bool operator==(const Sub& aRect) const { return false; }
+  bool operator!=(const Sub& aRect) const { return false; }
+};
+
+}
+
+#endif /* MOZILLA_BASERECT_H_ */
--- a/gfx/src/Makefile.in
+++ b/gfx/src/Makefile.in
@@ -59,16 +59,17 @@ XPIDLSRCS = \
 	gfxidltypes.idl \
 	$(NULL)
 
 EXPORTS_NAMESPACES = mozilla
 
 EXPORTS_mozilla = \
 	BaseMargin.h \
 	BasePoint.h \
+	BaseRect.h \
 	BaseSize.h \
 	$(NULL)
 
 EXPORTS	= \
 	gfxCore.h \
 	gfxCrashReporterUtils.h \
 	nsColor.h \
 	nsColorNames.h \
--- a/gfx/src/nsRect.cpp
+++ b/gfx/src/nsRect.cpp
@@ -39,177 +39,19 @@
 #include "nsString.h"
 #include "nsIDeviceContext.h"
 #include "prlog.h"
 #include <limits.h>
 
 // the mozilla::css::Side sequence must match the nsMargin nscoord sequence
 PR_STATIC_ASSERT((NS_SIDE_TOP == 0) && (NS_SIDE_RIGHT == 1) && (NS_SIDE_BOTTOM == 2) && (NS_SIDE_LEFT == 3));
 
-
 /* static */
 const nsIntRect nsIntRect::kMaxSizedIntRect(0, 0, INT_MAX, INT_MAX);
 
-// Containment
-PRBool nsRect::Contains(nscoord aX, nscoord aY) const
-{
-  return (PRBool) ((aX >= x) && (aY >= y) &&
-                   (aX < XMost()) && (aY < YMost()));
-}
-
-//Also Returns true if aRect is Empty
-PRBool nsRect::Contains(const nsRect &aRect) const
-{
-  return aRect.IsEmpty() ||
-          ((PRBool) ((aRect.x >= x) && (aRect.y >= y) &&
-                    (aRect.XMost() <= XMost()) && (aRect.YMost() <= YMost())));
-}
-
-// Intersection. Returns TRUE if the receiver overlaps aRect and
-// FALSE otherwise
-PRBool nsRect::Intersects(const nsRect &aRect) const
-{
-  return (PRBool) ((x < aRect.XMost()) && (y < aRect.YMost()) &&
-                   (aRect.x < XMost()) && (aRect.y < YMost()));
-}
-
-// Computes the area in which aRect1 and aRect2 overlap and fills 'this' with
-// the result. Returns FALSE if the rectangles don't intersect.
-PRBool nsRect::IntersectRect(const nsRect &aRect1, const nsRect &aRect2)
-{
-  nscoord  xmost1 = aRect1.XMost();
-  nscoord  ymost1 = aRect1.YMost();
-  nscoord  xmost2 = aRect2.XMost();
-  nscoord  ymost2 = aRect2.YMost();
-  nscoord  temp;
-
-  x = PR_MAX(aRect1.x, aRect2.x);
-  y = PR_MAX(aRect1.y, aRect2.y);
-
-  // Compute the destination width
-  temp = PR_MIN(xmost1, xmost2);
-  if (temp <= x) {
-    width = 0;
-  } else {
-    width = temp - x;
-  }
-
-  // Compute the destination height
-  temp = PR_MIN(ymost1, ymost2);
-  if (temp <= y) {
-    height = 0;
-  } else {
-    height = temp - y;
-  }
-
-  return !IsEmpty();
-}
-
-// Computes the smallest rectangle that contains both aRect1 and aRect2 and
-// fills 'this' with the result. Returns FALSE if both aRect1 and aRect2 are
-// empty and TRUE otherwise
-PRBool nsRect::UnionRect(const nsRect &aRect1, const nsRect &aRect2)
-{
-  PRBool  result = PR_TRUE;
-
-  // Is aRect1 empty?
-  if (aRect1.IsEmpty()) {
-    if (aRect2.IsEmpty()) {
-      // Both rectangles are empty which is an error
-      Empty();
-      result = PR_FALSE;
-    } else {
-      // aRect1 is empty so set the result to aRect2
-      *this = aRect2;
-    }
-  } else if (aRect2.IsEmpty()) {
-    // aRect2 is empty so set the result to aRect1
-    *this = aRect1;
-  } else {
-    UnionRectEdges(aRect1, aRect2);
-  }
-
-  return result;
-}
-
-void nsRect::UnionRectEdges(const nsRect &aRect1, const nsRect &aRect2)
-{
-  nscoord xmost1 = aRect1.XMost();
-  nscoord xmost2 = aRect2.XMost();
-  nscoord ymost1 = aRect1.YMost();
-  nscoord ymost2 = aRect2.YMost();
-
-  // Compute the origin
-  x = PR_MIN(aRect1.x, aRect2.x);
-  y = PR_MIN(aRect1.y, aRect2.y);
-
-  // Compute the size
-  width = PR_MAX(xmost1, xmost2) - x;
-  height = PR_MAX(ymost1, ymost2) - y;
-}
-
-// Inflate the rect by the specified width and height
-void nsRect::Inflate(nscoord aDx, nscoord aDy)
-{
-  x -= aDx;
-  y -= aDy;
-  width += 2 * aDx;
-  height += 2 * aDy;
-}
-
-// Inflate the rect by the specified margin
-void nsRect::Inflate(const nsMargin &aMargin)
-{
-  x -= aMargin.left;
-  y -= aMargin.top;
-  width += aMargin.left + aMargin.right;
-  height += aMargin.top + aMargin.bottom;
-}
-
-// Deflate the rect by the specified width and height
-void nsRect::Deflate(nscoord aDx, nscoord aDy)
-{
-  x += aDx;
-  y += aDy;
-  width = PR_MAX(0, width - 2 * aDx);
-  height = PR_MAX(0, height - 2 * aDy);
-}
-
-// Deflate the rect by the specified margin
-void nsRect::Deflate(const nsMargin &aMargin)
-{
-  x += aMargin.left;
-  y += aMargin.top;
-  width = PR_MAX(0, width - aMargin.LeftRight());
-  height = PR_MAX(0, height - aMargin.TopBottom());
-}
-
-// Find difference between rects as an nsMargin
-nsMargin nsRect::operator-(const nsRect& aRect) const
-{
-  nsMargin margin;
-  margin.left = aRect.x - x;
-  margin.right = XMost() - aRect.XMost();
-  margin.top = aRect.y - y;
-  margin.bottom = YMost() - aRect.YMost();
-  return margin;
-}
-
-// scale the rect but round to smallest containing rect
-nsRect& nsRect::ScaleRoundOut(float aXScale, float aYScale)
-{
-  nscoord right = NSToCoordCeil(float(XMost()) * aXScale);
-  nscoord bottom = NSToCoordCeil(float(YMost()) * aYScale);
-  x = NSToCoordFloor(float(x) * aXScale);
-  y = NSToCoordFloor(float(y) * aYScale);
-  width = (right - x);
-  height = (bottom - y);
-  return *this;
-}
-
 #ifdef DEBUG
 static bool IsFloatInteger(float aFloat)
 {
   return fabs(aFloat - NS_round(aFloat)) < 1e-6;
 }
 #endif
 
 nsRect& nsRect::ExtendForScaling(float aXMult, float aYMult)
@@ -254,90 +96,8 @@ FILE* operator<<(FILE* out, const nsRect
   tmp.AppendFloat(NSAppUnitsToFloatPixels(rect.height,
                        nsIDeviceContext::AppUnitsPerCSSPixel()));
   tmp.AppendLiteral("}");
   fputs(NS_LossyConvertUTF16toASCII(tmp).get(), out);
   return out;
 }
 
 #endif // DEBUG
-
-// Computes the area in which aRect1 and aRect2 overlap and fills 'this' with
-// the result. Returns FALSE if the rectangles don't intersect.
-PRBool nsIntRect::IntersectRect(const nsIntRect &aRect1, const nsIntRect &aRect2)
-{
-  PRInt32  xmost1 = aRect1.XMost();
-  PRInt32  ymost1 = aRect1.YMost();
-  PRInt32  xmost2 = aRect2.XMost();
-  PRInt32  ymost2 = aRect2.YMost();
-  PRInt32  temp;
-
-  x = PR_MAX(aRect1.x, aRect2.x);
-  y = PR_MAX(aRect1.y, aRect2.y);
-
-  // Compute the destination width
-  temp = PR_MIN(xmost1, xmost2);
-  if (temp <= x) {
-    Empty();
-    return PR_FALSE;
-  }
-  width = temp - x;
-
-  // Compute the destination height
-  temp = PR_MIN(ymost1, ymost2);
-  if (temp <= y) {
-    Empty();
-    return PR_FALSE;
-  }
-  height = temp - y;
-
-  return PR_TRUE;
-}
-
-// Computes the smallest rectangle that contains both aRect1 and aRect2 and
-// fills 'this' with the result. Returns FALSE if both aRect1 and aRect2 are
-// empty and TRUE otherwise
-PRBool nsIntRect::UnionRect(const nsIntRect &aRect1, const nsIntRect &aRect2)
-{
-  PRBool  result = PR_TRUE;
-
-  // Is aRect1 empty?
-  if (aRect1.IsEmpty()) {
-    if (aRect2.IsEmpty()) {
-      // Both rectangles are empty which is an error
-      Empty();
-      result = PR_FALSE;
-    } else {
-      // aRect1 is empty so set the result to aRect2
-      *this = aRect2;
-    }
-  } else if (aRect2.IsEmpty()) {
-    // aRect2 is empty so set the result to aRect1
-    *this = aRect1;
-  } else {
-    PRInt32 xmost1 = aRect1.XMost();
-    PRInt32 xmost2 = aRect2.XMost();
-    PRInt32 ymost1 = aRect1.YMost();
-    PRInt32 ymost2 = aRect2.YMost();
-
-    // Compute the origin
-    x = PR_MIN(aRect1.x, aRect2.x);
-    y = PR_MIN(aRect1.y, aRect2.y);
-
-    // Compute the size
-    width = PR_MAX(xmost1, xmost2) - x;
-    height = PR_MAX(ymost1, ymost2) - y;
-  }
-
-  return result;
-}
-
-// scale the rect but round to smallest containing rect
-nsIntRect& nsIntRect::ScaleRoundOut(float aXScale, float aYScale)
-{
-  nscoord right = NSToCoordCeil(float(XMost()) * aXScale);
-  nscoord bottom = NSToCoordCeil(float(YMost()) * aYScale);
-  x = NSToCoordFloor(float(x) * aXScale);
-  y = NSToCoordFloor(float(y) * aYScale);
-  width = (right - x);
-  height = (bottom - y);
-  return *this;
-}
--- a/gfx/src/nsRect.h
+++ b/gfx/src/nsRect.h
@@ -41,329 +41,99 @@
 
 #include <stdio.h>
 #include "nsCoord.h"
 #include "nsPoint.h"
 #include "nsSize.h"
 #include "nsMargin.h"
 #include "gfxCore.h"
 #include "nsTraceRefcnt.h"
+#include "mozilla/BaseRect.h"
 
 struct nsIntRect;
 
-struct NS_GFX nsRect {
-  nscoord x, y;
-  nscoord width, height;
+struct NS_GFX nsRect :
+  public mozilla::BaseRect<nscoord, nsRect, nsPoint, nsSize, nsMargin> {
+  typedef mozilla::BaseRect<nscoord, nsRect, nsPoint, nsSize, nsMargin> Super;
+
+  static void VERIFY_COORD(nscoord aValue) { ::VERIFY_COORD(aValue); }
 
   // Constructors
-  nsRect() : x(0), y(0), width(0), height(0) {
+  nsRect() : Super()
+  {
     MOZ_COUNT_CTOR(nsRect);
   }
-  nsRect(const nsRect& aRect) {
-    MOZ_COUNT_CTOR(nsRect);
-    *this = aRect;
-  }
-  nsRect(const nsPoint& aOrigin, const nsSize &aSize) {
+  nsRect(const nsRect& aRect) : Super(aRect)
+  {
     MOZ_COUNT_CTOR(nsRect);
-    x = aOrigin.x; y = aOrigin.y;
-    width = aSize.width; height = aSize.height;
+  }
+  nsRect(const nsPoint& aOrigin, const nsSize &aSize) : Super(aOrigin, aSize)
+  {
+    MOZ_COUNT_CTOR(nsRect);
   }
-  nsRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) {
+  nsRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) :
+      Super(aX, aY, aWidth, aHeight)
+  {
     MOZ_COUNT_CTOR(nsRect);
-    x = aX; y = aY; width = aWidth; height = aHeight;
-    VERIFY_COORD(x); VERIFY_COORD(y); VERIFY_COORD(width); VERIFY_COORD(height);
   }
 
 #ifdef NS_BUILD_REFCNT_LOGGING
   ~nsRect() {
     MOZ_COUNT_DTOR(nsRect);
   }
 #endif
-  
-  // Emptiness. An empty rect is one that has no area, i.e. its height or width
-  // is <= 0
-  PRBool IsEmpty() const {
-    return (PRBool) ((height <= 0) || (width <= 0));
-  }
-  void SetEmpty() {width = height = 0;}
 
-  // Returns true if this rectangle contains the interior of aRect. Always
-  // returns true if aRect is empty, and always returns false is aRect is
-  // nonempty but this rect is empty.
-  PRBool Contains(const nsRect& aRect) const;
-  // Returns true if this rectangle contains the given point; if the point
-  // is on the edge of the rectangle, this returns true.
-  PRBool Contains(nscoord aX, nscoord aY) const;
-  PRBool Contains(const nsPoint& aPoint) const {return Contains(aPoint.x, aPoint.y);}
-
-  // Intersection. Returns TRUE if the receiver's area has non-empty
-  // intersection with aRect's area, and FALSE otherwise.
-  // Always returns false if aRect is empty or 'this' is empty.
-  PRBool Intersects(const nsRect& aRect) const;
-
-  // Sets 'this' to be a rectangle containing the intersection of the points
-  // (including edges) of aRect1 and aRect2, or 0,0,0,0 if that intersection is
-  // empty. Returns false if the resulting rectangle is empty.
-  //
-  // 'this' can be the same object as either aRect1 or aRect2
-  PRBool IntersectRect(const nsRect& aRect1, const nsRect& aRect2);
-
-  // Computes the smallest rectangle that contains both the area of both
-  // aRect1 and aRect2, and fills 'this' with the result.
-  // Thus, empty input rectangles are ignored.
-  // Returns FALSE and sets 'this' rect to be an empty rect if both aRect1
-  // and aRect2 are empty.
-  //
-  // 'this' can be the same object as either aRect1 or aRect2
-  PRBool UnionRect(const nsRect& aRect1, const nsRect& aRect2);
-
-  // Computes the smallest rectangle that contains both the points (including
-  // edges) of both aRect1 and aRect2.
-  // Thus, empty input rectangles are allowed to affect the result.
-  //
-  // 'this' can be the same object as either aRect1 or aRect2
-  void UnionRectEdges(const nsRect& aRect1, const nsRect& aRect2);
-
-  // Accessors
-  void SetRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) {
-    x = aX; y = aY; width = aWidth; height = aHeight;
-  }
-  void SetRect(const nsPoint& aPt, const nsSize& aSize) {
-    SetRect(aPt.x, aPt.y, aSize.width, aSize.height);
-  }
-  void MoveTo(nscoord aX, nscoord aY) {x = aX; y = aY;}
-  void MoveTo(const nsPoint& aPoint) {x = aPoint.x; y = aPoint.y;}
-  void MoveBy(nscoord aDx, nscoord aDy) {x += aDx; y += aDy;}
-  void MoveBy(const nsPoint& aPoint) {x += aPoint.x; y += aPoint.y;}
-  void SizeTo(nscoord aWidth, nscoord aHeight) {width = aWidth; height = aHeight;}
-  void SizeTo(const nsSize& aSize) {SizeTo(aSize.width, aSize.height);}
-  void SizeBy(nscoord aDeltaWidth, nscoord aDeltaHeight) {width += aDeltaWidth;
-                                                          height += aDeltaHeight;}
-
-  // Inflate the rect by the specified width/height or margin
-  void Inflate(nscoord aDx, nscoord aDy);
-  void Inflate(const nsSize& aSize) {Inflate(aSize.width, aSize.height);}
-  void Inflate(const nsMargin& aMargin);
-
-  // Deflate the rect by the specified width/height or margin
-  void Deflate(nscoord aDx, nscoord aDy);
-  void Deflate(const nsSize& aSize) {Deflate(aSize.width, aSize.height);}
-  void Deflate(const nsMargin& aMargin);
-
-  // Return true if the rectangles contain the same set of points, including
-  // points on the edges.
-  // Use when we care about the exact x/y/width/height values being
-  // equal (i.e. we care about differences in empty rectangles).
-  PRBool IsEqualEdges(const nsRect& aRect) const {
-    return x == aRect.x && y == aRect.y &&
-           width == aRect.width && height == aRect.height;
-  }
-  // Return true if the rectangles contain the same area of the plane.
-  // Use when we do not care about differences in empty rectangles.
-  PRBool IsEqualInterior(const nsRect& aRect) const {
-    return IsEqualEdges(aRect) || (IsEmpty() && aRect.IsEmpty());
-  }
-
-  // Arithmetic with nsPoints
-  nsRect  operator+(const nsPoint& aPoint) const {
-    return nsRect(x + aPoint.x, y + aPoint.y, width, height);
-  }
-  nsRect  operator-(const nsPoint& aPoint) const {
-    return nsRect(x - aPoint.x, y - aPoint.y, width, height);
-  }
-  nsRect& operator+=(const nsPoint& aPoint) {x += aPoint.x; y += aPoint.y; return *this;}
-  nsRect& operator-=(const nsPoint& aPoint) {x -= aPoint.x; y -= aPoint.y; return *this;}
-
-  // Arithmetic with nsMargins
-  nsMargin operator-(const nsRect& aRect) const; // Find difference as nsMargin
-  nsRect& operator+=(const nsMargin& aMargin) { Inflate(aMargin); return *this; }
-  nsRect& operator-=(const nsMargin& aMargin) { Deflate(aMargin); return *this; }
-  nsRect  operator+(const nsMargin& aMargin) const { return nsRect(*this) += aMargin; }
-  nsRect  operator-(const nsMargin& aMargin) const { return nsRect(*this) -= aMargin; }
-
-  // Scale by aScale, converting coordinates to integers so that the result is
-  // the smallest integer-coordinate rectangle containing the unrounded result.
-  nsRect& ScaleRoundOut(float aScale) { return ScaleRoundOut(aScale, aScale); }
-  nsRect& ScaleRoundOut(float aXScale, float aYScale);
-
-  // Extend the rect outwards such that the edges are on integer boundaries
+  // Extend the rect outwards such that the edges are on integer boundaries
   // and the edges scaled by aXMult/aYMult are also on integer boundaries.
   // aXMult/aYMult must be N or 1/N for integer N.
   nsRect& ExtendForScaling(float aXMult, float aYMult);
 
   // Converts this rect from aFromAPP, an appunits per pixel ratio, to aToAPP.
   // In the RoundOut version we make the rect the smallest rect containing the
   // unrounded result. In the RoundIn version we make the rect the largest rect
   // contained in the unrounded result.
   inline nsRect ConvertAppUnitsRoundOut(PRInt32 aFromAPP, PRInt32 aToAPP) const;
   inline nsRect ConvertAppUnitsRoundIn(PRInt32 aFromAPP, PRInt32 aToAPP) const;
 
-  // Helpers for accessing the vertices
-  nsPoint TopLeft() const { return nsPoint(x, y); }
-  nsPoint TopRight() const { return nsPoint(XMost(), y); }
-  nsPoint BottomLeft() const { return nsPoint(x, YMost()); }
-  nsPoint BottomRight() const { return nsPoint(XMost(), YMost()); }
-
-  nsSize Size() const { return nsSize(width, height); }
-
-  // Helper methods for computing the extents
-  nscoord XMost() const {return x + width;}
-  nscoord YMost() const {return y + height;}
-
   inline nsIntRect ToNearestPixels(nscoord aAppUnitsPerPixel) const;
   inline nsIntRect ToOutsidePixels(nscoord aAppUnitsPerPixel) const;
   inline nsIntRect ToInsidePixels(nscoord aAppUnitsPerPixel) const;
 };
 
-struct NS_GFX nsIntRect {
-  PRInt32 x, y;
-  PRInt32 width, height;
+struct NS_GFX nsIntRect :
+  public mozilla::BaseRect<PRInt32, nsIntRect, nsIntPoint, nsIntSize, nsIntMargin> {
+  typedef mozilla::BaseRect<PRInt32, nsIntRect, nsIntPoint, nsIntSize, nsIntMargin> Super;
 
   // Constructors
-  nsIntRect() : x(0), y(0), width(0), height(0) {}
-  nsIntRect(const nsIntRect& aRect) {*this = aRect;}
-  nsIntRect(const nsIntPoint& aOrigin, const nsIntSize &aSize) {
-    x = aOrigin.x; y = aOrigin.y;
-    width = aSize.width; height = aSize.height;
-  }
-  nsIntRect(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) {
-    x = aX; y = aY; width = aWidth; height = aHeight;
-  }
-
-  // Emptiness. An empty rect is one that has no area, i.e. its height or width
-  // is <= 0
-  PRBool IsEmpty() const {
-    return (PRBool) ((height <= 0) || (width <= 0));
-  }
-  void Empty() {width = height = 0;}
-
-  // Inflate the rect by the specified width/height or margin
-  void Inflate(PRInt32 aDx, PRInt32 aDy) {
-    x -= aDx;
-    y -= aDy;
-    width += aDx*2;
-    height += aDy*2;
-  }
-  void Inflate(const nsIntMargin &aMargin) {
-    x -= aMargin.left;
-    y -= aMargin.top;
-    width += aMargin.left + aMargin.right;
-    height += aMargin.top + aMargin.bottom;
+  nsIntRect() : Super()
+  {
   }
-
-  // Deflate the rect by the specified width/height or margin
-  void Deflate(PRInt32 aDx, PRInt32 aDy) {
-    x += aDx;
-    y += aDy;
-    width -= aDx*2;
-    height -= aDy*2;
-  }
-  void Deflate(const nsIntMargin &aMargin) {
-    x += aMargin.left;
-    y += aMargin.top;
-    width -= (aMargin.left + aMargin.right);
-    height -= (aMargin.top + aMargin.bottom);
-  }
-
-  // Overloaded operators. Note that '=' isn't defined so we'll get the
-  // compiler generated default assignment operator.
-  PRBool operator==(const nsIntRect& aRect) const {
-    return IsEqualEdges(aRect);
-  }
-
-  // Return true if the rectangles contain the same set of points, including
-  // points on the edges.
-  // Use when we care about the exact x/y/width/height values being
-  // equal (i.e. we care about differences in empty rectangles).
-  PRBool IsEqualEdges(const nsIntRect& aRect) const {
-    return x == aRect.x && y == aRect.y &&
-           width == aRect.width && height == aRect.height;
-  }
-  // Return true if the rectangles contain the same area of the plane.
-  // Use when we do not care about differences in empty rectangles.
-  PRBool IsEqualInterior(const nsIntRect& aRect) const {
-    return IsEqualEdges(aRect) || (IsEmpty() && aRect.IsEmpty());
+  nsIntRect(const nsIntRect& aRect) : Super(aRect)
+  {
   }
-
-  nsIntRect  operator+(const nsIntPoint& aPoint) const {
-    return nsIntRect(x + aPoint.x, y + aPoint.y, width, height);
-  }
-  nsIntRect  operator-(const nsIntPoint& aPoint) const {
-    return nsIntRect(x - aPoint.x, y - aPoint.y, width, height);
-  }
-  nsIntRect& operator+=(const nsIntPoint& aPoint) {x += aPoint.x; y += aPoint.y; return *this;}
-  nsIntRect& operator-=(const nsIntPoint& aPoint) {x -= aPoint.x; y -= aPoint.y; return *this;}
-
-  void SetRect(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) {
-    x = aX; y = aY; width = aWidth; height = aHeight;
-  }
-
-  void MoveTo(PRInt32 aX, PRInt32 aY) {x = aX; y = aY;}
-  void MoveTo(const nsIntPoint& aPoint) {x = aPoint.x; y = aPoint.y;}
-  void MoveBy(PRInt32 aDx, PRInt32 aDy) {x += aDx; y += aDy;}
-  void MoveBy(const nsIntPoint& aPoint) {x += aPoint.x; y += aPoint.y;}
-  void SizeTo(PRInt32 aWidth, PRInt32 aHeight) {width = aWidth; height = aHeight;}
-  void SizeTo(const nsIntSize& aSize) {SizeTo(aSize.width, aSize.height);}
-  void SizeBy(PRInt32 aDeltaWidth, PRInt32 aDeltaHeight) {width += aDeltaWidth;
-                                                          height += aDeltaHeight;}
-
-  PRBool Contains(const nsIntRect& aRect) const
+  nsIntRect(const nsIntPoint& aOrigin, const nsIntSize &aSize) : Super(aOrigin, aSize)
   {
-    return aRect.IsEmpty() ||
-        (PRBool) ((aRect.x >= x) && (aRect.y >= y) &&
-                  (aRect.XMost() <= XMost()) && (aRect.YMost() <= YMost()));
-  }
-  PRBool Contains(PRInt32 aX, PRInt32 aY) const
-  {
-    return (PRBool) ((aX >= x) && (aY >= y) &&
-                     (aX < XMost()) && (aY < YMost()));
   }
-  PRBool Contains(const nsIntPoint& aPoint) const { return Contains(aPoint.x, aPoint.y); }
-
-  // Intersection. Returns TRUE if the receiver overlaps aRect and
-  // FALSE otherwise
-  PRBool Intersects(const nsIntRect& aRect) const {
-    return (PRBool) ((x < aRect.XMost()) && (y < aRect.YMost()) &&
-                     (aRect.x < XMost()) && (aRect.y < YMost()));
+  nsIntRect(PRInt32 aX, PRInt32 aY, PRInt32 aWidth, PRInt32 aHeight) :
+      Super(aX, aY, aWidth, aHeight)
+  {
   }
 
-  // Computes the area in which aRect1 and aRect2 overlap, and fills 'this' with
-  // the result. Returns FALSE if the rectangles don't intersect, and sets 'this'
-  // rect to be an empty rect.
-  //
-  // 'this' can be the same object as either aRect1 or aRect2
-  PRBool IntersectRect(const nsIntRect& aRect1, const nsIntRect& aRect2);
-
-  // Computes the smallest rectangle that contains both aRect1 and aRect2 and
-  // fills 'this' with the result. Returns FALSE and sets 'this' rect to be an
-  // empty rect if both aRect1 and aRect2 are empty
-  //
-  // 'this' can be the same object as either aRect1 or aRect2
-  PRBool UnionRect(const nsIntRect& aRect1, const nsIntRect& aRect2);
-
-  // Helpers for accessing the vertices
-  nsIntPoint TopLeft() const { return nsIntPoint(x, y); }
-  nsIntPoint TopRight() const { return nsIntPoint(XMost(), y); }
-  nsIntPoint BottomLeft() const { return nsIntPoint(x, YMost()); }
-  nsIntPoint BottomRight() const { return nsIntPoint(XMost(), YMost()); }
-
-  nsIntSize Size() const { return nsIntSize(width, height); }
-
-  // Helper methods for computing the extents
-  PRInt32 XMost() const {return x + width;}
-  PRInt32 YMost() const {return y + height;}
-
   inline nsRect ToAppUnits(nscoord aAppUnitsPerPixel) const;
 
-  nsIntRect& ScaleRoundOut(float aXScale, float aYScale);
-
   // Returns a special nsIntRect that's used in some places to signify
   // "all available space".
   static const nsIntRect& GetMaxSizedIntRect() { return kMaxSizedIntRect; }
 
+  // This is here only to keep IPDL-generated code happy. DO NOT USE.
+  bool operator==(const nsIntRect& aRect) const
+  {
+    return IsEqualEdges(aRect);
+  }
+
 protected:
   static const nsIntRect kMaxSizedIntRect;
 };
 
 /*
  * App Unit/Pixel conversions
  */
 
--- a/gfx/thebes/gfxRect.cpp
+++ b/gfx/thebes/gfxRect.cpp
@@ -34,64 +34,16 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "gfxRect.h"
 
 #include "nsMathUtils.h"
 
-gfxRect
-gfxRect::Intersect(const gfxRect& aRect) const
-{
-  gfxRect result(0,0,0,0);
-
-  gfxFloat x = PR_MAX(aRect.X(), X());
-  gfxFloat xmost = PR_MIN(aRect.XMost(), XMost());
-  if (x >= xmost)
-    return result;
-
-  gfxFloat y = PR_MAX(aRect.Y(), Y());
-  gfxFloat ymost = PR_MIN(aRect.YMost(), YMost());
-  if (y >= ymost)
-    return result;
-
-  result = gfxRect(x, y, xmost - x, ymost - y);
-  return result;
-}
-
-gfxRect
-gfxRect::Union(const gfxRect& aRect) const
-{
-  if (IsEmpty())
-    return aRect;
-  if (aRect.IsEmpty())
-    return *this;
-
-  gfxFloat x = PR_MIN(aRect.X(), X());
-  gfxFloat xmost = PR_MAX(aRect.XMost(), XMost());
-  gfxFloat y = PR_MIN(aRect.Y(), Y());
-  gfxFloat ymost = PR_MAX(aRect.YMost(), YMost());
-  return gfxRect(x, y, xmost - x, ymost - y);
-}
-
-PRBool
-gfxRect::Contains(const gfxRect& aRect) const
-{
-  return aRect.X() >= X() && aRect.XMost() <= XMost() &&
-         aRect.Y() >= Y() && aRect.YMost() <= YMost();
-}
-
-PRBool
-gfxRect::Contains(const gfxPoint& aPoint) const
-{
-  return aPoint.x >= X() && aPoint.x <= XMost() &&
-         aPoint.y >= Y() && aPoint.y <= YMost();
-}
-
 static PRBool
 WithinEpsilonOfInteger(gfxFloat aX, gfxFloat aEpsilon)
 {
     return fabs(NS_round(aX) - aX) <= fabs(aEpsilon);
 }
 
 PRBool
 gfxRect::WithinEpsilonOfIntegerPixels(gfxFloat aEpsilon) const
--- a/gfx/thebes/gfxRect.h
+++ b/gfx/thebes/gfxRect.h
@@ -36,17 +36,29 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef GFX_RECT_H
 #define GFX_RECT_H
 
 #include "gfxTypes.h"
 #include "gfxPoint.h"
 #include "gfxCore.h"
-#include "nsDebug.h" 
+#include "nsDebug.h"
+#include "mozilla/BaseMargin.h"
+#include "mozilla/BaseRect.h"
+
+struct gfxMargin : public mozilla::BaseMargin<gfxFloat, gfxMargin> {
+  typedef mozilla::BaseMargin<gfxFloat, gfxMargin> Super;
+
+  // Constructors
+  gfxMargin() : Super() {}
+  gfxMargin(const gfxMargin& aMargin) : Super(aMargin) {}
+  gfxMargin(gfxFloat aLeft,  gfxFloat aTop, gfxFloat aRight, gfxFloat aBottom)
+    : Super(aLeft, aTop, aRight, aBottom) {}
+};
 
 namespace mozilla {
     namespace css {
         enum Corner {
             // this order is important!
             eCornerTopLeft = 0,
             eCornerTopRight = 1,
             eCornerBottomRight = 2,
@@ -68,136 +80,56 @@ namespace mozilla {
 
 static inline mozilla::css::Corner operator++(mozilla::css::Corner& corner, int) {
     NS_PRECONDITION(corner >= NS_CORNER_TOP_LEFT &&
                     corner < NS_NUM_CORNERS, "Out of range corner");
     corner = mozilla::css::Corner(corner + 1);
     return corner;
 }
 
-struct THEBES_API gfxRect
-{
-    gfxFloat x, y;
-    gfxFloat width, height;
-
-    gfxRect() {}
-    gfxRect(const gfxPoint& _pos, const gfxSize& _size) :
-        x(_pos.x), y(_pos.y), width(_size.width), height(_size.height) {}
-    gfxRect(gfxFloat _x, gfxFloat _y, gfxFloat _width, gfxFloat _height) :
-        x(_x), y(_y), width(_width), height(_height) {}
-
-    int operator==(const gfxRect& s) const {
-        return x == s.x && y == s.y && width == s.width && height == s.height;
-    }
-    PRBool IsEqualEdges(const gfxRect& aRect) const {
-      return x == aRect.x && y == aRect.y &&
-             width == aRect.width && height == aRect.height;
-    }
-    // Return true if the rectangles contain the same area of the plane.
-    // Use when we do not care about differences in empty rectangles.
-    PRBool IsEqualInterior(const gfxRect& aRect) const {
-      return IsEqualEdges(aRect) || (IsEmpty() && aRect.IsEmpty());
-    }
-
-    void MoveTo(const gfxPoint& aPt) { x = aPt.x; y = aPt.y; }
-    const gfxRect& MoveBy(const gfxPoint& aPt) {
-        x += aPt.x;
-        y += aPt.y;
-        return *this;
-    }
-    void SizeTo(const gfxSize& aSize) { width = aSize.width; height = aSize.height; }
+struct THEBES_API gfxRect :
+    public mozilla::BaseRect<gfxFloat, gfxRect, gfxPoint, gfxSize, gfxMargin> {
+    typedef mozilla::BaseRect<gfxFloat, gfxRect, gfxPoint, gfxSize, gfxMargin> Super;
 
-    gfxRect operator+(const gfxPoint& aPt) const {
-        return gfxRect(x + aPt.x, y + aPt.y, width, height);
-    }
-    gfxRect operator-(const gfxPoint& aPt) const {
-        return gfxRect(x - aPt.x, y - aPt.y, width, height);
-    }
-    gfxRect operator+(const gfxSize& aSize) const {
-        return gfxRect(x + aSize.width, y + aSize.height, width, height);
-    }
-    gfxRect operator-(const gfxSize& aSize) const {
-        return gfxRect(x - aSize.width, y - aSize.height, width, height);
-    }
-    gfxRect operator*(const gfxFloat aScale) const {
-        return gfxRect(x * aScale, y * aScale, width * aScale, height * aScale);
-    }
-
-    const gfxRect& operator+=(const gfxPoint& aPt) {
-        x += aPt.x;
-        y += aPt.y;
-        return *this;
-    }
-    const gfxRect& operator-=(const gfxPoint& aPt) {
-        x -= aPt.x;
-        y -= aPt.y;
-        return *this;
-    }
-
-    gfxFloat Width() const { return width; }
-    gfxFloat Height() const { return height; }
-    gfxFloat X() const { return x; }
-    gfxFloat Y() const { return y; }
-    gfxFloat XMost() const { return x + width; }
-    gfxFloat YMost() const { return y + height; }
-
-    PRBool IsEmpty() const { return width <= 0 || height <= 0; }
-    gfxRect Intersect(const gfxRect& aRect) const;
-    gfxRect Union(const gfxRect& aRect) const;
-    PRBool Contains(const gfxRect& aRect) const;
-    PRBool Contains(const gfxPoint& aPoint) const;
+    gfxRect() : Super() {}
+    gfxRect(const gfxPoint& aPos, const gfxSize& aSize) :
+        Super(aPos, aSize) {}
+    gfxRect(gfxFloat aX, gfxFloat aY, gfxFloat aWidth, gfxFloat aHeight) :
+        Super(aX, aY, aWidth, aHeight) {}
 
     /**
      * Return true if all components of this rect are within
      * aEpsilon of integer coordinates, defined as
      *   |round(coord) - coord| <= |aEpsilon|
      * for x,y,width,height.
      */
     PRBool WithinEpsilonOfIntegerPixels(gfxFloat aEpsilon) const;
 
-    gfxSize Size() const { return gfxSize(width, height); }
-
     void Inset(gfxFloat k) {
-        x += k;
-        y += k;
-        width = PR_MAX(0.0, width - k * 2.0);
-        height = PR_MAX(0.0, height - k * 2.0);
+        Deflate(k, k);
     }
 
     void Inset(gfxFloat top, gfxFloat right, gfxFloat bottom, gfxFloat left) {
-        x += left;
-        y += top;
-        width = PR_MAX(0.0, width - (right+left));
-        height = PR_MAX(0.0, height - (bottom+top));
+        Deflate(gfxMargin(left, top, right, bottom));
     }
 
     void Inset(const gfxFloat *sides) {
         Inset(sides[0], sides[1], sides[2], sides[3]);
     }
 
     void Inset(const gfxIntSize& aSize) {
-        Inset(aSize.height, aSize.width, aSize.height, aSize.width);
+        Deflate(aSize.width, aSize.height);
     }
 
     void Outset(gfxFloat k) {
-        x -= k;
-        y -= k;
-        width = PR_MAX(0.0, width + k * 2.0);
-        height = PR_MAX(0.0, height + k * 2.0);
+        Inflate(k, k);
     }
 
     void Outset(gfxFloat top, gfxFloat right, gfxFloat bottom, gfxFloat left) {
-        x -= left;
-        y -= top;
-        width = PR_MAX(0.0, width + (right+left));
-        height = PR_MAX(0.0, height + (bottom+top));
-    }
-
-    void Outset(const gfxFloat *sides) {
-        Outset(sides[0], sides[1], sides[2], sides[3]);
+        Inflate(gfxMargin(left, top, right, bottom));
     }
 
     void Outset(const gfxIntSize& aSize) {
         Outset(aSize.height, aSize.width, aSize.height, aSize.width);
     }
 
     // Round the rectangle edges to integer coordinates, such that the rounded
     // rectangle has the same set of pixel centers as the original rectangle.
@@ -215,23 +147,16 @@ struct THEBES_API gfxRect
     // Snap the rectangle edges to integer coordinates, such that the
     // original rectangle contains the resulting rectangle.
     void RoundIn();
     
     // Snap the rectangle edges to integer coordinates, such that the
     // resulting rectangle contains the original rectangle.
     void RoundOut();
 
-    // grabbing specific points
-    gfxPoint TopLeft() const { return gfxPoint(x, y); }
-    gfxPoint TopRight() const { return gfxPoint(x, y) + gfxPoint(width, 0.0); }
-    gfxPoint BottomLeft() const { return gfxPoint(x, y) + gfxPoint(0.0, height); }
-    gfxPoint BottomRight() const { return gfxPoint(x, y) + gfxPoint(width, height); }
-    gfxPoint Center() const { return gfxPoint(x, y) + gfxPoint(width, height)/2.0; }
-
     gfxPoint AtCorner(mozilla::css::Corner corner) const {
         switch (corner) {
             case NS_CORNER_TOP_LEFT: return TopLeft();
             case NS_CORNER_TOP_RIGHT: return TopRight();
             case NS_CORNER_BOTTOM_RIGHT: return BottomRight();
             case NS_CORNER_BOTTOM_LEFT: return BottomLeft();
             default:
                 NS_ERROR("Invalid corner!");
--- a/layout/base/nsLayoutUtils.cpp
+++ b/layout/base/nsLayoutUtils.cpp
@@ -1004,20 +1004,18 @@ static void ConstrainToCoordValues(gfxFl
   else if (aVal >= nscoord_MAX)
     aVal = nscoord_MAX;
 }
 
 nsRect
 nsLayoutUtils::RoundGfxRectToAppRect(const gfxRect &aRect, float aFactor)
 {
   /* Get a new gfxRect whose units are app units by scaling by the specified factor. */
-  gfxRect scaledRect = aRect * aFactor;
-
-  /* Round outward. */
-  scaledRect.RoundOut();
+  gfxRect scaledRect = aRect;
+  scaledRect.ScaleRoundOut(aFactor);
 
   /* We now need to constrain our results to the max and min values for coords. */
   ConstrainToCoordValues(scaledRect.x);
   ConstrainToCoordValues(scaledRect.y);
   ConstrainToCoordValues(scaledRect.width);
   ConstrainToCoordValues(scaledRect.height);
 
   /* Now typecast everything back.  This is guaranteed to be safe. */
--- a/layout/generic/nsObjectFrame.cpp
+++ b/layout/generic/nsObjectFrame.cpp
@@ -1741,17 +1741,17 @@ nsObjectFrame::PrintPlugin(nsRenderingCo
     nativeDraw.EndNativeDrawing();
     return;
   }
 
   window.clipRect.right = window.width;
   window.clipRect.bottom = window.height;
   window.type = NPWindowTypeDrawable;
 
-  Rect gwBounds;
+  ::Rect gwBounds;
   ::SetRect(&gwBounds, 0, 0, window.width, window.height);
 
   nsTArray<char> buffer(window.width * window.height * 4);
   CGColorSpaceRef cspace = ::CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
   if (!cspace) {
     nativeDraw.EndNativeDrawing();
     return;
   }
--- a/layout/xul/base/src/nsMenuPopupFrame.cpp
+++ b/layout/xul/base/src/nsMenuPopupFrame.cpp
@@ -1351,17 +1351,17 @@ nsMenuPopupFrame::GetConstraintRect(cons
                         &screenRectPixels.width, &screenRectPixels.height);
       else
         screen->GetAvailRect(&screenRectPixels.x, &screenRectPixels.y,
                              &screenRectPixels.width, &screenRectPixels.height);
     }
   }
 
   // keep a 3 pixel margin to the right and bottom of the screen for the WinXP dropshadow
-  screenRectPixels.SizeBy(-3, -3);
+  screenRectPixels.SizeTo(screenRectPixels.width - 3, screenRectPixels.height - 3);
 
   nsRect screenRect = screenRectPixels.ToAppUnits(presContext->AppUnitsPerDevPixel());
   if (mInContentShell) {
     // for content shells, clip to the client area rather than the screen area
     screenRect.IntersectRect(screenRect, aRootScreenRect);
   }
 
   return screenRect;
--- a/layout/xul/base/src/nsResizerFrame.cpp
+++ b/layout/xul/base/src/nsResizerFrame.cpp
@@ -107,19 +107,19 @@ nsResizerFrame::HandleEvent(nsPresContex
             break;
 
           // cache the content rectangle for the frame to resize
           // GetScreenRectInAppUnits returns the border box rectangle, so
           // adjust to get the desired content rectangle.
           nsRect rect = frameToResize->GetScreenRectInAppUnits();
           switch (frameToResize->GetStylePosition()->mBoxSizing) {
             case NS_STYLE_BOX_SIZING_CONTENT:
-              rect -= frameToResize->GetUsedPadding();
+              rect.Deflate(frameToResize->GetUsedPadding());
             case NS_STYLE_BOX_SIZING_PADDING:
-              rect -= frameToResize->GetUsedBorder();
+              rect.Deflate(frameToResize->GetUsedBorder());
             default:
               break;
           }
 
           mMouseDownRect = rect.ToNearestPixels(aPresContext->AppUnitsPerDevPixel());
         }
         else {
           // ask the widget implementation to begin a resize drag if it can