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 */