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"
19 #include "mozilla/gfx/NumericTools.h"
22 #include <type_traits>
30 struct IsPixel
<gfx::UnknownUnits
> : std::true_type
{};
34 /// Use this for parameters of functions to allow implicit conversions to
35 /// integer types but not floating point types.
36 /// We use this wrapper to prevent IntSize and IntPoint's constructors to
37 /// take foating point values as parameters, and not require their constructors
38 /// to have implementations for each permutation of integer types.
41 constexpr MOZ_IMPLICIT
IntParam(char val
) : value(val
) {}
42 constexpr MOZ_IMPLICIT
IntParam(unsigned char val
) : value(val
) {}
43 constexpr MOZ_IMPLICIT
IntParam(short val
) : value(val
) {}
44 constexpr MOZ_IMPLICIT
IntParam(unsigned short val
) : value(val
) {}
45 constexpr MOZ_IMPLICIT
IntParam(int val
) : value(val
) {}
46 constexpr MOZ_IMPLICIT
IntParam(unsigned int val
) : value(val
) {}
47 constexpr MOZ_IMPLICIT
IntParam(long val
) : value(val
) {}
48 constexpr MOZ_IMPLICIT
IntParam(unsigned long val
) : value(val
) {}
49 constexpr MOZ_IMPLICIT
IntParam(long long val
) : value(val
) {}
50 constexpr MOZ_IMPLICIT
IntParam(unsigned long long val
) : value(val
) {}
51 template <typename Unit
>
52 constexpr MOZ_IMPLICIT
IntParam(IntCoordTyped
<Unit
> val
) : value(val
) {}
54 // Disable the evil ones!
55 MOZ_IMPLICIT
IntParam(float val
) = delete;
56 MOZ_IMPLICIT
IntParam(double val
) = delete;
61 template <class Units
, class>
63 template <class Units
, class>
66 template <class Units
>
67 struct MOZ_EMPTY_BASES IntPointTyped
68 : public BasePoint
<int32_t, IntPointTyped
<Units
>, IntCoordTyped
<Units
> >,
70 static_assert(IsPixel
<Units
>::value
,
71 "'Units' must be a coordinate system tag");
73 typedef IntParam
<int32_t> ToInt
;
74 typedef IntCoordTyped
<Units
> Coord
;
75 typedef BasePoint
<int32_t, IntPointTyped
<Units
>, IntCoordTyped
<Units
> > Super
;
77 constexpr IntPointTyped() : Super() {
78 static_assert(sizeof(IntPointTyped
) == sizeof(int32_t) * 2,
79 "Would be unfortunate otherwise!");
81 constexpr IntPointTyped(ToInt aX
, ToInt aY
)
82 : Super(Coord(aX
.value
), Coord(aY
.value
)) {}
84 static IntPointTyped
Round(float aX
, float aY
) {
85 return IntPointTyped(int32_t(floorf(aX
+ 0.5f
)),
86 int32_t(floorf(aY
+ 0.5f
)));
89 static IntPointTyped
Ceil(float aX
, float aY
) {
90 return IntPointTyped(int32_t(ceilf(aX
)), int32_t(ceilf(aY
)));
93 static IntPointTyped
Floor(float aX
, float aY
) {
94 return IntPointTyped(int32_t(floorf(aX
)), int32_t(floorf(aY
)));
97 static IntPointTyped
Truncate(float aX
, float aY
) {
98 return IntPointTyped(int32_t(aX
), int32_t(aY
));
101 static IntPointTyped
Round(const PointTyped
<Units
, float>& aPoint
);
102 static IntPointTyped
Ceil(const PointTyped
<Units
, float>& aPoint
);
103 static IntPointTyped
Floor(const PointTyped
<Units
, float>& aPoint
);
104 static IntPointTyped
Truncate(const PointTyped
<Units
, float>& aPoint
);
106 // XXX When all of the code is ported, the following functions to convert to
107 // and from unknown types should be removed.
109 static IntPointTyped
FromUnknownPoint(
110 const IntPointTyped
<UnknownUnits
>& aPoint
) {
111 return IntPointTyped
<Units
>(aPoint
.x
, aPoint
.y
);
114 IntPointTyped
<UnknownUnits
> ToUnknownPoint() const {
115 return IntPointTyped
<UnknownUnits
>(this->x
, this->y
);
118 IntPointTyped
RoundedToMultiple(int32_t aMultiplier
) const {
119 return {RoundToMultiple(this->x
, aMultiplier
),
120 RoundToMultiple(this->y
, aMultiplier
)};
123 typedef IntPointTyped
<UnknownUnits
> IntPoint
;
125 template <class Units
, class F
= Float
>
126 struct MOZ_EMPTY_BASES PointTyped
127 : public BasePoint
<F
, PointTyped
<Units
, F
>, CoordTyped
<Units
, F
> >,
129 static_assert(IsPixel
<Units
>::value
,
130 "'Units' must be a coordinate system tag");
132 typedef CoordTyped
<Units
, F
> Coord
;
133 typedef BasePoint
<F
, PointTyped
<Units
, F
>, CoordTyped
<Units
, F
> > Super
;
135 constexpr PointTyped() : Super() {
136 static_assert(sizeof(PointTyped
) == sizeof(F
) * 2,
137 "Would be unfortunate otherwise!");
139 constexpr PointTyped(F aX
, F aY
) : Super(Coord(aX
), Coord(aY
)) {}
140 // The mixed-type constructors (Float, Coord) and (Coord, Float) are needed to
141 // avoid ambiguities because Coord is implicitly convertible to Float.
142 constexpr PointTyped(F aX
, Coord aY
) : Super(Coord(aX
), aY
) {}
143 constexpr PointTyped(Coord aX
, F aY
) : Super(aX
, Coord(aY
)) {}
144 constexpr PointTyped(Coord aX
, Coord aY
) : Super(aX
.value
, aY
.value
) {}
145 constexpr MOZ_IMPLICIT
PointTyped(const IntPointTyped
<Units
>& point
)
146 : Super(F(point
.x
), F(point
.y
)) {}
148 bool WithinEpsilonOf(const PointTyped
<Units
, F
>& aPoint
, F aEpsilon
) const {
149 return fabs(aPoint
.x
- this->x
) < aEpsilon
&&
150 fabs(aPoint
.y
- this->y
) < aEpsilon
;
153 // XXX When all of the code is ported, the following functions to convert to
154 // and from unknown types should be removed.
156 static PointTyped
<Units
, F
> FromUnknownPoint(
157 const PointTyped
<UnknownUnits
, F
>& aPoint
) {
158 return PointTyped
<Units
, F
>(aPoint
.x
, aPoint
.y
);
161 PointTyped
<UnknownUnits
, F
> ToUnknownPoint() const {
162 return PointTyped
<UnknownUnits
, F
>(this->x
, this->y
);
165 typedef PointTyped
<UnknownUnits
> Point
;
166 typedef PointTyped
<UnknownUnits
, double> PointDouble
;
168 template <class Units
>
169 IntPointTyped
<Units
> RoundedToInt(const PointTyped
<Units
>& aPoint
) {
170 return IntPointTyped
<Units
>::Round(aPoint
.x
, aPoint
.y
);
173 template <class Units
>
174 IntPointTyped
<Units
> TruncatedToInt(const PointTyped
<Units
>& aPoint
) {
175 return IntPointTyped
<Units
>::Truncate(aPoint
.x
, aPoint
.y
);
178 template <class Units
, class F
= Float
>
179 struct Point3DTyped
: public BasePoint3D
<F
, Point3DTyped
<Units
, F
> > {
180 static_assert(IsPixel
<Units
>::value
,
181 "'Units' must be a coordinate system tag");
183 typedef BasePoint3D
<F
, Point3DTyped
<Units
, F
> > Super
;
185 Point3DTyped() : Super() {
186 static_assert(sizeof(Point3DTyped
) == sizeof(F
) * 3,
187 "Would be unfortunate otherwise!");
189 Point3DTyped(F aX
, F aY
, F aZ
) : Super(aX
, aY
, aZ
) {}
191 // XXX When all of the code is ported, the following functions to convert to
192 // and from unknown types should be removed.
194 static Point3DTyped
<Units
, F
> FromUnknownPoint(
195 const Point3DTyped
<UnknownUnits
, F
>& aPoint
) {
196 return Point3DTyped
<Units
, F
>(aPoint
.x
, aPoint
.y
, aPoint
.z
);
199 Point3DTyped
<UnknownUnits
, F
> ToUnknownPoint() const {
200 return Point3DTyped
<UnknownUnits
, F
>(this->x
, this->y
, this->z
);
203 typedef Point3DTyped
<UnknownUnits
> Point3D
;
204 typedef Point3DTyped
<UnknownUnits
, double> PointDouble3D
;
206 template <typename Units
>
207 IntPointTyped
<Units
> IntPointTyped
<Units
>::Round(
208 const PointTyped
<Units
, float>& aPoint
) {
209 return IntPointTyped::Round(aPoint
.x
, aPoint
.y
);
212 template <typename Units
>
213 IntPointTyped
<Units
> IntPointTyped
<Units
>::Ceil(
214 const PointTyped
<Units
, float>& aPoint
) {
215 return IntPointTyped::Ceil(aPoint
.x
, aPoint
.y
);
218 template <typename Units
>
219 IntPointTyped
<Units
> IntPointTyped
<Units
>::Floor(
220 const PointTyped
<Units
, float>& aPoint
) {
221 return IntPointTyped::Floor(aPoint
.x
, aPoint
.y
);
224 template <typename Units
>
225 IntPointTyped
<Units
> IntPointTyped
<Units
>::Truncate(
226 const PointTyped
<Units
, float>& aPoint
) {
227 return IntPointTyped::Truncate(aPoint
.x
, aPoint
.y
);
230 template <class Units
, class F
= Float
>
231 struct Point4DTyped
: public BasePoint4D
<F
, Point4DTyped
<Units
, F
> > {
232 static_assert(IsPixel
<Units
>::value
,
233 "'Units' must be a coordinate system tag");
235 typedef BasePoint4D
<F
, Point4DTyped
<Units
, F
> > Super
;
237 Point4DTyped() : Super() {
238 static_assert(sizeof(Point4DTyped
) == sizeof(F
) * 4,
239 "Would be unfortunate otherwise!");
241 Point4DTyped(F aX
, F aY
, F aZ
, F aW
) : Super(aX
, aY
, aZ
, aW
) {}
243 explicit Point4DTyped(const Point3DTyped
<Units
, F
>& aPoint
)
244 : Super(aPoint
.x
, aPoint
.y
, aPoint
.z
, 1) {}
246 // XXX When all of the code is ported, the following functions to convert to
247 // and from unknown types should be removed.
249 static Point4DTyped
<Units
, F
> FromUnknownPoint(
250 const Point4DTyped
<UnknownUnits
, F
>& aPoint
) {
251 return Point4DTyped
<Units
, F
>(aPoint
.x
, aPoint
.y
, aPoint
.z
, aPoint
.w
);
254 Point4DTyped
<UnknownUnits
, F
> ToUnknownPoint() const {
255 return Point4DTyped
<UnknownUnits
, F
>(this->x
, this->y
, this->z
, this->w
);
258 PointTyped
<Units
, F
> As2DPoint() const {
259 return PointTyped
<Units
, F
>(this->x
/ this->w
, this->y
/ this->w
);
262 Point3DTyped
<Units
, F
> As3DPoint() const {
263 return Point3DTyped
<Units
, F
>(this->x
/ this->w
, this->y
/ this->w
,
267 typedef Point4DTyped
<UnknownUnits
> Point4D
;
268 typedef Point4DTyped
<UnknownUnits
, double> PointDouble4D
;
270 template <class Units
>
271 struct MOZ_EMPTY_BASES IntSizeTyped
272 : public BaseSize
<int32_t, IntSizeTyped
<Units
>, IntCoordTyped
<Units
> >,
274 static_assert(IsPixel
<Units
>::value
,
275 "'Units' must be a coordinate system tag");
277 typedef IntCoordTyped
<Units
> Coord
;
278 typedef BaseSize
<int32_t, IntSizeTyped
<Units
>, Coord
> Super
;
280 constexpr IntSizeTyped() : Super() {
281 static_assert(sizeof(IntSizeTyped
) == sizeof(int32_t) * 2,
282 "Would be unfortunate otherwise!");
284 constexpr IntSizeTyped(Coord aWidth
, Coord aHeight
)
285 : Super(aWidth
.value
, aHeight
.value
) {}
287 static IntSizeTyped
Round(float aWidth
, float aHeight
) {
288 return IntSizeTyped(int32_t(floorf(aWidth
+ 0.5)),
289 int32_t(floorf(aHeight
+ 0.5)));
292 static IntSizeTyped
Truncate(float aWidth
, float aHeight
) {
293 return IntSizeTyped(int32_t(aWidth
), int32_t(aHeight
));
296 static IntSizeTyped
Ceil(float aWidth
, float aHeight
) {
297 return IntSizeTyped(int32_t(ceil(aWidth
)), int32_t(ceil(aHeight
)));
300 static IntSizeTyped
Floor(float aWidth
, float aHeight
) {
301 return IntSizeTyped(int32_t(floorf(aWidth
)), int32_t(floorf(aHeight
)));
304 static IntSizeTyped
Round(const SizeTyped
<Units
, float>& aSize
);
305 static IntSizeTyped
Ceil(const SizeTyped
<Units
, float>& aSize
);
306 static IntSizeTyped
Floor(const SizeTyped
<Units
, float>& aSize
);
307 static IntSizeTyped
Truncate(const SizeTyped
<Units
, float>& aSize
);
309 IntSizeTyped
TruncatedToMultiple(int32_t aMultiplier
) const {
310 if (aMultiplier
== 1) {
313 return {RoundDownToMultiple(this->width
, aMultiplier
),
314 RoundDownToMultiple(this->height
, aMultiplier
)};
317 IntSizeTyped
CeiledToMultiple(int32_t aMultiplier
) const {
318 if (aMultiplier
== 1) {
321 return {RoundUpToMultiple(this->width
, aMultiplier
),
322 RoundUpToMultiple(this->height
, aMultiplier
)};
325 // XXX When all of the code is ported, the following functions to convert to
326 // and from unknown types should be removed.
328 static IntSizeTyped
FromUnknownSize(const IntSizeTyped
<UnknownUnits
>& aSize
) {
329 return IntSizeTyped(aSize
.width
, aSize
.height
);
332 IntSizeTyped
<UnknownUnits
> ToUnknownSize() const {
333 return IntSizeTyped
<UnknownUnits
>(this->width
, this->height
);
336 typedef IntSizeTyped
<UnknownUnits
> IntSize
;
337 typedef Maybe
<IntSize
> MaybeIntSize
;
339 template <class Units
, class F
= Float
>
340 struct MOZ_EMPTY_BASES SizeTyped
341 : public BaseSize
<F
, SizeTyped
<Units
, F
>, CoordTyped
<Units
, F
> >,
343 static_assert(IsPixel
<Units
>::value
,
344 "'Units' must be a coordinate system tag");
346 typedef CoordTyped
<Units
, F
> Coord
;
347 typedef BaseSize
<F
, SizeTyped
<Units
, F
>, Coord
> Super
;
349 constexpr SizeTyped() : Super() {
350 static_assert(sizeof(SizeTyped
) == sizeof(F
) * 2,
351 "Would be unfortunate otherwise!");
353 constexpr SizeTyped(Coord aWidth
, Coord aHeight
) : Super(aWidth
, aHeight
) {}
354 explicit SizeTyped(const IntSizeTyped
<Units
>& size
)
355 : Super(F(size
.width
), F(size
.height
)) {}
357 // XXX When all of the code is ported, the following functions to convert to
358 // and from unknown types should be removed.
360 static SizeTyped
<Units
, F
> FromUnknownSize(
361 const SizeTyped
<UnknownUnits
, F
>& aSize
) {
362 return SizeTyped
<Units
, F
>(aSize
.width
, aSize
.height
);
365 SizeTyped
<UnknownUnits
, F
> ToUnknownSize() const {
366 return SizeTyped
<UnknownUnits
, F
>(this->width
, this->height
);
369 typedef SizeTyped
<UnknownUnits
> Size
;
370 typedef SizeTyped
<UnknownUnits
, double> SizeDouble
;
372 template <class Units
>
373 IntSizeTyped
<Units
> RoundedToInt(const SizeTyped
<Units
>& aSize
) {
374 return IntSizeTyped
<Units
>(int32_t(floorf(aSize
.width
+ 0.5f
)),
375 int32_t(floorf(aSize
.height
+ 0.5f
)));
378 template <typename Units
>
379 IntSizeTyped
<Units
> IntSizeTyped
<Units
>::Round(
380 const SizeTyped
<Units
, float>& aSize
) {
381 return IntSizeTyped::Round(aSize
.width
, aSize
.height
);
384 template <typename Units
>
385 IntSizeTyped
<Units
> IntSizeTyped
<Units
>::Ceil(
386 const SizeTyped
<Units
, float>& aSize
) {
387 return IntSizeTyped::Ceil(aSize
.width
, aSize
.height
);
390 template <typename Units
>
391 IntSizeTyped
<Units
> IntSizeTyped
<Units
>::Floor(
392 const SizeTyped
<Units
, float>& aSize
) {
393 return IntSizeTyped::Floor(aSize
.width
, aSize
.height
);
396 template <typename Units
>
397 IntSizeTyped
<Units
> IntSizeTyped
<Units
>::Truncate(
398 const SizeTyped
<Units
, float>& aSize
) {
399 return IntSizeTyped::Truncate(aSize
.width
, aSize
.height
);
403 } // namespace mozilla
405 #endif /* MOZILLA_GFX_POINT_H_ */