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