Bug 1885602 - Part 2: Add a MozillaAccountMenuButton composable for the menu redesign...
[gecko.git] / gfx / src / nsCoord.h
blob6c2cd62be16afd2357f599ae594e28ec56e804b2
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef NSCOORD_H
8 #define NSCOORD_H
10 #include <algorithm>
11 #include <cstdint>
12 #include <cstdlib>
13 #include <math.h>
15 #include "mozilla/Assertions.h"
16 #include "mozilla/gfx/Coord.h"
17 #include "nsMathUtils.h"
20 * Basic type used for the geometry classes.
22 * Normally all coordinates are maintained in an app unit coordinate
23 * space. An app unit is 1/60th of a CSS device pixel, which is, in turn
24 * an integer number of device pixels, such at the CSS DPI is as close to
25 * 96dpi as possible.
28 using nscoord = int32_t;
29 inline constexpr nscoord nscoord_MAX = (1 << 30) - 1;
30 inline constexpr nscoord nscoord_MIN = -nscoord_MAX;
32 namespace mozilla {
33 struct AppUnit {};
35 // Declare AppUnit as a coordinate system tag.
36 template <>
37 struct IsPixel<AppUnit> : std::true_type {};
39 namespace detail {
40 template <typename Rep>
41 struct AuCoordImpl : public gfx::IntCoordTyped<AppUnit, Rep> {
42 using Super = gfx::IntCoordTyped<AppUnit, Rep>;
44 constexpr AuCoordImpl() : Super() {}
45 constexpr MOZ_IMPLICIT AuCoordImpl(Rep aValue) : Super(aValue) {}
46 constexpr MOZ_IMPLICIT AuCoordImpl(Super aValue) : Super(aValue) {}
48 template <typename F>
49 static AuCoordImpl FromRound(F aValue) {
50 // Note: aValue is *not* rounding to nearest integer if it is negative. See
51 // https://bugzilla.mozilla.org/show_bug.cgi?id=410748#c14
52 return AuCoordImpl(std::floor(aValue + 0.5f));
55 template <typename F>
56 static AuCoordImpl FromTruncate(F aValue) {
57 return AuCoordImpl(std::trunc(aValue));
60 template <typename F>
61 static AuCoordImpl FromCeil(F aValue) {
62 return AuCoordImpl(std::ceil(aValue));
65 template <typename F>
66 static AuCoordImpl FromFloor(F aValue) {
67 return AuCoordImpl(std::floor(aValue));
70 // Note: this returns the result of the operation, without modifying the
71 // original value.
72 [[nodiscard]] AuCoordImpl ToMinMaxClamped() const {
73 return std::clamp(this->value, kMin, kMax);
76 static constexpr Rep kMax = nscoord_MAX;
77 static constexpr Rep kMin = nscoord_MIN;
79 } // namespace detail
81 using AuCoord = detail::AuCoordImpl<int32_t>;
82 using AuCoord64 = detail::AuCoordImpl<int64_t>;
84 } // namespace mozilla
86 /**
87 * Divide aSpace by aN. Assign the resulting quotient to aQuotient and
88 * return the remainder.
90 inline nscoord NSCoordDivRem(nscoord aSpace, size_t aN, nscoord* aQuotient) {
91 div_t result = div(aSpace, aN);
92 *aQuotient = nscoord(result.quot);
93 return nscoord(result.rem);
96 inline nscoord NSCoordMulDiv(nscoord aMult1, nscoord aMult2, nscoord aDiv) {
97 return (int64_t(aMult1) * int64_t(aMult2) / int64_t(aDiv));
100 inline nscoord NSToCoordRound(float aValue) {
101 #if defined(XP_WIN) && defined(_M_IX86) && !defined(__GNUC__) && \
102 !defined(__clang__)
103 return NS_lroundup30(aValue);
104 #else
105 return nscoord(floorf(aValue + 0.5f));
106 #endif /* XP_WIN && _M_IX86 && !__GNUC__ */
109 inline nscoord NSToCoordRound(double aValue) {
110 #if defined(XP_WIN) && defined(_M_IX86) && !defined(__GNUC__) && \
111 !defined(__clang__)
112 return NS_lroundup30((float)aValue);
113 #else
114 return nscoord(floor(aValue + 0.5f));
115 #endif /* XP_WIN && _M_IX86 && !__GNUC__ */
118 inline nscoord NSToCoordRoundWithClamp(float aValue) {
119 // Bounds-check before converting out of float, to avoid overflow
120 if (aValue >= float(nscoord_MAX)) {
121 return nscoord_MAX;
123 if (aValue <= float(nscoord_MIN)) {
124 return nscoord_MIN;
126 return NSToCoordRound(aValue);
129 inline nscoord NSToCoordRoundWithClamp(double aValue) {
130 // Bounds-check before converting out of double, to avoid overflow
131 if (aValue >= double(nscoord_MAX)) {
132 return nscoord_MAX;
134 if (aValue <= double(nscoord_MIN)) {
135 return nscoord_MIN;
137 return NSToCoordRound(aValue);
141 * Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
142 * appropriate for the signs of aCoord and aScale. If requireNotNegative is
143 * true, this method will enforce that aScale is not negative; use that
144 * parametrization to get a check of that fact in debug builds.
146 inline nscoord _nscoordSaturatingMultiply(nscoord aCoord, float aScale,
147 bool requireNotNegative) {
148 if (requireNotNegative) {
149 MOZ_ASSERT(aScale >= 0.0f,
150 "negative scaling factors must be handled manually");
152 float product = aCoord * aScale;
153 if (requireNotNegative ? aCoord > 0 : (aCoord > 0) == (aScale > 0))
154 return NSToCoordRoundWithClamp(
155 std::min<float>((float)nscoord_MAX, product));
156 return NSToCoordRoundWithClamp(std::max<float>((float)nscoord_MIN, product));
160 * Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
161 * appropriate for the sign of aCoord. This method requires aScale to not be
162 * negative; use this method when you know that aScale should never be
163 * negative to get a sanity check of that invariant in debug builds.
165 inline nscoord NSCoordSaturatingNonnegativeMultiply(nscoord aCoord,
166 float aScale) {
167 return _nscoordSaturatingMultiply(aCoord, aScale, true);
171 * Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
172 * appropriate for the signs of aCoord and aScale.
174 inline nscoord NSCoordSaturatingMultiply(nscoord aCoord, float aScale) {
175 return _nscoordSaturatingMultiply(aCoord, aScale, false);
179 * Returns a + b, capping the sum to nscoord_MAX.
181 * This function assumes that neither argument is nscoord_MIN.
183 inline nscoord NSCoordSaturatingAdd(nscoord a, nscoord b) {
184 if (a == nscoord_MAX || b == nscoord_MAX) {
185 // infinity + anything = anything + infinity = infinity
186 return nscoord_MAX;
187 } else {
188 // a + b = a + b
189 // Cap the result, just in case we're dealing with numbers near nscoord_MAX
190 return std::min(nscoord_MAX, a + b);
195 * Returns a - b, gracefully handling cases involving nscoord_MAX.
196 * This function assumes that neither argument is nscoord_MIN.
198 * The behavior is as follows:
200 * a) infinity - infinity -> infMinusInfResult
201 * b) N - infinity -> 0 (unexpected -- triggers NOTREACHED)
202 * c) infinity - N -> infinity
203 * d) N1 - N2 -> N1 - N2
205 inline nscoord NSCoordSaturatingSubtract(nscoord a, nscoord b,
206 nscoord infMinusInfResult) {
207 if (b == nscoord_MAX) {
208 if (a == nscoord_MAX) {
209 // case (a)
210 return infMinusInfResult;
211 } else {
212 // case (b)
213 return 0;
215 } else {
216 if (a == nscoord_MAX) {
217 // case (c) for integers
218 return nscoord_MAX;
219 } else {
220 // case (d) for integers
221 // Cap the result, in case we're dealing with numbers near nscoord_MAX
222 return std::min(nscoord_MAX, a - b);
227 inline float NSCoordToFloat(nscoord aCoord) { return (float)aCoord; }
230 * Coord Rounding Functions
232 inline nscoord NSToCoordFloor(float aValue) { return nscoord(floorf(aValue)); }
234 inline nscoord NSToCoordFloor(double aValue) { return nscoord(floor(aValue)); }
236 inline nscoord NSToCoordFloorClamped(float aValue) {
237 // Bounds-check before converting out of float, to avoid overflow
238 if (aValue >= float(nscoord_MAX)) {
239 return nscoord_MAX;
241 if (aValue <= float(nscoord_MIN)) {
242 return nscoord_MIN;
244 return NSToCoordFloor(aValue);
247 inline nscoord NSToCoordCeil(float aValue) { return nscoord(ceilf(aValue)); }
249 inline nscoord NSToCoordCeil(double aValue) { return nscoord(ceil(aValue)); }
251 inline nscoord NSToCoordCeilClamped(double aValue) {
252 // Bounds-check before converting out of double, to avoid overflow
253 if (aValue >= nscoord_MAX) {
254 return nscoord_MAX;
256 if (aValue <= nscoord_MIN) {
257 return nscoord_MIN;
259 return NSToCoordCeil(aValue);
262 // The NSToCoordTrunc* functions remove the fractional component of
263 // aValue, and are thus equivalent to NSToCoordFloor* for positive
264 // values and NSToCoordCeil* for negative values.
266 inline nscoord NSToCoordTrunc(float aValue) {
267 // There's no need to use truncf() since it matches the default
268 // rules for float to integer conversion.
269 return nscoord(aValue);
272 inline nscoord NSToCoordTrunc(double aValue) {
273 // There's no need to use trunc() since it matches the default
274 // rules for float to integer conversion.
275 return nscoord(aValue);
278 inline nscoord NSToCoordTruncClamped(float aValue) {
279 // Bounds-check before converting out of float, to avoid overflow
280 if (aValue >= float(nscoord_MAX)) {
281 return nscoord_MAX;
283 if (aValue <= float(nscoord_MIN)) {
284 return nscoord_MIN;
286 return NSToCoordTrunc(aValue);
289 inline nscoord NSToCoordTruncClamped(double aValue) {
290 // Bounds-check before converting out of double, to avoid overflow
291 if (aValue >= float(nscoord_MAX)) {
292 return nscoord_MAX;
294 if (aValue <= float(nscoord_MIN)) {
295 return nscoord_MIN;
297 return NSToCoordTrunc(aValue);
301 * Int Rounding Functions
303 inline int32_t NSToIntFloor(float aValue) { return int32_t(floorf(aValue)); }
305 inline int32_t NSToIntCeil(float aValue) { return int32_t(ceilf(aValue)); }
307 inline int32_t NSToIntRound(float aValue) { return NS_lroundf(aValue); }
309 inline int32_t NSToIntRound(double aValue) { return NS_lround(aValue); }
311 inline int32_t NSToIntRoundUp(double aValue) {
312 return int32_t(floor(aValue + 0.5));
316 * App Unit/Pixel conversions
318 inline nscoord NSFloatPixelsToAppUnits(float aPixels, float aAppUnitsPerPixel) {
319 return NSToCoordRoundWithClamp(aPixels * aAppUnitsPerPixel);
322 inline nscoord NSIntPixelsToAppUnits(int32_t aPixels,
323 int32_t aAppUnitsPerPixel) {
324 // The cast to nscoord makes sure we don't overflow if we ever change
325 // nscoord to float
326 nscoord r = aPixels * (nscoord)aAppUnitsPerPixel;
327 return r;
330 inline float NSAppUnitsToFloatPixels(nscoord aAppUnits,
331 float aAppUnitsPerPixel) {
332 return (float(aAppUnits) / aAppUnitsPerPixel);
335 inline double NSAppUnitsToDoublePixels(nscoord aAppUnits,
336 double aAppUnitsPerPixel) {
337 return (double(aAppUnits) / aAppUnitsPerPixel);
340 inline int32_t NSAppUnitsToIntPixels(nscoord aAppUnits,
341 float aAppUnitsPerPixel) {
342 return NSToIntRound(float(aAppUnits) / aAppUnitsPerPixel);
345 inline float NSCoordScale(nscoord aCoord, int32_t aFromAPP, int32_t aToAPP) {
346 return (NSCoordToFloat(aCoord) * aToAPP) / aFromAPP;
349 /// handy constants
350 #define TWIPS_PER_POINT_INT 20
351 #define TWIPS_PER_POINT_FLOAT 20.0f
352 #define POINTS_PER_INCH_INT 72
353 #define POINTS_PER_INCH_FLOAT 72.0f
354 #define CM_PER_INCH_FLOAT 2.54f
355 #define MM_PER_INCH_FLOAT 25.4f
358 * Twips/unit conversions
360 inline float NSUnitsToTwips(float aValue, float aPointsPerUnit) {
361 return aValue * aPointsPerUnit * TWIPS_PER_POINT_FLOAT;
364 inline float NSTwipsToUnits(float aTwips, float aUnitsPerPoint) {
365 return (aTwips * (aUnitsPerPoint / TWIPS_PER_POINT_FLOAT));
368 /// Unit conversion macros
369 //@{
370 #define NS_POINTS_TO_TWIPS(x) NSUnitsToTwips((x), 1.0f)
371 #define NS_INCHES_TO_TWIPS(x) \
372 NSUnitsToTwips((x), POINTS_PER_INCH_FLOAT) // 72 points per inch
374 #define NS_MILLIMETERS_TO_TWIPS(x) \
375 NSUnitsToTwips((x), (POINTS_PER_INCH_FLOAT * 0.03937f))
377 #define NS_POINTS_TO_INT_TWIPS(x) NSToIntRound(NS_POINTS_TO_TWIPS(x))
378 #define NS_INCHES_TO_INT_TWIPS(x) NSToIntRound(NS_INCHES_TO_TWIPS(x))
380 #define NS_TWIPS_TO_INCHES(x) NSTwipsToUnits((x), 1.0f / POINTS_PER_INCH_FLOAT)
382 #define NS_TWIPS_TO_MILLIMETERS(x) \
383 NSTwipsToUnits((x), 1.0f / (POINTS_PER_INCH_FLOAT * 0.03937f))
384 //@}
386 #endif /* NSCOORD_H */