summaryrefslogtreecommitdiffstats
path: root/gfx/src/nsRect.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/src/nsRect.h')
-rw-r--r--gfx/src/nsRect.h324
1 files changed, 324 insertions, 0 deletions
diff --git a/gfx/src/nsRect.h b/gfx/src/nsRect.h
new file mode 100644
index 000000000..267f5849c
--- /dev/null
+++ b/gfx/src/nsRect.h
@@ -0,0 +1,324 @@
+/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+
+#ifndef NSRECT_H
+#define NSRECT_H
+
+#include <stdio.h> // for FILE
+#include <stdint.h> // for int32_t, int64_t
+#include <algorithm> // for min/max
+#include "mozilla/Likely.h" // for MOZ_UNLIKELY
+#include "mozilla/gfx/Rect.h"
+#include "nsCoord.h" // for nscoord, etc
+#include "nsISupportsImpl.h" // for MOZ_COUNT_CTOR, etc
+#include "nsPoint.h" // for nsIntPoint, nsPoint
+#include "nsMargin.h" // for nsIntMargin, nsMargin
+#include "nsSize.h" // for IntSize, nsSize
+#include "nscore.h" // for NS_BUILD_REFCNT_LOGGING
+
+typedef mozilla::gfx::IntRect nsIntRect;
+
+struct nsRect :
+ public mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize, nsMargin> {
+ typedef mozilla::gfx::BaseRect<nscoord, nsRect, nsPoint, nsSize, nsMargin> Super;
+
+ static void VERIFY_COORD(nscoord aValue) { ::VERIFY_COORD(aValue); }
+
+ // Constructors
+ nsRect() : Super()
+ {
+ MOZ_COUNT_CTOR(nsRect);
+ }
+ nsRect(const nsRect& aRect) : Super(aRect)
+ {
+ MOZ_COUNT_CTOR(nsRect);
+ }
+ nsRect(const nsPoint& aOrigin, const nsSize &aSize) : Super(aOrigin, aSize)
+ {
+ MOZ_COUNT_CTOR(nsRect);
+ }
+ nsRect(nscoord aX, nscoord aY, nscoord aWidth, nscoord aHeight) :
+ Super(aX, aY, aWidth, aHeight)
+ {
+ MOZ_COUNT_CTOR(nsRect);
+ }
+
+#ifdef NS_BUILD_REFCNT_LOGGING
+ ~nsRect() {
+ MOZ_COUNT_DTOR(nsRect);
+ }
+#endif
+
+ // We have saturating versions of all the Union methods. These avoid
+ // overflowing nscoord values in the 'width' and 'height' fields by
+ // clamping the width and height values to nscoord_MAX if necessary.
+
+ MOZ_MUST_USE nsRect SaturatingUnion(const nsRect& aRect) const
+ {
+ if (IsEmpty()) {
+ return aRect;
+ } else if (aRect.IsEmpty()) {
+ return *static_cast<const nsRect*>(this);
+ } else {
+ return SaturatingUnionEdges(aRect);
+ }
+ }
+
+ MOZ_MUST_USE nsRect SaturatingUnionEdges(const nsRect& aRect) const
+ {
+#ifdef NS_COORD_IS_FLOAT
+ return UnionEdges(aRect);
+#else
+ nsRect result;
+ result.x = std::min(aRect.x, x);
+ int64_t w = std::max(int64_t(aRect.x) + aRect.width, int64_t(x) + width) - result.x;
+ if (MOZ_UNLIKELY(w > nscoord_MAX)) {
+ // Clamp huge negative x to nscoord_MIN / 2 and try again.
+ result.x = std::max(result.x, nscoord_MIN / 2);
+ w = std::max(int64_t(aRect.x) + aRect.width, int64_t(x) + width) - result.x;
+ if (MOZ_UNLIKELY(w > nscoord_MAX)) {
+ w = nscoord_MAX;
+ }
+ }
+ result.width = nscoord(w);
+
+ result.y = std::min(aRect.y, y);
+ int64_t h = std::max(int64_t(aRect.y) + aRect.height, int64_t(y) + height) - result.y;
+ if (MOZ_UNLIKELY(h > nscoord_MAX)) {
+ // Clamp huge negative y to nscoord_MIN / 2 and try again.
+ result.y = std::max(result.y, nscoord_MIN / 2);
+ h = std::max(int64_t(aRect.y) + aRect.height, int64_t(y) + height) - result.y;
+ if (MOZ_UNLIKELY(h > nscoord_MAX)) {
+ h = nscoord_MAX;
+ }
+ }
+ result.height = nscoord(h);
+ return result;
+#endif
+ }
+
+#ifndef NS_COORD_IS_FLOAT
+ // Make all nsRect Union methods be saturating.
+ MOZ_MUST_USE nsRect UnionEdges(const nsRect& aRect) const
+ {
+ return SaturatingUnionEdges(aRect);
+ }
+ void UnionRectEdges(const nsRect& aRect1, const nsRect& aRect2)
+ {
+ *this = aRect1.UnionEdges(aRect2);
+ }
+ MOZ_MUST_USE nsRect Union(const nsRect& aRect) const
+ {
+ return SaturatingUnion(aRect);
+ }
+ void UnionRect(const nsRect& aRect1, const nsRect& aRect2)
+ {
+ *this = aRect1.Union(aRect2);
+ }
+#endif
+
+ void SaturatingUnionRect(const nsRect& aRect1, const nsRect& aRect2)
+ {
+ *this = aRect1.SaturatingUnion(aRect2);
+ }
+ void SaturatingUnionRectEdges(const nsRect& aRect1, const nsRect& aRect2)
+ {
+ *this = aRect1.SaturatingUnionEdges(aRect2);
+ }
+
+ // Return whether this rect's right or bottom edge overflow int32.
+ bool Overflows() const;
+
+ /**
+ * Return this rect scaled to a different appunits per pixel (APP) ratio.
+ * 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.
+ * @param aFromAPP the APP to scale from
+ * @param aToAPP the APP to scale to
+ * @note this can turn an empty rectangle into a non-empty rectangle
+ */
+ MOZ_MUST_USE inline nsRect
+ ScaleToOtherAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const;
+ MOZ_MUST_USE inline nsRect
+ ScaleToOtherAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const;
+
+ MOZ_MUST_USE inline mozilla::gfx::IntRect
+ ScaleToNearestPixels(float aXScale, float aYScale,
+ nscoord aAppUnitsPerPixel) const;
+
+ MOZ_MUST_USE inline mozilla::gfx::IntRect
+ ToNearestPixels(nscoord aAppUnitsPerPixel) const;
+
+ // Note: this can turn an empty rectangle into a non-empty rectangle
+ MOZ_MUST_USE inline mozilla::gfx::IntRect
+ ScaleToOutsidePixels(float aXScale, float aYScale,
+ nscoord aAppUnitsPerPixel) const;
+
+ // Note: this can turn an empty rectangle into a non-empty rectangle
+ MOZ_MUST_USE inline mozilla::gfx::IntRect
+ ToOutsidePixels(nscoord aAppUnitsPerPixel) const;
+
+ MOZ_MUST_USE inline mozilla::gfx::IntRect
+ ScaleToInsidePixels(float aXScale, float aYScale,
+ nscoord aAppUnitsPerPixel) const;
+
+ MOZ_MUST_USE inline mozilla::gfx::IntRect
+ ToInsidePixels(nscoord aAppUnitsPerPixel) const;
+
+ // This is here only to keep IPDL-generated code happy. DO NOT USE.
+ bool operator==(const nsRect& aRect) const
+ {
+ return IsEqualEdges(aRect);
+ }
+
+ MOZ_MUST_USE inline nsRect RemoveResolution(const float aResolution) const;
+};
+
+/*
+ * App Unit/Pixel conversions
+ */
+
+inline nsRect
+nsRect::ScaleToOtherAppUnitsRoundOut(int32_t aFromAPP, int32_t aToAPP) const
+{
+ if (aFromAPP == aToAPP) {
+ return *this;
+ }
+
+ nsRect rect;
+ nscoord right = NSToCoordCeil(NSCoordScale(XMost(), aFromAPP, aToAPP));
+ nscoord bottom = NSToCoordCeil(NSCoordScale(YMost(), aFromAPP, aToAPP));
+ rect.x = NSToCoordFloor(NSCoordScale(x, aFromAPP, aToAPP));
+ rect.y = NSToCoordFloor(NSCoordScale(y, aFromAPP, aToAPP));
+ rect.width = (right - rect.x);
+ rect.height = (bottom - rect.y);
+
+ return rect;
+}
+
+inline nsRect
+nsRect::ScaleToOtherAppUnitsRoundIn(int32_t aFromAPP, int32_t aToAPP) const
+{
+ if (aFromAPP == aToAPP) {
+ return *this;
+ }
+
+ nsRect rect;
+ nscoord right = NSToCoordFloor(NSCoordScale(XMost(), aFromAPP, aToAPP));
+ nscoord bottom = NSToCoordFloor(NSCoordScale(YMost(), aFromAPP, aToAPP));
+ rect.x = NSToCoordCeil(NSCoordScale(x, aFromAPP, aToAPP));
+ rect.y = NSToCoordCeil(NSCoordScale(y, aFromAPP, aToAPP));
+ rect.width = (right - rect.x);
+ rect.height = (bottom - rect.y);
+
+ return rect;
+}
+
+// scale the rect but round to preserve centers
+inline mozilla::gfx::IntRect
+nsRect::ScaleToNearestPixels(float aXScale, float aYScale,
+ nscoord aAppUnitsPerPixel) const
+{
+ mozilla::gfx::IntRect rect;
+ rect.x = NSToIntRoundUp(NSAppUnitsToDoublePixels(x, aAppUnitsPerPixel) * aXScale);
+ rect.y = NSToIntRoundUp(NSAppUnitsToDoublePixels(y, aAppUnitsPerPixel) * aYScale);
+ // Avoid negative widths and heights due to overflow
+ rect.width = std::max(0, NSToIntRoundUp(NSAppUnitsToDoublePixels(XMost(),
+ aAppUnitsPerPixel) * aXScale) - rect.x);
+ rect.height = std::max(0, NSToIntRoundUp(NSAppUnitsToDoublePixels(YMost(),
+ aAppUnitsPerPixel) * aYScale) - rect.y);
+ return rect;
+}
+
+// scale the rect but round to smallest containing rect
+inline mozilla::gfx::IntRect
+nsRect::ScaleToOutsidePixels(float aXScale, float aYScale,
+ nscoord aAppUnitsPerPixel) const
+{
+ mozilla::gfx::IntRect rect;
+ rect.x = NSToIntFloor(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) * aXScale);
+ rect.y = NSToIntFloor(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) * aYScale);
+ // Avoid negative widths and heights due to overflow
+ rect.width = std::max(0, NSToIntCeil(NSAppUnitsToFloatPixels(XMost(),
+ float(aAppUnitsPerPixel)) * aXScale) - rect.x);
+ rect.height = std::max(0, NSToIntCeil(NSAppUnitsToFloatPixels(YMost(),
+ float(aAppUnitsPerPixel)) * aYScale) - rect.y);
+ return rect;
+}
+
+// scale the rect but round to largest contained rect
+inline mozilla::gfx::IntRect
+nsRect::ScaleToInsidePixels(float aXScale, float aYScale,
+ nscoord aAppUnitsPerPixel) const
+{
+ mozilla::gfx::IntRect rect;
+ rect.x = NSToIntCeil(NSAppUnitsToFloatPixels(x, float(aAppUnitsPerPixel)) * aXScale);
+ rect.y = NSToIntCeil(NSAppUnitsToFloatPixels(y, float(aAppUnitsPerPixel)) * aYScale);
+ // Avoid negative widths and heights due to overflow
+ rect.width = std::max(0, NSToIntFloor(NSAppUnitsToFloatPixels(XMost(),
+ float(aAppUnitsPerPixel)) * aXScale) - rect.x);
+ rect.height = std::max(0, NSToIntFloor(NSAppUnitsToFloatPixels(YMost(),
+ float(aAppUnitsPerPixel)) * aYScale) - rect.y);
+ return rect;
+}
+
+inline mozilla::gfx::IntRect
+nsRect::ToNearestPixels(nscoord aAppUnitsPerPixel) const
+{
+ return ScaleToNearestPixels(1.0f, 1.0f, aAppUnitsPerPixel);
+}
+
+inline mozilla::gfx::IntRect
+nsRect::ToOutsidePixels(nscoord aAppUnitsPerPixel) const
+{
+ return ScaleToOutsidePixels(1.0f, 1.0f, aAppUnitsPerPixel);
+}
+
+inline mozilla::gfx::IntRect
+nsRect::ToInsidePixels(nscoord aAppUnitsPerPixel) const
+{
+ return ScaleToInsidePixels(1.0f, 1.0f, aAppUnitsPerPixel);
+}
+
+inline nsRect
+nsRect::RemoveResolution(const float aResolution) const
+{
+ MOZ_ASSERT(aResolution > 0.0f);
+ nsRect rect;
+ rect.x = NSToCoordRound(NSCoordToFloat(x) / aResolution);
+ rect.y = NSToCoordRound(NSCoordToFloat(y) / aResolution);
+ // A 1x1 rect indicates we are just hit testing a point, so pass down a 1x1
+ // rect as well instead of possibly rounding the width or height to zero.
+ if (width == 1 && height == 1) {
+ rect.width = rect.height = 1;
+ } else {
+ rect.width = NSToCoordCeil(NSCoordToFloat(width) / aResolution);
+ rect.height = NSToCoordCeil(NSCoordToFloat(height) / aResolution);
+ }
+
+ return rect;
+}
+
+const mozilla::gfx::IntRect& GetMaxSizedIntRect();
+
+// app units are integer multiples of pixels, so no rounding needed
+template<class units>
+nsRect
+ToAppUnits(const mozilla::gfx::IntRectTyped<units>& aRect, nscoord aAppUnitsPerPixel)
+{
+ return nsRect(NSIntPixelsToAppUnits(aRect.x, aAppUnitsPerPixel),
+ NSIntPixelsToAppUnits(aRect.y, aAppUnitsPerPixel),
+ NSIntPixelsToAppUnits(aRect.width, aAppUnitsPerPixel),
+ NSIntPixelsToAppUnits(aRect.height, aAppUnitsPerPixel));
+}
+
+#ifdef DEBUG
+// Diagnostics
+extern FILE* operator<<(FILE* out, const nsRect& rect);
+#endif // DEBUG
+
+#endif /* NSRECT_H */