LCOV - code coverage report
Current view: top level - gfx/src - nsCoord.h (source / functions) Hit Total Coverage
Test: output.info Lines: 84 109 77.1 %
Date: 2017-07-14 16:53:18 Functions: 30 34 88.2 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.13