diff options
Diffstat (limited to 'gfx/2d/BaseRect.h')
-rw-r--r-- | gfx/2d/BaseRect.h | 158 |
1 files changed, 128 insertions, 30 deletions
diff --git a/gfx/2d/BaseRect.h b/gfx/2d/BaseRect.h index f0f5efec2..0b6810cfd 100644 --- a/gfx/2d/BaseRect.h +++ b/gfx/2d/BaseRect.h @@ -6,9 +6,14 @@ #ifndef MOZILLA_GFX_BASERECT_H_ #define MOZILLA_GFX_BASERECT_H_ -#include <cmath> -#include <mozilla/Assertions.h> #include <algorithm> +#include <cmath> +#include <ostream> + +#include "mozilla/Assertions.h" +#include "mozilla/FloatingPoint.h" +#include "mozilla/TypeTraits.h" +#include "Types.h" namespace mozilla { namespace gfx { @@ -36,7 +41,7 @@ namespace gfx { * 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> +template <class T, class Sub, class Point, class SizeT, class MarginT> struct BaseRect { T x, y, width, height; @@ -59,10 +64,11 @@ struct BaseRect { // "Finite" means not inf and not NaN bool IsFinite() const { - return (std::isfinite(x) && - std::isfinite(y) && - std::isfinite(width) && - std::isfinite(height)); + typedef typename mozilla::Conditional<mozilla::IsSame<T, float>::value, float, double>::Type FloatType; + return (mozilla::IsFinite(FloatType(x)) && + mozilla::IsFinite(FloatType(y)) && + mozilla::IsFinite(FloatType(width)) && + mozilla::IsFinite(FloatType(height))); } // Returns true if this rectangle contains the interior of aRect. Always @@ -74,13 +80,17 @@ struct BaseRect { (x <= aRect.x && aRect.XMost() <= XMost() && y <= aRect.y && aRect.YMost() <= YMost()); } - // Returns true if this rectangle contains the rectangle (aX,aY,1,1). + // Returns true if this rectangle contains the point. Points are considered + // in the rectangle if they are on the left or top edge, but outside if they + // are on the right or bottom edge. bool Contains(T aX, T aY) const { - return x <= aX && aX + 1 <= XMost() && - y <= aY && aY + 1 <= YMost(); + return x <= aX && aX < XMost() && + y <= aY && aY < YMost(); } - // Returns true if this rectangle contains the rectangle (aPoint.x,aPoint.y,1,1). + // Returns true if this rectangle contains the point. Points are considered + // in the rectangle if they are on the left or top edge, but outside if they + // are on the right or bottom edge. bool Contains(const Point& aPoint) const { return Contains(aPoint.x, aPoint.y); } // Intersection. Returns TRUE if the receiver's area has non-empty @@ -88,7 +98,8 @@ struct BaseRect { // Always returns false if aRect is empty or 'this' is empty. bool Intersects(const Sub& aRect) const { - return x < aRect.XMost() && aRect.x < XMost() && + return !IsEmpty() && !aRect.IsEmpty() && + x < aRect.XMost() && aRect.x < XMost() && y < aRect.YMost() && aRect.y < YMost(); } // Returns the rectangle containing the intersection of the points @@ -166,6 +177,23 @@ struct BaseRect { *static_cast<Sub*>(this) = aRect1.UnionEdges(aRect2); } + // Expands the rect to include the point + void ExpandToEnclose(const Point& aPoint) + { + if (aPoint.x < x) { + width = XMost() - aPoint.x; + x = aPoint.x; + } else if (aPoint.x > XMost()) { + width = aPoint.x - x; + } + if (aPoint.y < y) { + height = YMost() - aPoint.y; + y = aPoint.y; + } else if (aPoint.y > YMost()) { + height = aPoint.y - y; + } + } + void SetRect(T aX, T aY, T aWidth, T aHeight) { x = aX; y = aY; width = aWidth; height = aHeight; @@ -189,7 +217,7 @@ struct BaseRect { width += 2 * aDx; height += 2 * aDy; } - void Inflate(const Margin& aMargin) + void Inflate(const MarginT& aMargin) { x -= aMargin.left; y -= aMargin.top; @@ -198,6 +226,20 @@ struct BaseRect { } void Inflate(const SizeT& aSize) { Inflate(aSize.width, aSize.height); } + void InflateToMultiple(const SizeT& aMultiple) + { + T xMost = XMost(); + T yMost = YMost(); + + x = static_cast<T>(floor(x / aMultiple.width)) * aMultiple.width; + y = static_cast<T>(floor(y / aMultiple.height)) * aMultiple.height; + xMost = static_cast<T>(ceil(x / aMultiple.width)) * aMultiple.width; + yMost = static_cast<T>(ceil(y / aMultiple.height)) * aMultiple.height; + + width = xMost - x; + height = yMost - y; + } + void Deflate(T aD) { Deflate(aD, aD); } void Deflate(T aDx, T aDy) { @@ -206,7 +248,7 @@ struct BaseRect { width = std::max(T(0), width - 2 * aDx); height = std::max(T(0), height - 2 * aDy); } - void Deflate(const Margin& aMargin) + void Deflate(const MarginT& aMargin) { x += aMargin.left; y += aMargin.top; @@ -231,13 +273,25 @@ struct BaseRect { return IsEqualEdges(aRect) || (IsEmpty() && aRect.IsEmpty()); } - Sub operator+(const Point& aPoint) const + friend Sub operator+(Sub aSub, const Point& aPoint) + { + aSub += aPoint; + return aSub; + } + friend Sub operator-(Sub aSub, const Point& aPoint) { - return Sub(x + aPoint.x, y + aPoint.y, width, height); + aSub -= aPoint; + return aSub; } - Sub operator-(const Point& aPoint) const + friend Sub operator+(Sub aSub, const SizeT& aSize) { - return Sub(x - aPoint.x, y - aPoint.y, width, height); + aSub += aSize; + return aSub; + } + friend Sub operator-(Sub aSub, const SizeT& aSize) + { + aSub -= aSize; + return aSub; } Sub& operator+=(const Point& aPoint) { @@ -249,14 +303,25 @@ struct BaseRect { MoveBy(-aPoint); return *static_cast<Sub*>(this); } - + Sub& operator+=(const SizeT& aSize) + { + width += aSize.width; + height += aSize.height; + return *static_cast<Sub*>(this); + } + Sub& operator-=(const SizeT& aSize) + { + width -= aSize.width; + height -= aSize.height; + return *static_cast<Sub*>(this); + } // Find difference as a Margin - Margin operator-(const Sub& aRect) const + MarginT operator-(const Sub& aRect) const { - return Margin(aRect.y - y, - XMost() - aRect.XMost(), - YMost() - aRect.YMost(), - aRect.x - x); + return MarginT(aRect.y - y, + XMost() - aRect.XMost(), + YMost() - aRect.YMost(), + aRect.x - x); } // Helpers for accessing the vertices @@ -264,6 +329,33 @@ struct BaseRect { Point TopRight() const { return Point(XMost(), y); } Point BottomLeft() const { return Point(x, YMost()); } Point BottomRight() const { return Point(XMost(), YMost()); } + Point AtCorner(int aCorner) const { + switch (aCorner) { + case RectCorner::TopLeft: return TopLeft(); + case RectCorner::TopRight: return TopRight(); + case RectCorner::BottomRight: return BottomRight(); + case RectCorner::BottomLeft: return BottomLeft(); + } + MOZ_CRASH("Incomplete switch"); + } + Point CCWCorner(mozilla::Side side) const { + switch (side) { + case NS_SIDE_TOP: return TopLeft(); + case NS_SIDE_RIGHT: return TopRight(); + case NS_SIDE_BOTTOM: return BottomRight(); + case NS_SIDE_LEFT: return BottomLeft(); + } + MOZ_CRASH("Incomplete switch"); + } + Point CWCorner(mozilla::Side side) const { + switch (side) { + case NS_SIDE_TOP: return TopRight(); + case NS_SIDE_RIGHT: return BottomRight(); + case NS_SIDE_BOTTOM: return BottomLeft(); + case NS_SIDE_LEFT: return TopLeft(); + } + MOZ_CRASH("Incomplete switch"); + } Point Center() const { return Point(x, y) + Point(width, height)/2; } SizeT Size() const { return SizeT(width, height); } @@ -440,21 +532,27 @@ struct BaseRect { } /** - * Clamp aRect to this rectangle. This returns aRect after it is forced - * inside the bounds of this rectangle. It will attempt to retain the size - * but will shrink the dimensions that don't fit. + * Clamp this rectangle to be inside aRect. The function returns a copy of + * this rect after it is forced inside the bounds of aRect. It will attempt to + * retain the size but will shrink the dimensions that don't fit. */ - Sub ClampRect(const Sub& aRect) const + Sub ForceInside(const Sub& aRect) const { Sub rect(std::max(aRect.x, x), std::max(aRect.y, y), std::min(aRect.width, width), std::min(aRect.height, height)); - rect.x = std::min(rect.XMost(), XMost()) - rect.width; - rect.y = std::min(rect.YMost(), YMost()) - rect.height; + rect.x = std::min(rect.XMost(), aRect.XMost()) - rect.width; + rect.y = std::min(rect.YMost(), aRect.YMost()) - rect.height; return rect; } + friend std::ostream& operator<<(std::ostream& stream, + const BaseRect<T, Sub, Point, SizeT, MarginT>& aRect) { + return stream << '(' << aRect.x << ',' << aRect.y << ',' + << aRect.width << ',' << aRect.height << ')'; + } + private: // Do not use the default operator== or operator!= ! // Use IsEqualEdges or IsEqualInterior explicitly. |