Bumping manifests a=b2g-bump
[gecko.git] / gfx / src / nsCoord.h
blob8dff58c976744953293028d0fcd0999ccb07ba92
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #ifndef NSCOORD_H
7 #define NSCOORD_H
9 #include "nsAlgorithm.h"
10 #include "nscore.h"
11 #include "nsMathUtils.h"
12 #include <math.h>
13 #include <float.h>
15 #include "nsDebug.h"
16 #include <algorithm>
19 * Basic type used for the geometry classes.
21 * Normally all coordinates are maintained in an app unit coordinate
22 * space. An app unit is 1/60th of a CSS device pixel, which is, in turn
23 * an integer number of device pixels, such at the CSS DPI is as close to
24 * 96dpi as possible.
27 // This controls whether we're using integers or floats for coordinates. We
28 // want to eventually use floats.
29 //#define NS_COORD_IS_FLOAT
31 inline float NS_IEEEPositiveInfinity() {
32 union { uint32_t mPRUint32; float mFloat; } pun;
33 pun.mPRUint32 = 0x7F800000;
34 return pun.mFloat;
36 inline bool NS_IEEEIsNan(float aF) {
37 union { uint32_t mBits; float mFloat; } pun;
38 pun.mFloat = aF;
39 return (pun.mBits & 0x7F800000) == 0x7F800000 &&
40 (pun.mBits & 0x007FFFFF) != 0;
43 #ifdef NS_COORD_IS_FLOAT
44 typedef float nscoord;
45 #define nscoord_MAX NS_IEEEPositiveInfinity()
46 #else
47 typedef int32_t nscoord;
48 #define nscoord_MAX nscoord(1 << 30)
49 #endif
51 #define nscoord_MIN (-nscoord_MAX)
53 inline void VERIFY_COORD(nscoord aCoord) {
54 #ifdef NS_COORD_IS_FLOAT
55 NS_ASSERTION(floorf(aCoord) == aCoord,
56 "Coords cannot have fractions");
57 #endif
60 inline nscoord NSCoordMulDiv(nscoord aMult1, nscoord aMult2, nscoord aDiv) {
61 #ifdef NS_COORD_IS_FLOAT
62 return (aMult1 * aMult2 / aDiv);
63 #else
64 return (int64_t(aMult1) * int64_t(aMult2) / int64_t(aDiv));
65 #endif
68 inline nscoord NSToCoordRound(float aValue)
70 #if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__) && !defined(__clang__)
71 return NS_lroundup30(aValue);
72 #else
73 return nscoord(floorf(aValue + 0.5f));
74 #endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
77 inline nscoord NSToCoordRound(double aValue)
79 #if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__) && !defined(__clang__)
80 return NS_lroundup30((float)aValue);
81 #else
82 return nscoord(floor(aValue + 0.5f));
83 #endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
86 inline nscoord NSToCoordRoundWithClamp(float aValue)
88 #ifndef NS_COORD_IS_FLOAT
89 // Bounds-check before converting out of float, to avoid overflow
90 if (aValue >= nscoord_MAX) {
91 return nscoord_MAX;
93 if (aValue <= nscoord_MIN) {
94 return nscoord_MIN;
96 #endif
97 return NSToCoordRound(aValue);
101 * Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
102 * appropriate for the signs of aCoord and aScale. If requireNotNegative is
103 * true, this method will enforce that aScale is not negative; use that
104 * parametrization to get a check of that fact in debug builds.
106 inline nscoord _nscoordSaturatingMultiply(nscoord aCoord, float aScale,
107 bool requireNotNegative) {
108 VERIFY_COORD(aCoord);
109 if (requireNotNegative) {
110 NS_ABORT_IF_FALSE(aScale >= 0.0f,
111 "negative scaling factors must be handled manually");
113 #ifdef NS_COORD_IS_FLOAT
114 return floorf(aCoord * aScale);
115 #else
116 float product = aCoord * aScale;
117 if (requireNotNegative ? aCoord > 0 : (aCoord > 0) == (aScale > 0))
118 return NSToCoordRoundWithClamp(std::min<float>(nscoord_MAX, product));
119 return NSToCoordRoundWithClamp(std::max<float>(nscoord_MIN, product));
120 #endif
124 * Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
125 * appropriate for the sign of aCoord. This method requires aScale to not be
126 * negative; use this method when you know that aScale should never be
127 * negative to get a sanity check of that invariant in debug builds.
129 inline nscoord NSCoordSaturatingNonnegativeMultiply(nscoord aCoord, float aScale) {
130 return _nscoordSaturatingMultiply(aCoord, aScale, true);
134 * Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
135 * appropriate for the signs of aCoord and aScale.
137 inline nscoord NSCoordSaturatingMultiply(nscoord aCoord, float aScale) {
138 return _nscoordSaturatingMultiply(aCoord, aScale, false);
142 * Returns a + b, capping the sum to nscoord_MAX.
144 * This function assumes that neither argument is nscoord_MIN.
146 * Note: If/when we start using floats for nscoords, this function won't be as
147 * necessary. Normal float addition correctly handles adding with infinity,
148 * assuming we aren't adding nscoord_MIN. (-infinity)
150 inline nscoord
151 NSCoordSaturatingAdd(nscoord a, nscoord b)
153 VERIFY_COORD(a);
154 VERIFY_COORD(b);
156 #ifdef NS_COORD_IS_FLOAT
157 // Float math correctly handles a+b, given that neither is -infinity.
158 return a + b;
159 #else
160 if (a == nscoord_MAX || b == nscoord_MAX) {
161 // infinity + anything = anything + infinity = infinity
162 return nscoord_MAX;
163 } else {
164 // a + b = a + b
165 // Cap the result, just in case we're dealing with numbers near nscoord_MAX
166 return std::min(nscoord_MAX, a + b);
168 #endif
172 * Returns a - b, gracefully handling cases involving nscoord_MAX.
173 * This function assumes that neither argument is nscoord_MIN.
175 * The behavior is as follows:
177 * a) infinity - infinity -> infMinusInfResult
178 * b) N - infinity -> 0 (unexpected -- triggers NOTREACHED)
179 * c) infinity - N -> infinity
180 * d) N1 - N2 -> N1 - N2
182 * Note: For float nscoords, cases (c) and (d) are handled by normal float
183 * math. We still need to explicitly specify the behavior for cases (a)
184 * and (b), though. (Under normal float math, those cases would return NaN
185 * and -infinity, respectively.)
187 inline nscoord
188 NSCoordSaturatingSubtract(nscoord a, nscoord b,
189 nscoord infMinusInfResult)
191 VERIFY_COORD(a);
192 VERIFY_COORD(b);
194 if (b == nscoord_MAX) {
195 if (a == nscoord_MAX) {
196 // case (a)
197 return infMinusInfResult;
198 } else {
199 // case (b)
200 NS_NOTREACHED("Attempted to subtract [n - nscoord_MAX]");
201 return 0;
203 } else {
204 #ifdef NS_COORD_IS_FLOAT
205 // case (c) and (d) for floats. (float math handles both)
206 return a - b;
207 #else
208 if (a == nscoord_MAX) {
209 // case (c) for integers
210 return nscoord_MAX;
211 } else {
212 // case (d) for integers
213 // Cap the result, in case we're dealing with numbers near nscoord_MAX
214 return std::min(nscoord_MAX, a - b);
217 #endif
220 inline float NSCoordToFloat(nscoord aCoord) {
221 VERIFY_COORD(aCoord);
222 #ifdef NS_COORD_IS_FLOAT
223 NS_ASSERTION(!NS_IEEEIsNan(aCoord), "NaN encountered in float conversion");
224 #endif
225 return (float)aCoord;
229 * Coord Rounding Functions
231 inline nscoord NSToCoordFloor(float aValue)
233 return nscoord(floorf(aValue));
236 inline nscoord NSToCoordFloor(double aValue)
238 return nscoord(floor(aValue));
241 inline nscoord NSToCoordFloorClamped(float aValue)
243 #ifndef NS_COORD_IS_FLOAT
244 // Bounds-check before converting out of float, to avoid overflow
245 if (aValue >= nscoord_MAX) {
246 return nscoord_MAX;
248 if (aValue <= nscoord_MIN) {
249 return nscoord_MIN;
251 #endif
252 return NSToCoordFloor(aValue);
255 inline nscoord NSToCoordCeil(float aValue)
257 return nscoord(ceilf(aValue));
260 inline nscoord NSToCoordCeil(double aValue)
262 return nscoord(ceil(aValue));
265 inline nscoord NSToCoordCeilClamped(double aValue)
267 #ifndef NS_COORD_IS_FLOAT
268 // Bounds-check before converting out of double, to avoid overflow
269 if (aValue >= nscoord_MAX) {
270 return nscoord_MAX;
272 if (aValue <= nscoord_MIN) {
273 return nscoord_MIN;
275 #endif
276 return NSToCoordCeil(aValue);
279 // The NSToCoordTrunc* functions remove the fractional component of
280 // aValue, and are thus equivalent to NSToCoordFloor* for positive
281 // values and NSToCoordCeil* for negative values.
283 inline nscoord NSToCoordTrunc(float aValue)
285 // There's no need to use truncf() since it matches the default
286 // rules for float to integer conversion.
287 return nscoord(aValue);
290 inline nscoord NSToCoordTrunc(double aValue)
292 // There's no need to use trunc() since it matches the default
293 // rules for float to integer conversion.
294 return nscoord(aValue);
297 inline nscoord NSToCoordTruncClamped(float aValue)
299 #ifndef NS_COORD_IS_FLOAT
300 // Bounds-check before converting out of float, to avoid overflow
301 if (aValue >= nscoord_MAX) {
302 return nscoord_MAX;
304 if (aValue <= nscoord_MIN) {
305 return nscoord_MIN;
307 #endif
308 return NSToCoordTrunc(aValue);
311 inline nscoord NSToCoordTruncClamped(double aValue)
313 #ifndef NS_COORD_IS_FLOAT
314 // Bounds-check before converting out of double, to avoid overflow
315 if (aValue >= nscoord_MAX) {
316 return nscoord_MAX;
318 if (aValue <= nscoord_MIN) {
319 return nscoord_MIN;
321 #endif
322 return NSToCoordTrunc(aValue);
326 * Int Rounding Functions
328 inline int32_t NSToIntFloor(float aValue)
330 return int32_t(floorf(aValue));
333 inline int32_t NSToIntCeil(float aValue)
335 return int32_t(ceilf(aValue));
338 inline int32_t NSToIntRound(float aValue)
340 return NS_lroundf(aValue);
343 inline int32_t NSToIntRound(double aValue)
345 return NS_lround(aValue);
348 inline int32_t NSToIntRoundUp(double aValue)
350 return int32_t(floor(aValue + 0.5));
354 * App Unit/Pixel conversions
356 inline nscoord NSFloatPixelsToAppUnits(float aPixels, float aAppUnitsPerPixel)
358 return NSToCoordRoundWithClamp(aPixels * aAppUnitsPerPixel);
361 inline nscoord NSIntPixelsToAppUnits(int32_t aPixels, int32_t aAppUnitsPerPixel)
363 // The cast to nscoord makes sure we don't overflow if we ever change
364 // nscoord to float
365 nscoord r = aPixels * (nscoord)aAppUnitsPerPixel;
366 VERIFY_COORD(r);
367 return r;
370 inline float NSAppUnitsToFloatPixels(nscoord aAppUnits, float aAppUnitsPerPixel)
372 return (float(aAppUnits) / aAppUnitsPerPixel);
375 inline double NSAppUnitsToDoublePixels(nscoord aAppUnits, double aAppUnitsPerPixel)
377 return (double(aAppUnits) / aAppUnitsPerPixel);
380 inline int32_t NSAppUnitsToIntPixels(nscoord aAppUnits, float aAppUnitsPerPixel)
382 return NSToIntRound(float(aAppUnits) / aAppUnitsPerPixel);
385 inline float NSCoordScale(nscoord aCoord, int32_t aFromAPP, int32_t aToAPP)
387 return (NSCoordToFloat(aCoord) * aToAPP) / aFromAPP;
390 /// handy constants
391 #define TWIPS_PER_POINT_INT 20
392 #define TWIPS_PER_POINT_FLOAT 20.0f
393 #define POINTS_PER_INCH_INT 72
394 #define POINTS_PER_INCH_FLOAT 72.0f
395 #define CM_PER_INCH_FLOAT 2.54f
396 #define MM_PER_INCH_FLOAT 25.4f
399 * Twips/unit conversions
401 inline float NSUnitsToTwips(float aValue, float aPointsPerUnit)
403 return aValue * aPointsPerUnit * TWIPS_PER_POINT_FLOAT;
406 inline float NSTwipsToUnits(float aTwips, float aUnitsPerPoint)
408 return (aTwips * (aUnitsPerPoint / TWIPS_PER_POINT_FLOAT));
411 /// Unit conversion macros
412 //@{
413 #define NS_POINTS_TO_TWIPS(x) NSUnitsToTwips((x), 1.0f)
414 #define NS_INCHES_TO_TWIPS(x) NSUnitsToTwips((x), POINTS_PER_INCH_FLOAT) // 72 points per inch
416 #define NS_MILLIMETERS_TO_TWIPS(x) NSUnitsToTwips((x), (POINTS_PER_INCH_FLOAT * 0.03937f))
418 #define NS_POINTS_TO_INT_TWIPS(x) NSToIntRound(NS_POINTS_TO_TWIPS(x))
419 #define NS_INCHES_TO_INT_TWIPS(x) NSToIntRound(NS_INCHES_TO_TWIPS(x))
421 #define NS_TWIPS_TO_INCHES(x) NSTwipsToUnits((x), 1.0f / POINTS_PER_INCH_FLOAT)
423 #define NS_TWIPS_TO_MILLIMETERS(x) NSTwipsToUnits((x), 1.0f / (POINTS_PER_INCH_FLOAT * 0.03937f))
424 //@}
426 #endif /* NSCOORD_H */