Coverage Report

Created: 2018-09-25 14:53

/work/obj-fuzz/dist/include/nsCoord.h
Line
Count
Source (jump to first uncovered line)
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/. */
6
7
#ifndef NSCOORD_H
8
#define NSCOORD_H
9
10
#include "mozilla/FloatingPoint.h"
11
12
#include "nsAlgorithm.h"
13
#include "nscore.h"
14
#include "nsMathUtils.h"
15
#include <math.h>
16
#include <float.h>
17
#include <stdlib.h>
18
19
#include "nsDebug.h"
20
#include <algorithm>
21
22
/*
23
 * Basic type used for the geometry classes.
24
 *
25
 * Normally all coordinates are maintained in an app unit coordinate
26
 * space. An app unit is 1/60th of a CSS device pixel, which is, in turn
27
 * an integer number of device pixels, such at the CSS DPI is as close to
28
 * 96dpi as possible.
29
 */
30
31
// This controls whether we're using integers or floats for coordinates. We
32
// want to eventually use floats.
33
//#define NS_COORD_IS_FLOAT
34
35
#ifdef NS_COORD_IS_FLOAT
36
typedef float nscoord;
37
#define nscoord_MAX (mozilla::PositiveInfinity<float>())
38
#else
39
typedef int32_t nscoord;
40
18
#define nscoord_MAX nscoord((1 << 30) - 1)
41
#endif
42
43
9
#define nscoord_MIN (-nscoord_MAX)
44
45
inline void VERIFY_COORD(nscoord aCoord) {
46
#ifdef NS_COORD_IS_FLOAT
47
  NS_ASSERTION(floorf(aCoord) == aCoord,
48
               "Coords cannot have fractions");
49
#endif
50
}
51
52
/**
53
 * Divide aSpace by aN.  Assign the resulting quotient to aQuotient and
54
 * return the remainder.
55
 */
56
inline nscoord NSCoordDivRem(nscoord aSpace, size_t aN, nscoord* aQuotient)
57
0
{
58
#ifdef NS_COORD_IS_FLOAT
59
  *aQuotient = aSpace / aN;
60
  return 0.0f;
61
#else
62
  div_t result = div(aSpace, aN);
63
0
  *aQuotient = nscoord(result.quot);
64
0
  return nscoord(result.rem);
65
0
#endif
66
0
}
67
68
0
inline nscoord NSCoordMulDiv(nscoord aMult1, nscoord aMult2, nscoord aDiv) {
69
#ifdef NS_COORD_IS_FLOAT
70
  return (aMult1 * aMult2 / aDiv);
71
#else
72
  return (int64_t(aMult1) * int64_t(aMult2) / int64_t(aDiv));
73
0
#endif
74
0
}
75
76
inline nscoord NSToCoordRound(float aValue)
77
{
78
#if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__) && !defined(__clang__)
79
  return NS_lroundup30(aValue);
80
#else
81
  return nscoord(floorf(aValue + 0.5f));
82
#endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
83
}
84
85
inline nscoord NSToCoordRound(double aValue)
86
{
87
#if defined(XP_WIN32) && defined(_M_IX86) && !defined(__GNUC__) && !defined(__clang__)
88
  return NS_lroundup30((float)aValue);
89
#else
90
  return nscoord(floor(aValue + 0.5f));
91
#endif /* XP_WIN32 && _M_IX86 && !__GNUC__ */
92
}
93
94
inline nscoord NSToCoordRoundWithClamp(float aValue)
95
9
{
96
9
#ifndef NS_COORD_IS_FLOAT
97
9
  // Bounds-check before converting out of float, to avoid overflow
98
9
  if (aValue >= nscoord_MAX) {
99
0
    return nscoord_MAX;
100
0
  }
101
9
  if (aValue <= nscoord_MIN) {
102
0
    return nscoord_MIN;
103
0
  }
104
9
#endif
105
9
  return NSToCoordRound(aValue);
106
9
}
107
108
/**
109
 * Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
110
 * appropriate for the signs of aCoord and aScale.  If requireNotNegative is
111
 * true, this method will enforce that aScale is not negative; use that
112
 * parametrization to get a check of that fact in debug builds.
113
 */
114
inline nscoord _nscoordSaturatingMultiply(nscoord aCoord, float aScale,
115
0
                                          bool requireNotNegative) {
116
0
  VERIFY_COORD(aCoord);
117
0
  if (requireNotNegative) {
118
0
    MOZ_ASSERT(aScale >= 0.0f,
119
0
               "negative scaling factors must be handled manually");
120
0
  }
121
#ifdef NS_COORD_IS_FLOAT
122
  return floorf(aCoord * aScale);
123
#else
124
  float product = aCoord * aScale;
125
0
  if (requireNotNegative ? aCoord > 0 : (aCoord > 0) == (aScale > 0))
126
0
    return NSToCoordRoundWithClamp(std::min<float>((float)nscoord_MAX, product));
127
0
  return NSToCoordRoundWithClamp(std::max<float>((float)nscoord_MIN, product));
128
0
#endif
129
0
}
130
131
/**
132
 * Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
133
 * appropriate for the sign of aCoord.  This method requires aScale to not be
134
 * negative; use this method when you know that aScale should never be
135
 * negative to get a sanity check of that invariant in debug builds.
136
 */
137
0
inline nscoord NSCoordSaturatingNonnegativeMultiply(nscoord aCoord, float aScale) {
138
0
  return _nscoordSaturatingMultiply(aCoord, aScale, true);
139
0
}
140
141
/**
142
 * Returns aCoord * aScale, capping the product to nscoord_MAX or nscoord_MIN as
143
 * appropriate for the signs of aCoord and aScale.
144
 */
145
0
inline nscoord NSCoordSaturatingMultiply(nscoord aCoord, float aScale) {
146
0
  return _nscoordSaturatingMultiply(aCoord, aScale, false);
147
0
}
148
149
/**
150
 * Returns a + b, capping the sum to nscoord_MAX.
151
 *
152
 * This function assumes that neither argument is nscoord_MIN.
153
 *
154
 * Note: If/when we start using floats for nscoords, this function won't be as
155
 * necessary.  Normal float addition correctly handles adding with infinity,
156
 * assuming we aren't adding nscoord_MIN. (-infinity)
157
 */
158
inline nscoord
159
NSCoordSaturatingAdd(nscoord a, nscoord b)
160
0
{
161
0
  VERIFY_COORD(a);
162
0
  VERIFY_COORD(b);
163
0
164
#ifdef NS_COORD_IS_FLOAT
165
  // Float math correctly handles a+b, given that neither is -infinity.
166
  return a + b;
167
#else
168
0
  if (a == nscoord_MAX || b == nscoord_MAX) {
169
0
    // infinity + anything = anything + infinity = infinity
170
0
    return nscoord_MAX;
171
0
  } else {
172
0
    // a + b = a + b
173
0
    // Cap the result, just in case we're dealing with numbers near nscoord_MAX
174
0
    return std::min(nscoord_MAX, a + b);
175
0
  }
176
0
#endif
177
0
}
178
179
/**
180
 * Returns a - b, gracefully handling cases involving nscoord_MAX.
181
 * This function assumes that neither argument is nscoord_MIN.
182
 *
183
 * The behavior is as follows:
184
 *
185
 *  a)  infinity - infinity -> infMinusInfResult
186
 *  b)  N - infinity        -> 0  (unexpected -- triggers NOTREACHED)
187
 *  c)  infinity - N        -> infinity
188
 *  d)  N1 - N2             -> N1 - N2
189
 *
190
 * Note: For float nscoords, cases (c) and (d) are handled by normal float
191
 * math.  We still need to explicitly specify the behavior for cases (a)
192
 * and (b), though.  (Under normal float math, those cases would return NaN
193
 * and -infinity, respectively.)
194
 */
195
inline nscoord 
196
NSCoordSaturatingSubtract(nscoord a, nscoord b, 
197
                          nscoord infMinusInfResult)
198
0
{
199
0
  VERIFY_COORD(a);
200
0
  VERIFY_COORD(b);
201
0
202
0
  if (b == nscoord_MAX) {
203
0
    if (a == nscoord_MAX) {
204
0
      // case (a)
205
0
      return infMinusInfResult;
206
0
    } else {
207
0
      // case (b)
208
0
      MOZ_ASSERT_UNREACHABLE("Attempted to subtract [n - nscoord_MAX]");
209
0
      return 0;
210
0
    }
211
0
  } else {
212
#ifdef NS_COORD_IS_FLOAT
213
    // case (c) and (d) for floats.  (float math handles both)
214
    return a - b;
215
#else
216
0
    if (a == nscoord_MAX) {
217
0
      // case (c) for integers
218
0
      return nscoord_MAX;
219
0
    } else {
220
0
      // case (d) for integers
221
0
      // Cap the result, in case we're dealing with numbers near nscoord_MAX
222
0
      return std::min(nscoord_MAX, a - b);
223
0
    }
224
0
#endif
225
0
  }
226
0
}
227
228
inline float NSCoordToFloat(nscoord aCoord) {
229
  VERIFY_COORD(aCoord);
230
#ifdef NS_COORD_IS_FLOAT
231
  NS_ASSERTION(!mozilla::IsNaN(aCoord), "NaN encountered in float conversion");
232
#endif
233
  return (float)aCoord;
234
}
235
236
/*
237
 * Coord Rounding Functions
238
 */
239
inline nscoord NSToCoordFloor(float aValue)
240
{
241
  return nscoord(floorf(aValue));
242
}
243
244
inline nscoord NSToCoordFloor(double aValue)
245
{
246
  return nscoord(floor(aValue));
247
}
248
249
inline nscoord NSToCoordFloorClamped(float aValue)
250
0
{
251
0
#ifndef NS_COORD_IS_FLOAT
252
0
  // Bounds-check before converting out of float, to avoid overflow
253
0
  if (aValue >= nscoord_MAX) {
254
0
    return nscoord_MAX;
255
0
  }
256
0
  if (aValue <= nscoord_MIN) {
257
0
    return nscoord_MIN;
258
0
  }
259
0
#endif
260
0
  return NSToCoordFloor(aValue);
261
0
}
262
263
inline nscoord NSToCoordCeil(float aValue)
264
{
265
  return nscoord(ceilf(aValue));
266
}
267
268
inline nscoord NSToCoordCeil(double aValue)
269
{
270
  return nscoord(ceil(aValue));
271
}
272
273
inline nscoord NSToCoordCeilClamped(double aValue)
274
0
{
275
0
#ifndef NS_COORD_IS_FLOAT
276
0
  // Bounds-check before converting out of double, to avoid overflow
277
0
  if (aValue >= nscoord_MAX) {
278
0
    return nscoord_MAX;
279
0
  }
280
0
  if (aValue <= nscoord_MIN) {
281
0
    return nscoord_MIN;
282
0
  }
283
0
#endif
284
0
  return NSToCoordCeil(aValue);
285
0
}
286
287
// The NSToCoordTrunc* functions remove the fractional component of
288
// aValue, and are thus equivalent to NSToCoordFloor* for positive
289
// values and NSToCoordCeil* for negative values.
290
291
inline nscoord NSToCoordTrunc(float aValue)
292
0
{
293
0
  // There's no need to use truncf() since it matches the default
294
0
  // rules for float to integer conversion.
295
0
  return nscoord(aValue);
296
0
}
297
298
inline nscoord NSToCoordTrunc(double aValue)
299
0
{
300
0
  // There's no need to use trunc() since it matches the default
301
0
  // rules for float to integer conversion.
302
0
  return nscoord(aValue);
303
0
}
304
305
inline nscoord NSToCoordTruncClamped(float aValue)
306
0
{
307
0
#ifndef NS_COORD_IS_FLOAT
308
0
  // Bounds-check before converting out of float, to avoid overflow
309
0
  if (aValue >= nscoord_MAX) {
310
0
    return nscoord_MAX;
311
0
  }
312
0
  if (aValue <= nscoord_MIN) {
313
0
    return nscoord_MIN;
314
0
  }
315
0
#endif
316
0
  return NSToCoordTrunc(aValue);
317
0
}
318
319
inline nscoord NSToCoordTruncClamped(double aValue)
320
0
{
321
0
#ifndef NS_COORD_IS_FLOAT
322
0
  // Bounds-check before converting out of double, to avoid overflow
323
0
  if (aValue >= nscoord_MAX) {
324
0
    return nscoord_MAX;
325
0
  }
326
0
  if (aValue <= nscoord_MIN) {
327
0
    return nscoord_MIN;
328
0
  }
329
0
#endif
330
0
  return NSToCoordTrunc(aValue);
331
0
}
332
333
/*
334
 * Int Rounding Functions
335
 */
336
inline int32_t NSToIntFloor(float aValue)
337
{
338
  return int32_t(floorf(aValue));
339
}
340
341
inline int32_t NSToIntCeil(float aValue)
342
{
343
  return int32_t(ceilf(aValue));
344
}
345
346
inline int32_t NSToIntRound(float aValue)
347
{
348
  return NS_lroundf(aValue);
349
}
350
351
inline int32_t NSToIntRound(double aValue)
352
0
{
353
0
  return NS_lround(aValue);
354
0
}
355
356
inline int32_t NSToIntRoundUp(double aValue)
357
0
{
358
0
  return int32_t(floor(aValue + 0.5));
359
0
}
360
361
/* 
362
 * App Unit/Pixel conversions
363
 */
364
inline nscoord NSFloatPixelsToAppUnits(float aPixels, float aAppUnitsPerPixel)
365
0
{
366
0
  return NSToCoordRoundWithClamp(aPixels * aAppUnitsPerPixel);
367
0
}
368
369
inline nscoord NSIntPixelsToAppUnits(int32_t aPixels, int32_t aAppUnitsPerPixel)
370
{
371
  // The cast to nscoord makes sure we don't overflow if we ever change
372
  // nscoord to float
373
  nscoord r = aPixels * (nscoord)aAppUnitsPerPixel;
374
  VERIFY_COORD(r);
375
  return r;
376
}
377
378
inline float NSAppUnitsToFloatPixels(nscoord aAppUnits, float aAppUnitsPerPixel)
379
{
380
  return (float(aAppUnits) / aAppUnitsPerPixel);
381
}
382
383
inline double NSAppUnitsToDoublePixels(nscoord aAppUnits, double aAppUnitsPerPixel)
384
0
{
385
0
  return (double(aAppUnits) / aAppUnitsPerPixel);
386
0
}
387
388
inline int32_t NSAppUnitsToIntPixels(nscoord aAppUnits, float aAppUnitsPerPixel)
389
0
{
390
0
  return NSToIntRound(float(aAppUnits) / aAppUnitsPerPixel);
391
0
}
392
393
inline float NSCoordScale(nscoord aCoord, int32_t aFromAPP, int32_t aToAPP)
394
{
395
  return (NSCoordToFloat(aCoord) * aToAPP) / aFromAPP;
396
}
397
398
/// handy constants
399
#define TWIPS_PER_POINT_INT           20
400
0
#define TWIPS_PER_POINT_FLOAT         20.0f
401
#define POINTS_PER_INCH_INT           72
402
0
#define POINTS_PER_INCH_FLOAT         72.0f
403
0
#define CM_PER_INCH_FLOAT             2.54f
404
0
#define MM_PER_INCH_FLOAT             25.4f
405
406
/* 
407
 * Twips/unit conversions
408
 */
409
inline float NSUnitsToTwips(float aValue, float aPointsPerUnit)
410
0
{
411
0
  return aValue * aPointsPerUnit * TWIPS_PER_POINT_FLOAT;
412
0
}
413
414
inline float NSTwipsToUnits(float aTwips, float aUnitsPerPoint)
415
0
{
416
0
  return (aTwips * (aUnitsPerPoint / TWIPS_PER_POINT_FLOAT));
417
0
}
418
419
/// Unit conversion macros
420
//@{
421
#define NS_POINTS_TO_TWIPS(x)         NSUnitsToTwips((x), 1.0f)
422
0
#define NS_INCHES_TO_TWIPS(x)         NSUnitsToTwips((x), POINTS_PER_INCH_FLOAT)                      // 72 points per inch
423
424
0
#define NS_MILLIMETERS_TO_TWIPS(x)    NSUnitsToTwips((x), (POINTS_PER_INCH_FLOAT * 0.03937f))
425
426
#define NS_POINTS_TO_INT_TWIPS(x)     NSToIntRound(NS_POINTS_TO_TWIPS(x))
427
0
#define NS_INCHES_TO_INT_TWIPS(x)     NSToIntRound(NS_INCHES_TO_TWIPS(x))
428
429
0
#define NS_TWIPS_TO_INCHES(x)         NSTwipsToUnits((x), 1.0f / POINTS_PER_INCH_FLOAT)
430
431
#define NS_TWIPS_TO_MILLIMETERS(x)    NSTwipsToUnits((x), 1.0f / (POINTS_PER_INCH_FLOAT * 0.03937f))
432
//@}
433
434
#endif /* NSCOORD_H */