tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

Point.h (14648B)


      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 MOZILLA_GFX_POINT_H_
      8 #define MOZILLA_GFX_POINT_H_
      9 
     10 #include "mozilla/Attributes.h"
     11 #include "Types.h"
     12 #include "Coord.h"
     13 #include "BaseCoord.h"
     14 #include "BasePoint.h"
     15 #include "BasePoint3D.h"
     16 #include "BasePoint4D.h"
     17 #include "BaseSize.h"
     18 #include "mozilla/gfx/NumericTools.h"
     19 
     20 #include <cmath>
     21 #include <type_traits>
     22 
     23 namespace mozilla {
     24 
     25 template <typename>
     26 struct IsPixel;
     27 
     28 template <>
     29 struct IsPixel<gfx::UnknownUnits> : std::true_type {};
     30 
     31 namespace gfx {
     32 
     33 /// Use this for parameters of functions to allow implicit conversions to
     34 /// integer types but not floating point types.
     35 /// We use this wrapper to prevent IntSize and IntPoint's constructors to
     36 /// take foating point values as parameters, and not require their constructors
     37 /// to have implementations for each permutation of integer types.
     38 template <typename T>
     39 struct IntParam {
     40  constexpr MOZ_IMPLICIT IntParam(char val) : value(val) {}
     41  constexpr MOZ_IMPLICIT IntParam(unsigned char val) : value(val) {}
     42  constexpr MOZ_IMPLICIT IntParam(short val) : value(val) {}
     43  constexpr MOZ_IMPLICIT IntParam(unsigned short val) : value(val) {}
     44  constexpr MOZ_IMPLICIT IntParam(int val) : value(val) {}
     45  constexpr MOZ_IMPLICIT IntParam(unsigned int val) : value(val) {}
     46  constexpr MOZ_IMPLICIT IntParam(long val) : value(val) {}
     47  constexpr MOZ_IMPLICIT IntParam(unsigned long val) : value(val) {}
     48  constexpr MOZ_IMPLICIT IntParam(long long val) : value(val) {}
     49  constexpr MOZ_IMPLICIT IntParam(unsigned long long val) : value(val) {}
     50  template <typename Unit>
     51  constexpr MOZ_IMPLICIT IntParam(IntCoordTyped<Unit> val) : value(val) {}
     52 
     53  // Disable the evil ones!
     54  MOZ_IMPLICIT IntParam(float val) = delete;
     55  MOZ_IMPLICIT IntParam(double val) = delete;
     56 
     57  T value;
     58 };
     59 
     60 template <class Units, class>
     61 struct PointTyped;
     62 template <class Units, class>
     63 struct SizeTyped;
     64 
     65 template <class Units>
     66 struct MOZ_EMPTY_BASES IntPointTyped
     67    : public BasePoint<int32_t, IntPointTyped<Units>, IntCoordTyped<Units> >,
     68      public Units {
     69  static_assert(IsPixel<Units>::value,
     70                "'Units' must be a coordinate system tag");
     71 
     72  typedef IntParam<int32_t> ToInt;
     73  typedef IntCoordTyped<Units> Coord;
     74  typedef BasePoint<int32_t, IntPointTyped<Units>, IntCoordTyped<Units> > Super;
     75 
     76  constexpr IntPointTyped() : Super() {
     77    static_assert(sizeof(IntPointTyped) == sizeof(int32_t) * 2,
     78                  "Would be unfortunate otherwise!");
     79  }
     80  constexpr IntPointTyped(ToInt aX, ToInt aY)
     81      : Super(Coord(aX.value), Coord(aY.value)) {}
     82 
     83  static IntPointTyped Round(float aX, float aY) {
     84    return IntPointTyped(int32_t(floorf(aX + 0.5f)),
     85                         int32_t(floorf(aY + 0.5f)));
     86  }
     87  static IntPointTyped Round(double aX, double aY) {
     88    return IntPointTyped(int32_t(floor(aX + 0.5)), int32_t(floor(aY + 0.5)));
     89  }
     90 
     91  static IntPointTyped Ceil(float aX, float aY) {
     92    return IntPointTyped(int32_t(ceilf(aX)), int32_t(ceilf(aY)));
     93  }
     94  static IntPointTyped Ceil(double aX, double aY) {
     95    return IntPointTyped(int32_t(ceil(aX)), int32_t(ceil(aY)));
     96  }
     97 
     98  static IntPointTyped Floor(float aX, float aY) {
     99    return IntPointTyped(int32_t(floorf(aX)), int32_t(floorf(aY)));
    100  }
    101  static IntPointTyped Floor(double aX, double aY) {
    102    return IntPointTyped(int32_t(floor(aX)), int32_t(floor(aY)));
    103  }
    104 
    105  template <typename F>
    106  static IntPointTyped Truncate(F aX, F aY) {
    107    return IntPointTyped(int32_t(aX), int32_t(aY));
    108  }
    109 
    110  template <typename F>
    111  static IntPointTyped Round(const PointTyped<Units, F>& aPoint);
    112  template <typename F>
    113  static IntPointTyped Ceil(const PointTyped<Units, F>& aPoint);
    114  template <typename F>
    115  static IntPointTyped Floor(const PointTyped<Units, F>& aPoint);
    116  template <typename F>
    117  static IntPointTyped Truncate(const PointTyped<Units, F>& aPoint);
    118 
    119  // XXX When all of the code is ported, the following functions to convert to
    120  // and from unknown types should be removed.
    121 
    122  static IntPointTyped FromUnknownPoint(
    123      const IntPointTyped<UnknownUnits>& aPoint) {
    124    return IntPointTyped<Units>(aPoint.x, aPoint.y);
    125  }
    126 
    127  IntPointTyped<UnknownUnits> ToUnknownPoint() const {
    128    return IntPointTyped<UnknownUnits>(this->x, this->y);
    129  }
    130 
    131  IntPointTyped RoundedToMultiple(int32_t aMultiplier) const {
    132    return {RoundToMultiple(this->x, aMultiplier),
    133            RoundToMultiple(this->y, aMultiplier)};
    134  }
    135 };
    136 typedef IntPointTyped<UnknownUnits> IntPoint;
    137 
    138 template <class Units, class F = Float>
    139 struct MOZ_EMPTY_BASES PointTyped
    140    : public BasePoint<F, PointTyped<Units, F>, CoordTyped<Units, F> >,
    141      public Units {
    142  static_assert(IsPixel<Units>::value,
    143                "'Units' must be a coordinate system tag");
    144 
    145  typedef CoordTyped<Units, F> Coord;
    146  typedef BasePoint<F, PointTyped<Units, F>, CoordTyped<Units, F> > Super;
    147 
    148  constexpr PointTyped() : Super() {
    149    static_assert(sizeof(PointTyped) == sizeof(F) * 2,
    150                  "Would be unfortunate otherwise!");
    151  }
    152  constexpr PointTyped(F aX, F aY) : Super(Coord(aX), Coord(aY)) {}
    153  // The mixed-type constructors (Float, Coord) and (Coord, Float) are needed to
    154  // avoid ambiguities because Coord is implicitly convertible to Float.
    155  constexpr PointTyped(F aX, Coord aY) : Super(Coord(aX), aY) {}
    156  constexpr PointTyped(Coord aX, F aY) : Super(aX, Coord(aY)) {}
    157  constexpr PointTyped(Coord aX, Coord aY) : Super(aX.value, aY.value) {}
    158  constexpr MOZ_IMPLICIT PointTyped(const IntPointTyped<Units>& point)
    159      : Super(F(point.x), F(point.y)) {}
    160 
    161  bool WithinEpsilonOf(const PointTyped<Units, F>& aPoint, F aEpsilon) const {
    162    return fabs(aPoint.x - this->x) < aEpsilon &&
    163           fabs(aPoint.y - this->y) < aEpsilon;
    164  }
    165 
    166  // XXX When all of the code is ported, the following functions to convert to
    167  // and from unknown types should be removed.
    168 
    169  static PointTyped<Units, F> FromUnknownPoint(
    170      const PointTyped<UnknownUnits, F>& aPoint) {
    171    return PointTyped<Units, F>(aPoint.x, aPoint.y);
    172  }
    173 
    174  PointTyped<UnknownUnits, F> ToUnknownPoint() const {
    175    return PointTyped<UnknownUnits, F>(this->x, this->y);
    176  }
    177 };
    178 typedef PointTyped<UnknownUnits> Point;
    179 typedef PointTyped<UnknownUnits, double> PointDouble;
    180 
    181 template <class Units, class F>
    182 IntPointTyped<Units> RoundedToInt(const PointTyped<Units, F>& aPoint) {
    183  return IntPointTyped<Units>::Round(aPoint.x, aPoint.y);
    184 }
    185 
    186 template <class Units, class F>
    187 IntPointTyped<Units> TruncatedToInt(const PointTyped<Units, F>& aPoint) {
    188  return IntPointTyped<Units>::Truncate(aPoint.x, aPoint.y);
    189 }
    190 
    191 template <class Units, class F = Float>
    192 struct Point3DTyped : public BasePoint3D<F, Point3DTyped<Units, F> > {
    193  static_assert(IsPixel<Units>::value,
    194                "'Units' must be a coordinate system tag");
    195 
    196  typedef BasePoint3D<F, Point3DTyped<Units, F> > Super;
    197 
    198  Point3DTyped() : Super() {
    199    static_assert(sizeof(Point3DTyped) == sizeof(F) * 3,
    200                  "Would be unfortunate otherwise!");
    201  }
    202  Point3DTyped(F aX, F aY, F aZ) : Super(aX, aY, aZ) {}
    203 
    204  // XXX When all of the code is ported, the following functions to convert to
    205  // and from unknown types should be removed.
    206 
    207  static Point3DTyped<Units, F> FromUnknownPoint(
    208      const Point3DTyped<UnknownUnits, F>& aPoint) {
    209    return Point3DTyped<Units, F>(aPoint.x, aPoint.y, aPoint.z);
    210  }
    211 
    212  Point3DTyped<UnknownUnits, F> ToUnknownPoint() const {
    213    return Point3DTyped<UnknownUnits, F>(this->x, this->y, this->z);
    214  }
    215 };
    216 typedef Point3DTyped<UnknownUnits> Point3D;
    217 typedef Point3DTyped<UnknownUnits, double> PointDouble3D;
    218 
    219 template <typename Units>
    220 template <typename F>
    221 IntPointTyped<Units> IntPointTyped<Units>::Round(
    222    const PointTyped<Units, F>& aPoint) {
    223  return IntPointTyped::Round(aPoint.x, aPoint.y);
    224 }
    225 
    226 template <typename Units>
    227 template <typename F>
    228 IntPointTyped<Units> IntPointTyped<Units>::Ceil(
    229    const PointTyped<Units, F>& aPoint) {
    230  return IntPointTyped::Ceil(aPoint.x, aPoint.y);
    231 }
    232 
    233 template <typename Units>
    234 template <typename F>
    235 IntPointTyped<Units> IntPointTyped<Units>::Floor(
    236    const PointTyped<Units, F>& aPoint) {
    237  return IntPointTyped::Floor(aPoint.x, aPoint.y);
    238 }
    239 
    240 template <typename Units>
    241 template <typename F>
    242 IntPointTyped<Units> IntPointTyped<Units>::Truncate(
    243    const PointTyped<Units, F>& aPoint) {
    244  return IntPointTyped::Truncate(aPoint.x, aPoint.y);
    245 }
    246 
    247 template <class Units, class F = Float>
    248 struct Point4DTyped : public BasePoint4D<F, Point4DTyped<Units, F> > {
    249  static_assert(IsPixel<Units>::value,
    250                "'Units' must be a coordinate system tag");
    251 
    252  typedef BasePoint4D<F, Point4DTyped<Units, F> > Super;
    253 
    254  Point4DTyped() : Super() {
    255    static_assert(sizeof(Point4DTyped) == sizeof(F) * 4,
    256                  "Would be unfortunate otherwise!");
    257  }
    258  Point4DTyped(F aX, F aY, F aZ, F aW) : Super(aX, aY, aZ, aW) {}
    259 
    260  explicit Point4DTyped(const Point3DTyped<Units, F>& aPoint)
    261      : Super(aPoint.x, aPoint.y, aPoint.z, 1) {}
    262 
    263  // XXX When all of the code is ported, the following functions to convert to
    264  // and from unknown types should be removed.
    265 
    266  static Point4DTyped<Units, F> FromUnknownPoint(
    267      const Point4DTyped<UnknownUnits, F>& aPoint) {
    268    return Point4DTyped<Units, F>(aPoint.x, aPoint.y, aPoint.z, aPoint.w);
    269  }
    270 
    271  Point4DTyped<UnknownUnits, F> ToUnknownPoint() const {
    272    return Point4DTyped<UnknownUnits, F>(this->x, this->y, this->z, this->w);
    273  }
    274 
    275  PointTyped<Units, F> As2DPoint() const {
    276    return PointTyped<Units, F>(this->x / this->w, this->y / this->w);
    277  }
    278 
    279  Point3DTyped<Units, F> As3DPoint() const {
    280    return Point3DTyped<Units, F>(this->x / this->w, this->y / this->w,
    281                                  this->z / this->w);
    282  }
    283 };
    284 typedef Point4DTyped<UnknownUnits> Point4D;
    285 typedef Point4DTyped<UnknownUnits, double> PointDouble4D;
    286 
    287 template <class Units>
    288 struct MOZ_EMPTY_BASES IntSizeTyped
    289    : public BaseSize<int32_t, IntSizeTyped<Units>, IntCoordTyped<Units> >,
    290      public Units {
    291  static_assert(IsPixel<Units>::value,
    292                "'Units' must be a coordinate system tag");
    293 
    294  typedef IntCoordTyped<Units> Coord;
    295  typedef BaseSize<int32_t, IntSizeTyped<Units>, Coord> Super;
    296 
    297  constexpr IntSizeTyped() : Super() {
    298    static_assert(sizeof(IntSizeTyped) == sizeof(int32_t) * 2,
    299                  "Would be unfortunate otherwise!");
    300  }
    301  constexpr IntSizeTyped(Coord aWidth, Coord aHeight)
    302      : Super(aWidth.value, aHeight.value) {}
    303 
    304  static IntSizeTyped Round(float aWidth, float aHeight) {
    305    return IntSizeTyped(int32_t(floorf(aWidth + 0.5)),
    306                        int32_t(floorf(aHeight + 0.5)));
    307  }
    308 
    309  static IntSizeTyped Truncate(float aWidth, float aHeight) {
    310    return IntSizeTyped(int32_t(aWidth), int32_t(aHeight));
    311  }
    312 
    313  static IntSizeTyped Ceil(float aWidth, float aHeight) {
    314    return IntSizeTyped(int32_t(ceil(aWidth)), int32_t(ceil(aHeight)));
    315  }
    316 
    317  static IntSizeTyped Floor(float aWidth, float aHeight) {
    318    return IntSizeTyped(int32_t(floorf(aWidth)), int32_t(floorf(aHeight)));
    319  }
    320 
    321  static IntSizeTyped Round(const SizeTyped<Units, float>& aSize);
    322  static IntSizeTyped Ceil(const SizeTyped<Units, float>& aSize);
    323  static IntSizeTyped Floor(const SizeTyped<Units, float>& aSize);
    324  static IntSizeTyped Truncate(const SizeTyped<Units, float>& aSize);
    325 
    326  IntSizeTyped TruncatedToMultiple(int32_t aMultiplier) const {
    327    if (aMultiplier == 1) {
    328      return *this;
    329    }
    330    return {RoundDownToMultiple(this->width, aMultiplier),
    331            RoundDownToMultiple(this->height, aMultiplier)};
    332  }
    333 
    334  IntSizeTyped CeiledToMultiple(int32_t aMultiplier) const {
    335    if (aMultiplier == 1) {
    336      return *this;
    337    }
    338    return {RoundUpToMultiple(this->width, aMultiplier),
    339            RoundUpToMultiple(this->height, aMultiplier)};
    340  }
    341 
    342  // XXX When all of the code is ported, the following functions to convert to
    343  // and from unknown types should be removed.
    344 
    345  static IntSizeTyped FromUnknownSize(const IntSizeTyped<UnknownUnits>& aSize) {
    346    return IntSizeTyped(aSize.width, aSize.height);
    347  }
    348 
    349  IntSizeTyped<UnknownUnits> ToUnknownSize() const {
    350    return IntSizeTyped<UnknownUnits>(this->width, this->height);
    351  }
    352 };
    353 typedef IntSizeTyped<UnknownUnits> IntSize;
    354 
    355 template <class Units, class F = Float>
    356 struct MOZ_EMPTY_BASES SizeTyped
    357    : public BaseSize<F, SizeTyped<Units, F>, CoordTyped<Units, F> >,
    358      public Units {
    359  static_assert(IsPixel<Units>::value,
    360                "'Units' must be a coordinate system tag");
    361 
    362  typedef CoordTyped<Units, F> Coord;
    363  typedef BaseSize<F, SizeTyped<Units, F>, Coord> Super;
    364 
    365  constexpr SizeTyped() : Super() {
    366    static_assert(sizeof(SizeTyped) == sizeof(F) * 2,
    367                  "Would be unfortunate otherwise!");
    368  }
    369  constexpr SizeTyped(Coord aWidth, Coord aHeight) : Super(aWidth, aHeight) {}
    370  explicit SizeTyped(const IntSizeTyped<Units>& size)
    371      : Super(F(size.width), F(size.height)) {}
    372 
    373  // XXX When all of the code is ported, the following functions to convert to
    374  // and from unknown types should be removed.
    375 
    376  static SizeTyped<Units, F> FromUnknownSize(
    377      const SizeTyped<UnknownUnits, F>& aSize) {
    378    return SizeTyped<Units, F>(aSize.width, aSize.height);
    379  }
    380 
    381  SizeTyped<UnknownUnits, F> ToUnknownSize() const {
    382    return SizeTyped<UnknownUnits, F>(this->width, this->height);
    383  }
    384 };
    385 typedef SizeTyped<UnknownUnits> Size;
    386 typedef SizeTyped<UnknownUnits, double> SizeDouble;
    387 
    388 template <class Units>
    389 IntSizeTyped<Units> RoundedToInt(const SizeTyped<Units>& aSize) {
    390  return IntSizeTyped<Units>(int32_t(floorf(aSize.width + 0.5f)),
    391                             int32_t(floorf(aSize.height + 0.5f)));
    392 }
    393 
    394 template <typename Units>
    395 IntSizeTyped<Units> IntSizeTyped<Units>::Round(
    396    const SizeTyped<Units, float>& aSize) {
    397  return IntSizeTyped::Round(aSize.width, aSize.height);
    398 }
    399 
    400 template <typename Units>
    401 IntSizeTyped<Units> IntSizeTyped<Units>::Ceil(
    402    const SizeTyped<Units, float>& aSize) {
    403  return IntSizeTyped::Ceil(aSize.width, aSize.height);
    404 }
    405 
    406 template <typename Units>
    407 IntSizeTyped<Units> IntSizeTyped<Units>::Floor(
    408    const SizeTyped<Units, float>& aSize) {
    409  return IntSizeTyped::Floor(aSize.width, aSize.height);
    410 }
    411 
    412 template <typename Units>
    413 IntSizeTyped<Units> IntSizeTyped<Units>::Truncate(
    414    const SizeTyped<Units, float>& aSize) {
    415  return IntSizeTyped::Truncate(aSize.width, aSize.height);
    416 }
    417 
    418 }  // namespace gfx
    419 }  // namespace mozilla
    420 
    421 #endif /* MOZILLA_GFX_POINT_H_ */