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