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 MOZILLA_GFX_POINT_H_
8 #define MOZILLA_GFX_POINT_H_
10 #include "mozilla/Attributes.h"
13 #include "BaseCoord.h"
14 #include "BasePoint.h"
15 #include "BasePoint3D.h"
16 #include "BasePoint4D.h"
18 #include "mozilla/Maybe.h"
21 #include <type_traits>
30 // This should only be used by the typedefs below.
31 struct UnknownUnits
{};
36 struct IsPixel
<gfx::UnknownUnits
> : std::true_type
{};
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.
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
) {}
60 // Disable the evil ones!
61 MOZ_IMPLICIT
IntParam(float val
) = delete;
62 MOZ_IMPLICIT
IntParam(double val
) = delete;
67 template <class units
, class>
69 template <class units
, class>
72 template <class units
>
74 : public BasePoint
<int32_t, IntPointTyped
<units
>, IntCoordTyped
<units
> >,
76 static_assert(IsPixel
<units
>::value
,
77 "'units' must be a coordinate system tag");
79 typedef IntParam
<int32_t> ToInt
;
80 typedef IntCoordTyped
<units
> Coord
;
81 typedef BasePoint
<int32_t, IntPointTyped
<units
>, IntCoordTyped
<units
> > Super
;
83 constexpr IntPointTyped() : Super() {}
84 constexpr IntPointTyped(ToInt aX
, ToInt aY
)
85 : Super(Coord(aX
.value
), Coord(aY
.value
)) {}
87 static IntPointTyped
<units
> Round(float aX
, float aY
) {
88 return IntPointTyped(int32_t(floorf(aX
+ 0.5)), int32_t(floorf(aY
+ 0.5)));
91 static IntPointTyped
<units
> Ceil(float aX
, float aY
) {
92 return IntPointTyped(int32_t(ceil(aX
)), int32_t(ceil(aY
)));
95 static IntPointTyped
<units
> Floor(float aX
, float aY
) {
96 return IntPointTyped(int32_t(floorf(aX
)), int32_t(floorf(aY
)));
99 static IntPointTyped
<units
> Truncate(float aX
, float aY
) {
100 return IntPointTyped(int32_t(aX
), int32_t(aY
));
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
);
108 // XXX When all of the code is ported, the following functions to convert to
109 // and from unknown types should be removed.
111 static IntPointTyped
<units
> FromUnknownPoint(
112 const IntPointTyped
<UnknownUnits
>& aPoint
) {
113 return IntPointTyped
<units
>(aPoint
.x
, aPoint
.y
);
116 IntPointTyped
<UnknownUnits
> ToUnknownPoint() const {
117 return IntPointTyped
<UnknownUnits
>(this->x
, this->y
);
120 typedef IntPointTyped
<UnknownUnits
> IntPoint
;
122 template <class units
, class F
= Float
>
124 : public BasePoint
<F
, PointTyped
<units
, F
>, CoordTyped
<units
, F
> >,
126 static_assert(IsPixel
<units
>::value
,
127 "'units' must be a coordinate system tag");
129 typedef CoordTyped
<units
, F
> Coord
;
130 typedef BasePoint
<F
, PointTyped
<units
, F
>, CoordTyped
<units
, F
> > Super
;
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
)) {}
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
;
147 // XXX When all of the code is ported, the following functions to convert to
148 // and from unknown types should be removed.
150 static PointTyped
<units
, F
> FromUnknownPoint(
151 const PointTyped
<UnknownUnits
, F
>& aPoint
) {
152 return PointTyped
<units
, F
>(aPoint
.x
, aPoint
.y
);
155 PointTyped
<UnknownUnits
, F
> ToUnknownPoint() const {
156 return PointTyped
<UnknownUnits
, F
>(this->x
, this->y
);
159 typedef PointTyped
<UnknownUnits
> Point
;
160 typedef PointTyped
<UnknownUnits
, double> PointDouble
;
162 template <class units
>
163 IntPointTyped
<units
> RoundedToInt(const PointTyped
<units
>& aPoint
) {
164 return IntPointTyped
<units
>::Round(aPoint
.x
, aPoint
.y
);
167 template <class units
>
168 IntPointTyped
<units
> TruncatedToInt(const PointTyped
<units
>& aPoint
) {
169 return IntPointTyped
<units
>::Truncate(aPoint
.x
, aPoint
.y
);
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");
177 typedef BasePoint3D
<F
, Point3DTyped
<units
, F
> > Super
;
179 Point3DTyped() : Super() {}
180 Point3DTyped(F aX
, F aY
, F aZ
) : Super(aX
, aY
, aZ
) {}
182 // XXX When all of the code is ported, the following functions to convert to
183 // and from unknown types should be removed.
185 static Point3DTyped
<units
, F
> FromUnknownPoint(
186 const Point3DTyped
<UnknownUnits
, F
>& aPoint
) {
187 return Point3DTyped
<units
, F
>(aPoint
.x
, aPoint
.y
, aPoint
.z
);
190 Point3DTyped
<UnknownUnits
, F
> ToUnknownPoint() const {
191 return Point3DTyped
<UnknownUnits
, F
>(this->x
, this->y
, this->z
);
194 typedef Point3DTyped
<UnknownUnits
> Point3D
;
195 typedef Point3DTyped
<UnknownUnits
, double> PointDouble3D
;
197 template <typename units
>
198 IntPointTyped
<units
> IntPointTyped
<units
>::Round(
199 const PointTyped
<units
, float>& aPoint
) {
200 return IntPointTyped::Round(aPoint
.x
, aPoint
.y
);
203 template <typename units
>
204 IntPointTyped
<units
> IntPointTyped
<units
>::Ceil(
205 const PointTyped
<units
, float>& aPoint
) {
206 return IntPointTyped::Ceil(aPoint
.x
, aPoint
.y
);
209 template <typename units
>
210 IntPointTyped
<units
> IntPointTyped
<units
>::Floor(
211 const PointTyped
<units
, float>& aPoint
) {
212 return IntPointTyped::Floor(aPoint
.x
, aPoint
.y
);
215 template <typename units
>
216 IntPointTyped
<units
> IntPointTyped
<units
>::Truncate(
217 const PointTyped
<units
, float>& aPoint
) {
218 return IntPointTyped::Truncate(aPoint
.x
, aPoint
.y
);
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");
226 typedef BasePoint4D
<F
, Point4DTyped
<units
, F
> > Super
;
228 Point4DTyped() : Super() {}
229 Point4DTyped(F aX
, F aY
, F aZ
, F aW
) : Super(aX
, aY
, aZ
, aW
) {}
231 explicit Point4DTyped(const Point3DTyped
<units
, F
>& aPoint
)
232 : Super(aPoint
.x
, aPoint
.y
, aPoint
.z
, 1) {}
234 // XXX When all of the code is ported, the following functions to convert to
235 // and from unknown types should be removed.
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
);
242 Point4DTyped
<UnknownUnits
, F
> ToUnknownPoint() const {
243 return Point4DTyped
<UnknownUnits
, F
>(this->x
, this->y
, this->z
, this->w
);
246 PointTyped
<units
, F
> As2DPoint() const {
247 return PointTyped
<units
, F
>(this->x
/ this->w
, this->y
/ this->w
);
250 Point3DTyped
<units
, F
> As3DPoint() const {
251 return Point3DTyped
<units
, F
>(this->x
/ this->w
, this->y
/ this->w
,
255 typedef Point4DTyped
<UnknownUnits
> Point4D
;
256 typedef Point4DTyped
<UnknownUnits
, double> PointDouble4D
;
258 template <class units
>
259 struct IntSizeTyped
: public BaseSize
<int32_t, IntSizeTyped
<units
> >,
261 static_assert(IsPixel
<units
>::value
,
262 "'units' must be a coordinate system tag");
264 typedef IntParam
<int32_t> ToInt
;
265 typedef BaseSize
<int32_t, IntSizeTyped
<units
> > Super
;
267 constexpr IntSizeTyped() : Super() {}
268 constexpr IntSizeTyped(ToInt aWidth
, ToInt aHeight
)
269 : Super(aWidth
.value
, aHeight
.value
) {}
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)));
276 static IntSizeTyped
<units
> Truncate(float aWidth
, float aHeight
) {
277 return IntSizeTyped(int32_t(aWidth
), int32_t(aHeight
));
280 static IntSizeTyped
<units
> Ceil(float aWidth
, float aHeight
) {
281 return IntSizeTyped(int32_t(ceil(aWidth
)), int32_t(ceil(aHeight
)));
284 static IntSizeTyped
<units
> Floor(float aWidth
, float aHeight
) {
285 return IntSizeTyped(int32_t(floorf(aWidth
)), int32_t(floorf(aHeight
)));
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
);
293 // XXX When all of the code is ported, the following functions to convert to
294 // and from unknown types should be removed.
296 static IntSizeTyped
<units
> FromUnknownSize(
297 const IntSizeTyped
<UnknownUnits
>& aSize
) {
298 return IntSizeTyped
<units
>(aSize
.width
, aSize
.height
);
301 IntSizeTyped
<UnknownUnits
> ToUnknownSize() const {
302 return IntSizeTyped
<UnknownUnits
>(this->width
, this->height
);
305 typedef IntSizeTyped
<UnknownUnits
> IntSize
;
306 typedef Maybe
<IntSize
> MaybeIntSize
;
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");
313 typedef BaseSize
<F
, SizeTyped
<units
, F
> > Super
;
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
)) {}
320 // XXX When all of the code is ported, the following functions to convert to
321 // and from unknown types should be removed.
323 static SizeTyped
<units
, F
> FromUnknownSize(
324 const SizeTyped
<UnknownUnits
, F
>& aSize
) {
325 return SizeTyped
<units
, F
>(aSize
.width
, aSize
.height
);
328 SizeTyped
<UnknownUnits
, F
> ToUnknownSize() const {
329 return SizeTyped
<UnknownUnits
, F
>(this->width
, this->height
);
332 typedef SizeTyped
<UnknownUnits
> Size
;
333 typedef SizeTyped
<UnknownUnits
, double> SizeDouble
;
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
)));
341 template <typename units
>
342 IntSizeTyped
<units
> IntSizeTyped
<units
>::Round(
343 const SizeTyped
<units
, float>& aSize
) {
344 return IntSizeTyped::Round(aSize
.width
, aSize
.height
);
347 template <typename units
>
348 IntSizeTyped
<units
> IntSizeTyped
<units
>::Ceil(
349 const SizeTyped
<units
, float>& aSize
) {
350 return IntSizeTyped::Ceil(aSize
.width
, aSize
.height
);
353 template <typename units
>
354 IntSizeTyped
<units
> IntSizeTyped
<units
>::Floor(
355 const SizeTyped
<units
, float>& aSize
) {
356 return IntSizeTyped::Floor(aSize
.width
, aSize
.height
);
359 template <typename units
>
360 IntSizeTyped
<units
> IntSizeTyped
<units
>::Truncate(
361 const SizeTyped
<units
, float>& aSize
) {
362 return IntSizeTyped::Truncate(aSize
.width
, aSize
.height
);
366 } // namespace mozilla
368 #endif /* MOZILLA_GFX_POINT_H_ */