gfx/src/nsCoord.h

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/gfx/src/nsCoord.h	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,372 @@
     1.4 +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
     1.5 +/* This Source Code Form is subject to the terms of the Mozilla Public
     1.6 + * License, v. 2.0. If a copy of the MPL was not distributed with this
     1.7 + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
     1.8 +
     1.9 +#ifndef NSCOORD_H
    1.10 +#define NSCOORD_H
    1.11 +
    1.12 +#include "nsAlgorithm.h"
    1.13 +#include "nscore.h"
    1.14 +#include "nsMathUtils.h"
    1.15 +#include <math.h>
    1.16 +#include <float.h>
    1.17 +
    1.18 +#include "nsDebug.h"
    1.19 +#include <algorithm>
    1.20 +
    1.21 +/*
    1.22 + * Basic type used for the geometry classes.
    1.23 + *
    1.24 + * Normally all coordinates are maintained in an app unit coordinate
    1.25 + * space. An app unit is 1/60th of a CSS device pixel, which is, in turn
    1.26 + * an integer number of device pixels, such at the CSS DPI is as close to
    1.27 + * 96dpi as possible.
    1.28 + */
    1.29 +
    1.30 +// This controls whether we're using integers or floats for coordinates. We
    1.31 +// want to eventually use floats.
    1.32 +//#define NS_COORD_IS_FLOAT
    1.33 +
    1.34 +inline float NS_IEEEPositiveInfinity() {
    1.35 +  union { uint32_t mPRUint32; float mFloat; } pun;
    1.36 +  pun.mPRUint32 = 0x7F800000;
    1.37 +  return pun.mFloat;
    1.38 +}
    1.39 +inline bool NS_IEEEIsNan(float aF) {
    1.40 +  union { uint32_t mBits; float mFloat; } pun;
    1.41 +  pun.mFloat = aF;
    1.42 +  return (pun.mBits & 0x7F800000) == 0x7F800000 &&
    1.43 +    (pun.mBits & 0x007FFFFF) != 0;
    1.44 +}
    1.45 +
    1.46 +#ifdef NS_COORD_IS_FLOAT
    1.47 +typedef float nscoord;
    1.48 +#define nscoord_MAX NS_IEEEPositiveInfinity()
    1.49 +#else
    1.50 +typedef int32_t nscoord;
    1.51 +#define nscoord_MAX nscoord(1 << 30)
    1.52 +#endif
    1.53 +
    1.54 +#define nscoord_MIN (-nscoord_MAX)
    1.55 +
    1.56 +inline void VERIFY_COORD(nscoord aCoord) {
    1.57 +#ifdef NS_COORD_IS_FLOAT
    1.58 +  NS_ASSERTION(floorf(aCoord) == aCoord,
    1.59 +               "Coords cannot have fractions");
    1.60 +#endif
    1.61 +}
    1.62 +
    1.63 +inline nscoord NSToCoordRound(float aValue)
    1.64 +{
    1.65 +#if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__)
    1.66 +  return NS_lroundup30(aValue);
    1.67 +#else
    1.68 +  return nscoord(floorf(aValue + 0.5f));
    1.69 +#endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
    1.70 +}
    1.71 +
    1.72 +inline nscoord NSToCoordRound(double aValue)
    1.73 +{
    1.74 +#if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__)
    1.75 +  return NS_lroundup30((float)aValue);
    1.76 +#else
    1.77 +  return nscoord(floor(aValue + 0.5f));
    1.78 +#endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
    1.79 +}
    1.80 +
    1.81 +inline nscoord NSToCoordRoundWithClamp(float aValue)
    1.82 +{
    1.83 +#ifndef NS_COORD_IS_FLOAT
    1.84 +  // Bounds-check before converting out of float, to avoid overflow
    1.85 +  if (aValue >= nscoord_MAX) {
    1.86 +    return nscoord_MAX;
    1.87 +  }
    1.88 +  if (aValue <= nscoord_MIN) {
    1.89 +    return nscoord_MIN;
    1.90 +  }
    1.91 +#endif
    1.92 +  return NSToCoordRound(aValue);
    1.93 +}
    1.94 +
    1.95 +/**
    1.96 + * Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
    1.97 + * appropriate for the signs of aCoord and aScale.  If requireNotNegative is
    1.98 + * true, this method will enforce that aScale is not negative; use that
    1.99 + * parametrization to get a check of that fact in debug builds.
   1.100 + */
   1.101 +inline nscoord _nscoordSaturatingMultiply(nscoord aCoord, float aScale,
   1.102 +                                          bool requireNotNegative) {
   1.103 +  VERIFY_COORD(aCoord);
   1.104 +  if (requireNotNegative) {
   1.105 +    NS_ABORT_IF_FALSE(aScale >= 0.0f,
   1.106 +                      "negative scaling factors must be handled manually");
   1.107 +  }
   1.108 +#ifdef NS_COORD_IS_FLOAT
   1.109 +  return floorf(aCoord * aScale);
   1.110 +#else
   1.111 +  float product = aCoord * aScale;
   1.112 +  if (requireNotNegative ? aCoord > 0 : (aCoord > 0) == (aScale > 0))
   1.113 +    return NSToCoordRoundWithClamp(std::min<float>(nscoord_MAX, product));
   1.114 +  return NSToCoordRoundWithClamp(std::max<float>(nscoord_MIN, product));
   1.115 +#endif
   1.116 +}
   1.117 +
   1.118 +/**
   1.119 + * Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
   1.120 + * appropriate for the sign of aCoord.  This method requires aScale to not be
   1.121 + * negative; use this method when you know that aScale should never be
   1.122 + * negative to get a sanity check of that invariant in debug builds.
   1.123 + */
   1.124 +inline nscoord NSCoordSaturatingNonnegativeMultiply(nscoord aCoord, float aScale) {
   1.125 +  return _nscoordSaturatingMultiply(aCoord, aScale, true);
   1.126 +}
   1.127 +
   1.128 +/**
   1.129 + * Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
   1.130 + * appropriate for the signs of aCoord and aScale.
   1.131 + */
   1.132 +inline nscoord NSCoordSaturatingMultiply(nscoord aCoord, float aScale) {
   1.133 +  return _nscoordSaturatingMultiply(aCoord, aScale, false);
   1.134 +}
   1.135 +
   1.136 +/**
   1.137 + * Returns a + b, capping the sum to nscoord_MAX.
   1.138 + *
   1.139 + * This function assumes that neither argument is nscoord_MIN.
   1.140 + *
   1.141 + * Note: If/when we start using floats for nscoords, this function won't be as
   1.142 + * necessary.  Normal float addition correctly handles adding with infinity,
   1.143 + * assuming we aren't adding nscoord_MIN. (-infinity)
   1.144 + */
   1.145 +inline nscoord
   1.146 +NSCoordSaturatingAdd(nscoord a, nscoord b)
   1.147 +{
   1.148 +  VERIFY_COORD(a);
   1.149 +  VERIFY_COORD(b);
   1.150 +
   1.151 +#ifdef NS_COORD_IS_FLOAT
   1.152 +  // Float math correctly handles a+b, given that neither is -infinity.
   1.153 +  return a + b;
   1.154 +#else
   1.155 +  if (a == nscoord_MAX || b == nscoord_MAX) {
   1.156 +    // infinity + anything = anything + infinity = infinity
   1.157 +    return nscoord_MAX;
   1.158 +  } else {
   1.159 +    // a + b = a + b
   1.160 +    // Cap the result, just in case we're dealing with numbers near nscoord_MAX
   1.161 +    return std::min(nscoord_MAX, a + b);
   1.162 +  }
   1.163 +#endif
   1.164 +}
   1.165 +
   1.166 +/**
   1.167 + * Returns a - b, gracefully handling cases involving nscoord_MAX.
   1.168 + * This function assumes that neither argument is nscoord_MIN.
   1.169 + *
   1.170 + * The behavior is as follows:
   1.171 + *
   1.172 + *  a)  infinity - infinity -> infMinusInfResult
   1.173 + *  b)  N - infinity        -> 0  (unexpected -- triggers NOTREACHED)
   1.174 + *  c)  infinity - N        -> infinity
   1.175 + *  d)  N1 - N2             -> N1 - N2
   1.176 + *
   1.177 + * Note: For float nscoords, cases (c) and (d) are handled by normal float
   1.178 + * math.  We still need to explicitly specify the behavior for cases (a)
   1.179 + * and (b), though.  (Under normal float math, those cases would return NaN
   1.180 + * and -infinity, respectively.)
   1.181 + */
   1.182 +inline nscoord 
   1.183 +NSCoordSaturatingSubtract(nscoord a, nscoord b, 
   1.184 +                          nscoord infMinusInfResult)
   1.185 +{
   1.186 +  VERIFY_COORD(a);
   1.187 +  VERIFY_COORD(b);
   1.188 +
   1.189 +  if (b == nscoord_MAX) {
   1.190 +    if (a == nscoord_MAX) {
   1.191 +      // case (a)
   1.192 +      return infMinusInfResult;
   1.193 +    } else {
   1.194 +      // case (b)
   1.195 +      NS_NOTREACHED("Attempted to subtract [n - nscoord_MAX]");
   1.196 +      return 0;
   1.197 +    }
   1.198 +  } else {
   1.199 +#ifdef NS_COORD_IS_FLOAT
   1.200 +    // case (c) and (d) for floats.  (float math handles both)
   1.201 +    return a - b;
   1.202 +#else
   1.203 +    if (a == nscoord_MAX) {
   1.204 +      // case (c) for integers
   1.205 +      return nscoord_MAX;
   1.206 +    } else {
   1.207 +      // case (d) for integers
   1.208 +      // Cap the result, in case we're dealing with numbers near nscoord_MAX
   1.209 +      return std::min(nscoord_MAX, a - b);
   1.210 +    }
   1.211 +  }
   1.212 +#endif
   1.213 +}
   1.214 +
   1.215 +inline float NSCoordToFloat(nscoord aCoord) {
   1.216 +  VERIFY_COORD(aCoord);
   1.217 +#ifdef NS_COORD_IS_FLOAT
   1.218 +  NS_ASSERTION(!NS_IEEEIsNan(aCoord), "NaN encountered in float conversion");
   1.219 +#endif
   1.220 +  return (float)aCoord;
   1.221 +}
   1.222 +
   1.223 +/*
   1.224 + * Coord Rounding Functions
   1.225 + */
   1.226 +inline nscoord NSToCoordFloor(float aValue)
   1.227 +{
   1.228 +  return nscoord(floorf(aValue));
   1.229 +}
   1.230 +
   1.231 +inline nscoord NSToCoordFloor(double aValue)
   1.232 +{
   1.233 +  return nscoord(floor(aValue));
   1.234 +}
   1.235 +
   1.236 +inline nscoord NSToCoordFloorClamped(float aValue)
   1.237 +{
   1.238 +#ifndef NS_COORD_IS_FLOAT
   1.239 +  // Bounds-check before converting out of float, to avoid overflow
   1.240 +  if (aValue >= nscoord_MAX) {
   1.241 +    return nscoord_MAX;
   1.242 +  }
   1.243 +  if (aValue <= nscoord_MIN) {
   1.244 +    return nscoord_MIN;
   1.245 +  }
   1.246 +#endif
   1.247 +  return NSToCoordFloor(aValue);
   1.248 +}
   1.249 +
   1.250 +inline nscoord NSToCoordCeil(float aValue)
   1.251 +{
   1.252 +  return nscoord(ceilf(aValue));
   1.253 +}
   1.254 +
   1.255 +inline nscoord NSToCoordCeil(double aValue)
   1.256 +{
   1.257 +  return nscoord(ceil(aValue));
   1.258 +}
   1.259 +
   1.260 +inline nscoord NSToCoordCeilClamped(double aValue)
   1.261 +{
   1.262 +#ifndef NS_COORD_IS_FLOAT
   1.263 +  // Bounds-check before converting out of double, to avoid overflow
   1.264 +  if (aValue >= nscoord_MAX) {
   1.265 +    return nscoord_MAX;
   1.266 +  }
   1.267 +  if (aValue <= nscoord_MIN) {
   1.268 +    return nscoord_MIN;
   1.269 +  }
   1.270 +#endif
   1.271 +  return NSToCoordCeil(aValue);
   1.272 +}
   1.273 +
   1.274 +/*
   1.275 + * Int Rounding Functions
   1.276 + */
   1.277 +inline int32_t NSToIntFloor(float aValue)
   1.278 +{
   1.279 +  return int32_t(floorf(aValue));
   1.280 +}
   1.281 +
   1.282 +inline int32_t NSToIntCeil(float aValue)
   1.283 +{
   1.284 +  return int32_t(ceilf(aValue));
   1.285 +}
   1.286 +
   1.287 +inline int32_t NSToIntRound(float aValue)
   1.288 +{
   1.289 +  return NS_lroundf(aValue);
   1.290 +}
   1.291 +
   1.292 +inline int32_t NSToIntRound(double aValue)
   1.293 +{
   1.294 +  return NS_lround(aValue);
   1.295 +}
   1.296 +
   1.297 +inline int32_t NSToIntRoundUp(double aValue)
   1.298 +{
   1.299 +  return int32_t(floor(aValue + 0.5));
   1.300 +}
   1.301 +
   1.302 +/* 
   1.303 + * App Unit/Pixel conversions
   1.304 + */
   1.305 +inline nscoord NSFloatPixelsToAppUnits(float aPixels, float aAppUnitsPerPixel)
   1.306 +{
   1.307 +  return NSToCoordRoundWithClamp(aPixels * aAppUnitsPerPixel);
   1.308 +}
   1.309 +
   1.310 +inline nscoord NSIntPixelsToAppUnits(int32_t aPixels, int32_t aAppUnitsPerPixel)
   1.311 +{
   1.312 +  // The cast to nscoord makes sure we don't overflow if we ever change
   1.313 +  // nscoord to float
   1.314 +  nscoord r = aPixels * (nscoord)aAppUnitsPerPixel;
   1.315 +  VERIFY_COORD(r);
   1.316 +  return r;
   1.317 +}
   1.318 +
   1.319 +inline float NSAppUnitsToFloatPixels(nscoord aAppUnits, float aAppUnitsPerPixel)
   1.320 +{
   1.321 +  return (float(aAppUnits) / aAppUnitsPerPixel);
   1.322 +}
   1.323 +
   1.324 +inline double NSAppUnitsToDoublePixels(nscoord aAppUnits, double aAppUnitsPerPixel)
   1.325 +{
   1.326 +  return (double(aAppUnits) / aAppUnitsPerPixel);
   1.327 +}
   1.328 +
   1.329 +inline int32_t NSAppUnitsToIntPixels(nscoord aAppUnits, float aAppUnitsPerPixel)
   1.330 +{
   1.331 +  return NSToIntRound(float(aAppUnits) / aAppUnitsPerPixel);
   1.332 +}
   1.333 +
   1.334 +inline float NSCoordScale(nscoord aCoord, int32_t aFromAPP, int32_t aToAPP)
   1.335 +{
   1.336 +  return (NSCoordToFloat(aCoord) * aToAPP) / aFromAPP;
   1.337 +}
   1.338 +
   1.339 +/// handy constants
   1.340 +#define TWIPS_PER_POINT_INT           20
   1.341 +#define TWIPS_PER_POINT_FLOAT         20.0f
   1.342 +#define POINTS_PER_INCH_INT           72
   1.343 +#define POINTS_PER_INCH_FLOAT         72.0f
   1.344 +#define CM_PER_INCH_FLOAT             2.54f
   1.345 +#define MM_PER_INCH_FLOAT             25.4f
   1.346 +
   1.347 +/* 
   1.348 + * Twips/unit conversions
   1.349 + */
   1.350 +inline float NSUnitsToTwips(float aValue, float aPointsPerUnit)
   1.351 +{
   1.352 +  return aValue * aPointsPerUnit * TWIPS_PER_POINT_FLOAT;
   1.353 +}
   1.354 +
   1.355 +inline float NSTwipsToUnits(float aTwips, float aUnitsPerPoint)
   1.356 +{
   1.357 +  return (aTwips * (aUnitsPerPoint / TWIPS_PER_POINT_FLOAT));
   1.358 +}
   1.359 +
   1.360 +/// Unit conversion macros
   1.361 +//@{
   1.362 +#define NS_POINTS_TO_TWIPS(x)         NSUnitsToTwips((x), 1.0f)
   1.363 +#define NS_INCHES_TO_TWIPS(x)         NSUnitsToTwips((x), POINTS_PER_INCH_FLOAT)                      // 72 points per inch
   1.364 +
   1.365 +#define NS_MILLIMETERS_TO_TWIPS(x)    NSUnitsToTwips((x), (POINTS_PER_INCH_FLOAT * 0.03937f))
   1.366 +
   1.367 +#define NS_POINTS_TO_INT_TWIPS(x)     NSToIntRound(NS_POINTS_TO_TWIPS(x))
   1.368 +#define NS_INCHES_TO_INT_TWIPS(x)     NSToIntRound(NS_INCHES_TO_TWIPS(x))
   1.369 +
   1.370 +#define NS_TWIPS_TO_INCHES(x)         NSTwipsToUnits((x), 1.0f / POINTS_PER_INCH_FLOAT)
   1.371 +
   1.372 +#define NS_TWIPS_TO_MILLIMETERS(x)    NSTwipsToUnits((x), 1.0f / (POINTS_PER_INCH_FLOAT * 0.03937f))
   1.373 +//@}
   1.374 +
   1.375 +#endif /* NSCOORD_H */

mercurial