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_COORD_H_
7 : #define MOZILLA_GFX_COORD_H_
8 :
9 : #include "mozilla/Attributes.h"
10 : #include "mozilla/TypeTraits.h" // For IsSame
11 : #include "Types.h"
12 : #include "BaseCoord.h"
13 :
14 : #include <cmath>
15 :
16 : namespace mozilla {
17 :
18 : template <typename> struct IsPixel;
19 :
20 : namespace gfx {
21 :
22 : template <class units> struct IntCoordTyped;
23 : template <class units, class F = Float> struct CoordTyped;
24 :
25 : // CommonType<coord, primitive> is a metafunction that returns the type of the
26 : // result of an arithmetic operation on the underlying type of a strongly-typed
27 : // coordinate type 'coord', and a primitive type 'primitive'. C++ rules for
28 : // arithmetic conversions are designed to avoid losing information - for
29 : // example, the result of adding an int and a float is a float - and we want
30 : // the same behaviour when mixing our coordinate types with primitive types.
31 : // We get C++ to compute the desired result type using 'decltype'.
32 :
33 : template <class coord, class primitive>
34 : struct CommonType;
35 :
36 : template <class units, class primitive>
37 : struct CommonType<IntCoordTyped<units>, primitive> {
38 : typedef decltype(int32_t() + primitive()) type;
39 : };
40 :
41 : template <class units, class F, class primitive>
42 : struct CommonType<CoordTyped<units, F>, primitive> {
43 : typedef decltype(F() + primitive()) type;
44 : };
45 :
46 : // This is a base class that provides mixed-type operator overloads between
47 : // a strongly-typed Coord and a primitive value. It is needed to avoid
48 : // ambiguities at mixed-type call sites, because Coord classes are implicitly
49 : // convertible to their underlying value type. As we transition more of our code
50 : // to strongly-typed classes, we may be able to remove some or all of these
51 : // overloads.
52 :
53 : template <bool B, class coord, class primitive>
54 74094 : struct CoordOperatorsHelper {
55 : // Using SFINAE (Substitution Failure Is Not An Error) to suppress redundant
56 : // operators
57 : };
58 :
59 : template <class coord, class primitive>
60 259150 : struct CoordOperatorsHelper<true, coord, primitive> {
61 : friend bool operator==(coord aA, primitive aB) {
62 : return aA.value == aB;
63 : }
64 : friend bool operator==(primitive aA, coord aB) {
65 : return aA == aB.value;
66 : }
67 : friend bool operator!=(coord aA, primitive aB) {
68 : return aA.value != aB;
69 : }
70 : friend bool operator!=(primitive aA, coord aB) {
71 : return aA != aB.value;
72 : }
73 :
74 : typedef typename CommonType<coord, primitive>::type result_type;
75 :
76 : friend result_type operator+(coord aA, primitive aB) {
77 : return aA.value + aB;
78 : }
79 : friend result_type operator+(primitive aA, coord aB) {
80 : return aA + aB.value;
81 : }
82 : friend result_type operator-(coord aA, primitive aB) {
83 : return aA.value - aB;
84 : }
85 : friend result_type operator-(primitive aA, coord aB) {
86 : return aA - aB.value;
87 : }
88 0 : friend result_type operator*(coord aCoord, primitive aScale) {
89 0 : return aCoord.value * aScale;
90 : }
91 0 : friend result_type operator*(primitive aScale, coord aCoord) {
92 0 : return aScale * aCoord.value;
93 : }
94 0 : friend result_type operator/(coord aCoord, primitive aScale) {
95 0 : return aCoord.value / aScale;
96 : }
97 : // 'scale / coord' is intentionally omitted because it doesn't make sense.
98 : };
99 :
100 : // Note: 'IntCoordTyped<units>' and 'CoordTyped<units>' do not derive from
101 : // 'units' to work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=61959.
102 :
103 : template<class units>
104 : struct IntCoordTyped :
105 : public BaseCoord< int32_t, IntCoordTyped<units> >,
106 : public CoordOperatorsHelper< true, IntCoordTyped<units>, float >,
107 : public CoordOperatorsHelper< true, IntCoordTyped<units>, double > {
108 : static_assert(IsPixel<units>::value,
109 : "'units' must be a coordinate system tag");
110 :
111 : typedef BaseCoord< int32_t, IntCoordTyped<units> > Super;
112 :
113 : constexpr IntCoordTyped() : Super() {}
114 18434 : constexpr MOZ_IMPLICIT IntCoordTyped(int32_t aValue) : Super(aValue) {}
115 : };
116 :
117 : template<class units, class F>
118 : struct CoordTyped :
119 : public BaseCoord< F, CoordTyped<units, F> >,
120 : public CoordOperatorsHelper< !IsSame<F, int32_t>::value, CoordTyped<units, F>, int32_t >,
121 : public CoordOperatorsHelper< !IsSame<F, uint32_t>::value, CoordTyped<units, F>, uint32_t >,
122 : public CoordOperatorsHelper< !IsSame<F, double>::value, CoordTyped<units, F>, double >,
123 : public CoordOperatorsHelper< !IsSame<F, float>::value, CoordTyped<units, F>, float > {
124 : static_assert(IsPixel<units>::value,
125 : "'units' must be a coordinate system tag");
126 :
127 : typedef BaseCoord< F, CoordTyped<units, F> > Super;
128 :
129 1448 : constexpr CoordTyped() : Super() {}
130 72646 : constexpr MOZ_IMPLICIT CoordTyped(F aValue) : Super(aValue) {}
131 : explicit constexpr CoordTyped(const IntCoordTyped<units>& aCoord) : Super(F(aCoord.value)) {}
132 :
133 : void Round() {
134 : this->value = floor(this->value + 0.5);
135 : }
136 : void Truncate() {
137 : this->value = int32_t(this->value);
138 : }
139 :
140 : IntCoordTyped<units> Rounded() const {
141 : return IntCoordTyped<units>(int32_t(floor(this->value + 0.5)));
142 : }
143 : IntCoordTyped<units> Truncated() const {
144 : return IntCoordTyped<units>(int32_t(this->value));
145 : }
146 : };
147 :
148 : } // namespace gfx
149 : } // namespace mozilla
150 :
151 : #endif /* MOZILLA_GFX_COORD_H_ */
|