diff --git a/gfx/src/BaseRect.h b/gfx/src/BaseRect.h new file mode 100644 index 000000000000..425168787320 --- /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 + * + * 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 +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(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(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(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(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(this); + } + Sub& operator-=(const Point& aPoint) + { + MoveBy(-aPoint); + return *static_cast(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(NS_ceil(double(XMost()) * aXScale)); + T bottom = static_cast(NS_ceil(double(YMost()) * aYScale)); + x = static_cast(NS_floor(double(x) * aXScale)); + y = static_cast(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_ */ diff --git a/gfx/src/Makefile.in b/gfx/src/Makefile.in index 40d36195ca18..b7b98e72a074 100644 --- a/gfx/src/Makefile.in +++ b/gfx/src/Makefile.in @@ -64,6 +64,7 @@ EXPORTS_NAMESPACES = mozilla EXPORTS_mozilla = \ BaseMargin.h \ BasePoint.h \ + BaseRect.h \ BaseSize.h \ $(NULL) diff --git a/gfx/src/nsRect.cpp b/gfx/src/nsRect.cpp index 9f298990b6f8..b200ce945c63 100644 --- a/gfx/src/nsRect.cpp +++ b/gfx/src/nsRect.cpp @@ -44,167 +44,9 @@ // 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) { @@ -259,85 +101,3 @@ FILE* operator<<(FILE* out, const nsRect& rect) } #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; -} diff --git a/gfx/src/nsRect.h b/gfx/src/nsRect.h index 21866034d83b..c55576331233 100644 --- a/gfx/src/nsRect.h +++ b/gfx/src/nsRect.h @@ -46,30 +46,33 @@ #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 { + typedef mozilla::BaseRect 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) { + nsRect(const nsRect& aRect) : Super(aRect) + { MOZ_COUNT_CTOR(nsRect); - *this = aRect; } - nsRect(const nsPoint& aOrigin, const nsSize &aSize) { + nsRect(const nsPoint& aOrigin, const nsSize &aSize) : Super(aOrigin, aSize) + { MOZ_COUNT_CTOR(nsRect); - x = aOrigin.x; y = aOrigin.y; - width = aSize.width; height = aSize.height; } - 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 @@ -77,114 +80,8 @@ struct NS_GFX 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); @@ -196,169 +93,42 @@ struct NS_GFX nsRect { 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 { + typedef mozilla::BaseRect 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; - } - - // 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 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() : Super() { - return aRect.IsEmpty() || - (PRBool) ((aRect.x >= x) && (aRect.y >= y) && - (aRect.XMost() <= XMost()) && (aRect.YMost() <= YMost())); } - PRBool Contains(PRInt32 aX, PRInt32 aY) const + nsIntRect(const nsIntRect& aRect) : Super(aRect) { - 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(const nsIntPoint& aOrigin, const nsIntSize &aSize) : Super(aOrigin, aSize) + { + } + 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; }; diff --git a/gfx/thebes/gfxRect.cpp b/gfx/thebes/gfxRect.cpp index 42bee2032c10..210c1e67dda1 100644 --- a/gfx/thebes/gfxRect.cpp +++ b/gfx/thebes/gfxRect.cpp @@ -39,54 +39,6 @@ #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) { diff --git a/gfx/thebes/gfxRect.h b/gfx/thebes/gfxRect.h index 64647e45e1f2..a7b5e9f39aa5 100644 --- a/gfx/thebes/gfxRect.h +++ b/gfx/thebes/gfxRect.h @@ -41,7 +41,19 @@ #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 { + typedef mozilla::BaseMargin 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 { @@ -73,77 +85,15 @@ static inline mozilla::css::Corner operator++(mozilla::css::Corner& corner, int) return corner; } -struct THEBES_API gfxRect -{ - gfxFloat x, y; - gfxFloat width, height; +struct THEBES_API gfxRect : + public mozilla::BaseRect { + typedef mozilla::BaseRect Super; - 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; } - - 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 @@ -153,20 +103,12 @@ struct THEBES_API gfxRect */ 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) { @@ -174,25 +116,15 @@ struct THEBES_API gfxRect } 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) { @@ -220,13 +152,6 @@ struct THEBES_API gfxRect // 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(); diff --git a/layout/base/nsLayoutUtils.cpp b/layout/base/nsLayoutUtils.cpp index 958be61583a2..8f939f85a6c0 100644 --- a/layout/base/nsLayoutUtils.cpp +++ b/layout/base/nsLayoutUtils.cpp @@ -1009,10 +1009,8 @@ 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); diff --git a/layout/generic/nsObjectFrame.cpp b/layout/generic/nsObjectFrame.cpp index 27e58cd4d6e3..8a0f0811683a 100644 --- a/layout/generic/nsObjectFrame.cpp +++ b/layout/generic/nsObjectFrame.cpp @@ -1746,7 +1746,7 @@ nsObjectFrame::PrintPlugin(nsRenderingContext& aRenderingContext, window.clipRect.bottom = window.height; window.type = NPWindowTypeDrawable; - Rect gwBounds; + ::Rect gwBounds; ::SetRect(&gwBounds, 0, 0, window.width, window.height); nsTArray buffer(window.width * window.height * 4); diff --git a/layout/xul/base/src/nsMenuPopupFrame.cpp b/layout/xul/base/src/nsMenuPopupFrame.cpp index 419ab7ce5aee..8c9712b3b75a 100644 --- a/layout/xul/base/src/nsMenuPopupFrame.cpp +++ b/layout/xul/base/src/nsMenuPopupFrame.cpp @@ -1356,7 +1356,7 @@ nsMenuPopupFrame::GetConstraintRect(const nsRect& aAnchorRect, } // 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) { diff --git a/layout/xul/base/src/nsResizerFrame.cpp b/layout/xul/base/src/nsResizerFrame.cpp index f77978ac7a5e..5ac7bcb5157e 100644 --- a/layout/xul/base/src/nsResizerFrame.cpp +++ b/layout/xul/base/src/nsResizerFrame.cpp @@ -112,9 +112,9 @@ nsResizerFrame::HandleEvent(nsPresContext* aPresContext, 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; }