michael@0: /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: michael@0: #ifndef NSRECT_H michael@0: #define NSRECT_H michael@0: michael@0: #include // for FILE michael@0: #include // for int32_t, int64_t michael@0: #include // for min/max michael@0: #include "nsDebug.h" // for NS_WARNING michael@0: #include "gfxCore.h" // for NS_GFX michael@0: #include "mozilla/Likely.h" // for MOZ_UNLIKELY michael@0: #include "mozilla/gfx/BaseRect.h" // for BaseRect michael@0: #include "nsCoord.h" // for nscoord, etc michael@0: #include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc michael@0: #include "nsPoint.h" // for nsIntPoint, nsPoint michael@0: #include "nsSize.h" // for nsIntSize, nsSize michael@0: #include "nscore.h" // for NS_BUILD_REFCNT_LOGGING michael@0: michael@0: struct nsIntRect; michael@0: struct nsMargin; michael@0: struct nsIntMargin; michael@0: michael@0: struct NS_GFX nsRect : michael@0: public mozilla::gfx::BaseRect { michael@0: typedef mozilla::gfx::BaseRect Super; michael@0: michael@0: static void VERIFY_COORD(nscoord aValue) { ::VERIFY_COORD(aValue); } michael@0: michael@0: // Constructors michael@0: nsRect() : Super() michael@0: { michael@0: MOZ_COUNT_CTOR(nsRect); michael@0: } michael@0: nsRect(const nsRect& aRect) : Super(aRect) michael@0: { michael@0: MOZ_COUNT_CTOR(nsRect); michael@0: } michael@0: nsRect(const nsPoint& aOrigin, const nsSize &aSize) : Super(aOrigin, aSize) michael@0: { michael@0: MOZ_COUNT_CTOR(nsRect); michael@0: } michael@0: nsRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) : michael@0: Super(aX, aY, aWidth, aHeight) michael@0: { michael@0: MOZ_COUNT_CTOR(nsRect); michael@0: } michael@0: michael@0: #ifdef NS_BUILD_REFCNT_LOGGING michael@0: ~nsRect() { michael@0: MOZ_COUNT_DTOR(nsRect); michael@0: } michael@0: #endif michael@0: michael@0: // We have saturating versions of all the Union methods. These avoid michael@0: // overflowing nscoord values in the 'width' and 'height' fields by michael@0: // clamping the width and height values to nscoord_MAX if necessary. michael@0: michael@0: nsRect SaturatingUnion(const nsRect& aRect) const michael@0: { michael@0: if (IsEmpty()) { michael@0: return aRect; michael@0: } else if (aRect.IsEmpty()) { michael@0: return *static_cast(this); michael@0: } else { michael@0: return SaturatingUnionEdges(aRect); michael@0: } michael@0: } michael@0: michael@0: nsRect SaturatingUnionEdges(const nsRect& aRect) const michael@0: { michael@0: #ifdef NS_COORD_IS_FLOAT michael@0: return UnionEdges(aRect); michael@0: #else michael@0: nsRect result; michael@0: result.x = std::min(aRect.x, x); michael@0: int64_t w = std::max(int64_t(aRect.x) + aRect.width, int64_t(x) + width) - result.x; michael@0: if (MOZ_UNLIKELY(w > nscoord_MAX)) { michael@0: NS_WARNING("Overflowed nscoord_MAX in conversion to nscoord width"); michael@0: // Clamp huge negative x to nscoord_MIN / 2 and try again. michael@0: result.x = std::max(result.x, nscoord_MIN / 2); michael@0: w = std::max(int64_t(aRect.x) + aRect.width, int64_t(x) + width) - result.x; michael@0: if (MOZ_UNLIKELY(w > nscoord_MAX)) { michael@0: w = nscoord_MAX; michael@0: } michael@0: } michael@0: result.width = nscoord(w); michael@0: michael@0: result.y = std::min(aRect.y, y); michael@0: int64_t h = std::max(int64_t(aRect.y) + aRect.height, int64_t(y) + height) - result.y; michael@0: if (MOZ_UNLIKELY(h > nscoord_MAX)) { michael@0: NS_WARNING("Overflowed nscoord_MAX in conversion to nscoord height"); michael@0: // Clamp huge negative y to nscoord_MIN / 2 and try again. michael@0: result.y = std::max(result.y, nscoord_MIN / 2); michael@0: h = std::max(int64_t(aRect.y) + aRect.height, int64_t(y) + height) - result.y; michael@0: if (MOZ_UNLIKELY(h > nscoord_MAX)) { michael@0: h = nscoord_MAX; michael@0: } michael@0: } michael@0: result.height = nscoord(h); michael@0: return result; michael@0: #endif michael@0: } michael@0: michael@0: #ifndef NS_COORD_IS_FLOAT michael@0: // Make all nsRect Union methods be saturating. michael@0: nsRect UnionEdges(const nsRect& aRect) const michael@0: { michael@0: return SaturatingUnionEdges(aRect); michael@0: } michael@0: void UnionRectEdges(const nsRect& aRect1, const nsRect& aRect2) michael@0: { michael@0: *this = aRect1.UnionEdges(aRect2); michael@0: } michael@0: nsRect Union(const nsRect& aRect) const michael@0: { michael@0: return SaturatingUnion(aRect); michael@0: } michael@0: void UnionRect(const nsRect& aRect1, const nsRect& aRect2) michael@0: { michael@0: *this = aRect1.Union(aRect2); michael@0: } michael@0: #endif michael@0: michael@0: void SaturatingUnionRect(const nsRect& aRect1, const nsRect& aRect2) michael@0: { michael@0: *this = aRect1.SaturatingUnion(aRect2); michael@0: } michael@0: void SaturatingUnionRectEdges(const nsRect& aRect1, const nsRect& aRect2) michael@0: { michael@0: *this = aRect1.SaturatingUnionEdges(aRect2); michael@0: } michael@0: michael@0: // Converts this rect from aFromAPP, an appunits per pixel ratio, to aToAPP. michael@0: // In the RoundOut version we make the rect the smallest rect containing the michael@0: // unrounded result. In the RoundIn version we make the rect the largest rect michael@0: // contained in the unrounded result. michael@0: // Note: this can turn an empty rectangle into a non-empty rectangle michael@0: inline nsRect ConvertAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const; michael@0: inline nsRect ConvertAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const; michael@0: michael@0: inline nsIntRect ScaleToNearestPixels(float aXScale, float aYScale, michael@0: nscoord aAppUnitsPerPixel) const; michael@0: inline nsIntRect ToNearestPixels(nscoord aAppUnitsPerPixel) const; michael@0: // Note: this can turn an empty rectangle into a non-empty rectangle michael@0: inline nsIntRect ScaleToOutsidePixels(float aXScale, float aYScale, michael@0: nscoord aAppUnitsPerPixel) const; michael@0: // Note: this can turn an empty rectangle into a non-empty rectangle michael@0: inline nsIntRect ToOutsidePixels(nscoord aAppUnitsPerPixel) const; michael@0: inline nsIntRect ScaleToInsidePixels(float aXScale, float aYScale, michael@0: nscoord aAppUnitsPerPixel) const; michael@0: inline nsIntRect ToInsidePixels(nscoord aAppUnitsPerPixel) const; michael@0: michael@0: // This is here only to keep IPDL-generated code happy. DO NOT USE. michael@0: bool operator==(const nsRect& aRect) const michael@0: { michael@0: return IsEqualEdges(aRect); michael@0: } michael@0: }; michael@0: michael@0: struct NS_GFX nsIntRect : michael@0: public mozilla::gfx::BaseRect { michael@0: typedef mozilla::gfx::BaseRect Super; michael@0: michael@0: // Constructors michael@0: nsIntRect() : Super() michael@0: { michael@0: } michael@0: nsIntRect(const nsIntRect& aRect) : Super(aRect) michael@0: { michael@0: } michael@0: nsIntRect(const nsIntPoint& aOrigin, const nsIntSize &aSize) : Super(aOrigin, aSize) michael@0: { michael@0: } michael@0: nsIntRect(int32_t aX, int32_t aY, int32_t aWidth, int32_t aHeight) : michael@0: Super(aX, aY, aWidth, aHeight) michael@0: { michael@0: } michael@0: michael@0: inline nsRect ToAppUnits(nscoord aAppUnitsPerPixel) const; michael@0: michael@0: // Returns a special nsIntRect that's used in some places to signify michael@0: // "all available space". michael@0: static const nsIntRect& GetMaxSizedIntRect() { michael@0: static const nsIntRect r(0, 0, INT32_MAX, INT32_MAX); michael@0: return r; michael@0: } michael@0: michael@0: // This is here only to keep IPDL-generated code happy. DO NOT USE. michael@0: bool operator==(const nsIntRect& aRect) const michael@0: { michael@0: return IsEqualEdges(aRect); michael@0: } michael@0: }; michael@0: michael@0: /* michael@0: * App Unit/Pixel conversions michael@0: */ michael@0: michael@0: inline nsRect michael@0: nsRect::ConvertAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const michael@0: { michael@0: if (aFromAPP == aToAPP) { michael@0: return *this; michael@0: } michael@0: michael@0: nsRect rect; michael@0: nscoord right = NSToCoordCeil(NSCoordScale(XMost(), aFromAPP, aToAPP)); michael@0: nscoord bottom = NSToCoordCeil(NSCoordScale(YMost(), aFromAPP, aToAPP)); michael@0: rect.x = NSToCoordFloor(NSCoordScale(x, aFromAPP, aToAPP)); michael@0: rect.y = NSToCoordFloor(NSCoordScale(y, aFromAPP, aToAPP)); michael@0: rect.width = (right - rect.x); michael@0: rect.height = (bottom - rect.y); michael@0: michael@0: return rect; michael@0: } michael@0: michael@0: inline nsRect michael@0: nsRect::ConvertAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const michael@0: { michael@0: if (aFromAPP == aToAPP) { michael@0: return *this; michael@0: } michael@0: michael@0: nsRect rect; michael@0: nscoord right = NSToCoordFloor(NSCoordScale(XMost(), aFromAPP, aToAPP)); michael@0: nscoord bottom = NSToCoordFloor(NSCoordScale(YMost(), aFromAPP, aToAPP)); michael@0: rect.x = NSToCoordCeil(NSCoordScale(x, aFromAPP, aToAPP)); michael@0: rect.y = NSToCoordCeil(NSCoordScale(y, aFromAPP, aToAPP)); michael@0: rect.width = (right - rect.x); michael@0: rect.height = (bottom - rect.y); michael@0: michael@0: return rect; michael@0: } michael@0: michael@0: // scale the rect but round to preserve centers michael@0: inline nsIntRect michael@0: nsRect::ScaleToNearestPixels(float aXScale, float aYScale, michael@0: nscoord aAppUnitsPerPixel) const michael@0: { michael@0: nsIntRect rect; michael@0: rect.x = NSToIntRoundUp(NSAppUnitsToDoublePixels(x, aAppUnitsPerPixel) * aXScale); michael@0: rect.y = NSToIntRoundUp(NSAppUnitsToDoublePixels(y, aAppUnitsPerPixel) * aYScale); michael@0: rect.width = NSToIntRoundUp(NSAppUnitsToDoublePixels(XMost(), michael@0: aAppUnitsPerPixel) * aXScale) - rect.x; michael@0: rect.height = NSToIntRoundUp(NSAppUnitsToDoublePixels(YMost(), michael@0: aAppUnitsPerPixel) * aYScale) - rect.y; michael@0: return rect; michael@0: } michael@0: michael@0: // scale the rect but round to smallest containing rect michael@0: inline nsIntRect michael@0: nsRect::ScaleToOutsidePixels(float aXScale, float aYScale, michael@0: nscoord aAppUnitsPerPixel) const michael@0: { michael@0: nsIntRect rect; michael@0: rect.x = NSToIntFloor(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) * aXScale); michael@0: rect.y = NSToIntFloor(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) * aYScale); michael@0: rect.width = NSToIntCeil(NSAppUnitsToFloatPixels(XMost(), michael@0: float(aAppUnitsPerPixel)) * aXScale) - rect.x; michael@0: rect.height = NSToIntCeil(NSAppUnitsToFloatPixels(YMost(), michael@0: float(aAppUnitsPerPixel)) * aYScale) - rect.y; michael@0: return rect; michael@0: } michael@0: michael@0: // scale the rect but round to largest contained rect michael@0: inline nsIntRect michael@0: nsRect::ScaleToInsidePixels(float aXScale, float aYScale, michael@0: nscoord aAppUnitsPerPixel) const michael@0: { michael@0: nsIntRect rect; michael@0: rect.x = NSToIntCeil(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) * aXScale); michael@0: rect.y = NSToIntCeil(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) * aYScale); michael@0: rect.width = NSToIntFloor(NSAppUnitsToFloatPixels(XMost(), michael@0: float(aAppUnitsPerPixel)) * aXScale) - rect.x; michael@0: rect.height = NSToIntFloor(NSAppUnitsToFloatPixels(YMost(), michael@0: float(aAppUnitsPerPixel)) * aYScale) - rect.y; michael@0: return rect; michael@0: } michael@0: michael@0: inline nsIntRect michael@0: nsRect::ToNearestPixels(nscoord aAppUnitsPerPixel) const michael@0: { michael@0: return ScaleToNearestPixels(1.0f, 1.0f, aAppUnitsPerPixel); michael@0: } michael@0: michael@0: inline nsIntRect michael@0: nsRect::ToOutsidePixels(nscoord aAppUnitsPerPixel) const michael@0: { michael@0: return ScaleToOutsidePixels(1.0f, 1.0f, aAppUnitsPerPixel); michael@0: } michael@0: michael@0: inline nsIntRect michael@0: nsRect::ToInsidePixels(nscoord aAppUnitsPerPixel) const michael@0: { michael@0: return ScaleToInsidePixels(1.0f, 1.0f, aAppUnitsPerPixel); michael@0: } michael@0: michael@0: // app units are integer multiples of pixels, so no rounding needed michael@0: inline nsRect michael@0: nsIntRect::ToAppUnits(nscoord aAppUnitsPerPixel) const michael@0: { michael@0: return nsRect(NSIntPixelsToAppUnits(x, aAppUnitsPerPixel), michael@0: NSIntPixelsToAppUnits(y, aAppUnitsPerPixel), michael@0: NSIntPixelsToAppUnits(width, aAppUnitsPerPixel), michael@0: NSIntPixelsToAppUnits(height, aAppUnitsPerPixel)); michael@0: } michael@0: michael@0: #ifdef DEBUG michael@0: // Diagnostics michael@0: extern NS_GFX FILE* operator<<(FILE* out, const nsRect& rect); michael@0: #endif // DEBUG michael@0: michael@0: #endif /* NSRECT_H */