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/. */
9 #include "nsAlgorithm.h"
11 #include "nsMathUtils.h"
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
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;
36 inline bool NS_IEEEIsNan(float aF
) {
37 union { uint32_t mBits
; float mFloat
; } pun
;
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()
47 typedef int32_t nscoord
;
48 #define nscoord_MAX nscoord(1 << 30)
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");
60 inline nscoord
NSCoordMulDiv(nscoord aMult1
, nscoord aMult2
, nscoord aDiv
) {
61 #ifdef NS_COORD_IS_FLOAT
62 return (aMult1
* aMult2
/ aDiv
);
64 return (int64_t(aMult1
) * int64_t(aMult2
) / int64_t(aDiv
));
68 inline nscoord
NSToCoordRound(float aValue
)
70 #if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__) && !defined(__clang__)
71 return NS_lroundup30(aValue
);
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
);
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
) {
93 if (aValue
<= nscoord_MIN
) {
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
);
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
));
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)
151 NSCoordSaturatingAdd(nscoord a
, nscoord b
)
156 #ifdef NS_COORD_IS_FLOAT
157 // Float math correctly handles a+b, given that neither is -infinity.
160 if (a
== nscoord_MAX
|| b
== nscoord_MAX
) {
161 // infinity + anything = anything + infinity = infinity
165 // Cap the result, just in case we're dealing with numbers near nscoord_MAX
166 return std::min(nscoord_MAX
, a
+ b
);
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.)
188 NSCoordSaturatingSubtract(nscoord a
, nscoord b
,
189 nscoord infMinusInfResult
)
194 if (b
== nscoord_MAX
) {
195 if (a
== nscoord_MAX
) {
197 return infMinusInfResult
;
200 NS_NOTREACHED("Attempted to subtract [n - nscoord_MAX]");
204 #ifdef NS_COORD_IS_FLOAT
205 // case (c) and (d) for floats. (float math handles both)
208 if (a
== nscoord_MAX
) {
209 // case (c) for integers
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
);
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");
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
) {
248 if (aValue
<= nscoord_MIN
) {
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
) {
272 if (aValue
<= nscoord_MIN
) {
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
) {
304 if (aValue
<= nscoord_MIN
) {
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
) {
318 if (aValue
<= nscoord_MIN
) {
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
365 nscoord r
= aPixels
* (nscoord
)aAppUnitsPerPixel
;
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
;
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
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))
426 #endif /* NSCOORD_H */