summaryrefslogtreecommitdiffstats
path: root/gfx/src/nsCoord.h
diff options
context:
space:
mode:
Diffstat (limited to 'gfx/src/nsCoord.h')
-rw-r--r--gfx/src/nsCoord.h443
1 files changed, 443 insertions, 0 deletions
diff --git a/gfx/src/nsCoord.h b/gfx/src/nsCoord.h
new file mode 100644
index 000000000..bb53611cf
--- /dev/null
+++ b/gfx/src/nsCoord.h
@@ -0,0 +1,443 @@
+/* -*- 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 NSCOORD_H
+#define NSCOORD_H
+
+#include "nsAlgorithm.h"
+#include "nscore.h"
+#include "nsMathUtils.h"
+#include <math.h>
+#include <float.h>
+#include <stdlib.h>
+
+#include "nsDebug.h"
+#include <algorithm>
+
+/*
+ * Basic type used for the geometry classes.
+ *
+ * Normally all coordinates are maintained in an app unit coordinate
+ * space. An app unit is 1/60th of a CSS device pixel, which is, in turn
+ * an integer number of device pixels, such at the CSS DPI is as close to
+ * 96dpi as possible.
+ */
+
+// This controls whether we're using integers or floats for coordinates. We
+// want to eventually use floats.
+//#define NS_COORD_IS_FLOAT
+
+inline float NS_IEEEPositiveInfinity() {
+ union { uint32_t mPRUint32; float mFloat; } pun;
+ pun.mPRUint32 = 0x7F800000;
+ return pun.mFloat;
+}
+inline bool NS_IEEEIsNan(float aF) {
+ union { uint32_t mBits; float mFloat; } pun;
+ pun.mFloat = aF;
+ return (pun.mBits & 0x7F800000) == 0x7F800000 &&
+ (pun.mBits & 0x007FFFFF) != 0;
+}
+
+#ifdef NS_COORD_IS_FLOAT
+typedef float nscoord;
+#define nscoord_MAX NS_IEEEPositiveInfinity()
+#else
+typedef int32_t nscoord;
+#define nscoord_MAX nscoord(1 << 30)
+#endif
+
+#define nscoord_MIN (-nscoord_MAX)
+
+inline void VERIFY_COORD(nscoord aCoord) {
+#ifdef NS_COORD_IS_FLOAT
+ NS_ASSERTION(floorf(aCoord) == aCoord,
+ "Coords cannot have fractions");
+#endif
+}
+
+/**
+ * Divide aSpace by aN. Assign the resulting quotient to aQuotient and
+ * return the remainder.
+ */
+inline nscoord NSCoordDivRem(nscoord aSpace, size_t aN, nscoord* aQuotient)
+{
+#ifdef NS_COORD_IS_FLOAT
+ *aQuotient = aSpace / aN;
+ return 0.0f;
+#else
+ div_t result = div(aSpace, aN);
+ *aQuotient = nscoord(result.quot);
+ return nscoord(result.rem);
+#endif
+}
+
+inline nscoord NSCoordMulDiv(nscoord aMult1, nscoord aMult2, nscoord aDiv) {
+#ifdef NS_COORD_IS_FLOAT
+ return (aMult1 * aMult2 / aDiv);
+#else
+ return (int64_t(aMult1) * int64_t(aMult2) / int64_t(aDiv));
+#endif
+}
+
+inline nscoord NSToCoordRound(float aValue)
+{
+#if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__) && !defined(__clang__)
+ return NS_lroundup30(aValue);
+#else
+ return nscoord(floorf(aValue + 0.5f));
+#endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
+}
+
+inline nscoord NSToCoordRound(double aValue)
+{
+#if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__) && !defined(__clang__)
+ return NS_lroundup30((float)aValue);
+#else
+ return nscoord(floor(aValue + 0.5f));
+#endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
+}
+
+inline nscoord NSToCoordRoundWithClamp(float aValue)
+{
+#ifndef NS_COORD_IS_FLOAT
+ // Bounds-check before converting out of float, to avoid overflow
+ if (aValue >= nscoord_MAX) {
+ return nscoord_MAX;
+ }
+ if (aValue <= nscoord_MIN) {
+ return nscoord_MIN;
+ }
+#endif
+ return NSToCoordRound(aValue);
+}
+
+/**
+ * Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
+ * appropriate for the signs of aCoord and aScale. If requireNotNegative is
+ * true, this method will enforce that aScale is not negative; use that
+ * parametrization to get a check of that fact in debug builds.
+ */
+inline nscoord _nscoordSaturatingMultiply(nscoord aCoord, float aScale,
+ bool requireNotNegative) {
+ VERIFY_COORD(aCoord);
+ if (requireNotNegative) {
+ MOZ_ASSERT(aScale >= 0.0f,
+ "negative scaling factors must be handled manually");
+ }
+#ifdef NS_COORD_IS_FLOAT
+ return floorf(aCoord * aScale);
+#else
+ float product = aCoord * aScale;
+ if (requireNotNegative ? aCoord > 0 : (aCoord > 0) == (aScale > 0))
+ return NSToCoordRoundWithClamp(std::min<float>(nscoord_MAX, product));
+ return NSToCoordRoundWithClamp(std::max<float>(nscoord_MIN, product));
+#endif
+}
+
+/**
+ * Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
+ * appropriate for the sign of aCoord. This method requires aScale to not be
+ * negative; use this method when you know that aScale should never be
+ * negative to get a sanity check of that invariant in debug builds.
+ */
+inline nscoord NSCoordSaturatingNonnegativeMultiply(nscoord aCoord, float aScale) {
+ return _nscoordSaturatingMultiply(aCoord, aScale, true);
+}
+
+/**
+ * Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
+ * appropriate for the signs of aCoord and aScale.
+ */
+inline nscoord NSCoordSaturatingMultiply(nscoord aCoord, float aScale) {
+ return _nscoordSaturatingMultiply(aCoord, aScale, false);
+}
+
+/**
+ * Returns a + b, capping the sum to nscoord_MAX.
+ *
+ * This function assumes that neither argument is nscoord_MIN.
+ *
+ * Note: If/when we start using floats for nscoords, this function won't be as
+ * necessary. Normal float addition correctly handles adding with infinity,
+ * assuming we aren't adding nscoord_MIN. (-infinity)
+ */
+inline nscoord
+NSCoordSaturatingAdd(nscoord a, nscoord b)
+{
+ VERIFY_COORD(a);
+ VERIFY_COORD(b);
+
+#ifdef NS_COORD_IS_FLOAT
+ // Float math correctly handles a+b, given that neither is -infinity.
+ return a + b;
+#else
+ if (a == nscoord_MAX || b == nscoord_MAX) {
+ // infinity + anything = anything + infinity = infinity
+ return nscoord_MAX;
+ } else {
+ // a + b = a + b
+ // Cap the result, just in case we're dealing with numbers near nscoord_MAX
+ return std::min(nscoord_MAX, a + b);
+ }
+#endif
+}
+
+/**
+ * Returns a - b, gracefully handling cases involving nscoord_MAX.
+ * This function assumes that neither argument is nscoord_MIN.
+ *
+ * The behavior is as follows:
+ *
+ * a) infinity - infinity -> infMinusInfResult
+ * b) N - infinity -> 0 (unexpected -- triggers NOTREACHED)
+ * c) infinity - N -> infinity
+ * d) N1 - N2 -> N1 - N2
+ *
+ * Note: For float nscoords, cases (c) and (d) are handled by normal float
+ * math. We still need to explicitly specify the behavior for cases (a)
+ * and (b), though. (Under normal float math, those cases would return NaN
+ * and -infinity, respectively.)
+ */
+inline nscoord
+NSCoordSaturatingSubtract(nscoord a, nscoord b,
+ nscoord infMinusInfResult)
+{
+ VERIFY_COORD(a);
+ VERIFY_COORD(b);
+
+ if (b == nscoord_MAX) {
+ if (a == nscoord_MAX) {
+ // case (a)
+ return infMinusInfResult;
+ } else {
+ // case (b)
+ NS_NOTREACHED("Attempted to subtract [n - nscoord_MAX]");
+ return 0;
+ }
+ } else {
+#ifdef NS_COORD_IS_FLOAT
+ // case (c) and (d) for floats. (float math handles both)
+ return a - b;
+#else
+ if (a == nscoord_MAX) {
+ // case (c) for integers
+ return nscoord_MAX;
+ } else {
+ // case (d) for integers
+ // Cap the result, in case we're dealing with numbers near nscoord_MAX
+ return std::min(nscoord_MAX, a - b);
+ }
+#endif
+ }
+}
+
+inline float NSCoordToFloat(nscoord aCoord) {
+ VERIFY_COORD(aCoord);
+#ifdef NS_COORD_IS_FLOAT
+ NS_ASSERTION(!NS_IEEEIsNan(aCoord), "NaN encountered in float conversion");
+#endif
+ return (float)aCoord;
+}
+
+/*
+ * Coord Rounding Functions
+ */
+inline nscoord NSToCoordFloor(float aValue)
+{
+ return nscoord(floorf(aValue));
+}
+
+inline nscoord NSToCoordFloor(double aValue)
+{
+ return nscoord(floor(aValue));
+}
+
+inline nscoord NSToCoordFloorClamped(float aValue)
+{
+#ifndef NS_COORD_IS_FLOAT
+ // Bounds-check before converting out of float, to avoid overflow
+ if (aValue >= nscoord_MAX) {
+ return nscoord_MAX;
+ }
+ if (aValue <= nscoord_MIN) {
+ return nscoord_MIN;
+ }
+#endif
+ return NSToCoordFloor(aValue);
+}
+
+inline nscoord NSToCoordCeil(float aValue)
+{
+ return nscoord(ceilf(aValue));
+}
+
+inline nscoord NSToCoordCeil(double aValue)
+{
+ return nscoord(ceil(aValue));
+}
+
+inline nscoord NSToCoordCeilClamped(double aValue)
+{
+#ifndef NS_COORD_IS_FLOAT
+ // Bounds-check before converting out of double, to avoid overflow
+ if (aValue >= nscoord_MAX) {
+ return nscoord_MAX;
+ }
+ if (aValue <= nscoord_MIN) {
+ return nscoord_MIN;
+ }
+#endif
+ return NSToCoordCeil(aValue);
+}
+
+// The NSToCoordTrunc* functions remove the fractional component of
+// aValue, and are thus equivalent to NSToCoordFloor* for positive
+// values and NSToCoordCeil* for negative values.
+
+inline nscoord NSToCoordTrunc(float aValue)
+{
+ // There's no need to use truncf() since it matches the default
+ // rules for float to integer conversion.
+ return nscoord(aValue);
+}
+
+inline nscoord NSToCoordTrunc(double aValue)
+{
+ // There's no need to use trunc() since it matches the default
+ // rules for float to integer conversion.
+ return nscoord(aValue);
+}
+
+inline nscoord NSToCoordTruncClamped(float aValue)
+{
+#ifndef NS_COORD_IS_FLOAT
+ // Bounds-check before converting out of float, to avoid overflow
+ if (aValue >= nscoord_MAX) {
+ return nscoord_MAX;
+ }
+ if (aValue <= nscoord_MIN) {
+ return nscoord_MIN;
+ }
+#endif
+ return NSToCoordTrunc(aValue);
+}
+
+inline nscoord NSToCoordTruncClamped(double aValue)
+{
+#ifndef NS_COORD_IS_FLOAT
+ // Bounds-check before converting out of double, to avoid overflow
+ if (aValue >= nscoord_MAX) {
+ return nscoord_MAX;
+ }
+ if (aValue <= nscoord_MIN) {
+ return nscoord_MIN;
+ }
+#endif
+ return NSToCoordTrunc(aValue);
+}
+
+/*
+ * Int Rounding Functions
+ */
+inline int32_t NSToIntFloor(float aValue)
+{
+ return int32_t(floorf(aValue));
+}
+
+inline int32_t NSToIntCeil(float aValue)
+{
+ return int32_t(ceilf(aValue));
+}
+
+inline int32_t NSToIntRound(float aValue)
+{
+ return NS_lroundf(aValue);
+}
+
+inline int32_t NSToIntRound(double aValue)
+{
+ return NS_lround(aValue);
+}
+
+inline int32_t NSToIntRoundUp(double aValue)
+{
+ return int32_t(floor(aValue + 0.5));
+}
+
+/*
+ * App Unit/Pixel conversions
+ */
+inline nscoord NSFloatPixelsToAppUnits(float aPixels, float aAppUnitsPerPixel)
+{
+ return NSToCoordRoundWithClamp(aPixels * aAppUnitsPerPixel);
+}
+
+inline nscoord NSIntPixelsToAppUnits(int32_t aPixels, int32_t aAppUnitsPerPixel)
+{
+ // The cast to nscoord makes sure we don't overflow if we ever change
+ // nscoord to float
+ nscoord r = aPixels * (nscoord)aAppUnitsPerPixel;
+ VERIFY_COORD(r);
+ return r;
+}
+
+inline float NSAppUnitsToFloatPixels(nscoord aAppUnits, float aAppUnitsPerPixel)
+{
+ return (float(aAppUnits) / aAppUnitsPerPixel);
+}
+
+inline double NSAppUnitsToDoublePixels(nscoord aAppUnits, double aAppUnitsPerPixel)
+{
+ return (double(aAppUnits) / aAppUnitsPerPixel);
+}
+
+inline int32_t NSAppUnitsToIntPixels(nscoord aAppUnits, float aAppUnitsPerPixel)
+{
+ return NSToIntRound(float(aAppUnits) / aAppUnitsPerPixel);
+}
+
+inline float NSCoordScale(nscoord aCoord, int32_t aFromAPP, int32_t aToAPP)
+{
+ return (NSCoordToFloat(aCoord) * aToAPP) / aFromAPP;
+}
+
+/// handy constants
+#define TWIPS_PER_POINT_INT 20
+#define TWIPS_PER_POINT_FLOAT 20.0f
+#define POINTS_PER_INCH_INT 72
+#define POINTS_PER_INCH_FLOAT 72.0f
+#define CM_PER_INCH_FLOAT 2.54f
+#define MM_PER_INCH_FLOAT 25.4f
+
+/*
+ * Twips/unit conversions
+ */
+inline float NSUnitsToTwips(float aValue, float aPointsPerUnit)
+{
+ return aValue * aPointsPerUnit * TWIPS_PER_POINT_FLOAT;
+}
+
+inline float NSTwipsToUnits(float aTwips, float aUnitsPerPoint)
+{
+ return (aTwips * (aUnitsPerPoint / TWIPS_PER_POINT_FLOAT));
+}
+
+/// Unit conversion macros
+//@{
+#define NS_POINTS_TO_TWIPS(x) NSUnitsToTwips((x), 1.0f)
+#define NS_INCHES_TO_TWIPS(x) NSUnitsToTwips((x), POINTS_PER_INCH_FLOAT) // 72 points per inch
+
+#define NS_MILLIMETERS_TO_TWIPS(x) NSUnitsToTwips((x), (POINTS_PER_INCH_FLOAT * 0.03937f))
+
+#define NS_POINTS_TO_INT_TWIPS(x) NSToIntRound(NS_POINTS_TO_TWIPS(x))
+#define NS_INCHES_TO_INT_TWIPS(x) NSToIntRound(NS_INCHES_TO_TWIPS(x))
+
+#define NS_TWIPS_TO_INCHES(x) NSTwipsToUnits((x), 1.0f / POINTS_PER_INCH_FLOAT)
+
+#define NS_TWIPS_TO_MILLIMETERS(x) NSTwipsToUnits((x), 1.0f / (POINTS_PER_INCH_FLOAT * 0.03937f))
+//@}
+
+#endif /* NSCOORD_H */