Bug 1890689 accumulate input in LargerReceiverBlockSizeThanDesiredBuffering GTest...
[gecko.git] / gfx / 2d / Coord.h
blob3b81482b4489ee102bd093b44c3ea11a6356dc37
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_COORD_H_
8 #define MOZILLA_GFX_COORD_H_
10 #include "mozilla/Attributes.h"
11 #include "mozilla/FloatingPoint.h"
12 #include "Types.h"
13 #include "BaseCoord.h"
15 #include <cmath>
16 #include <type_traits>
18 namespace mozilla {
20 namespace gfx {
22 template <class Units, class Rep = int32_t>
23 struct IntCoordTyped;
24 template <class Units, class F = Float>
25 struct CoordTyped;
27 } // namespace gfx
29 } // namespace mozilla
31 namespace std {
33 template <class Units, class Rep>
34 struct common_type<mozilla::gfx::IntCoordTyped<Units, Rep>, float> {
35 using type = mozilla::gfx::CoordTyped<Units, common_type_t<Rep, float>>;
38 template <class Units, class Rep>
39 struct common_type<mozilla::gfx::IntCoordTyped<Units, Rep>, double> {
40 using type = mozilla::gfx::CoordTyped<Units, common_type_t<Rep, double>>;
43 template <class Units, class Rep>
44 struct common_type<mozilla::gfx::IntCoordTyped<Units, Rep>, int32_t> {
45 using type = mozilla::gfx::IntCoordTyped<Units, common_type_t<Rep, int32_t>>;
48 template <class Units, class Rep>
49 struct common_type<mozilla::gfx::IntCoordTyped<Units, Rep>, uint32_t> {
50 using type = mozilla::gfx::IntCoordTyped<Units, common_type_t<Rep, uint32_t>>;
53 template <class Units, class F, class T>
54 struct common_type<mozilla::gfx::CoordTyped<Units, F>, T> {
55 using type = mozilla::gfx::CoordTyped<Units, common_type_t<F, T>>;
58 // With a few exceptions, we use CoordTyped values with a float representation.
59 // These are the types for which we have short typedefs like
60 // CSSCoord, and the types expected in most interfaces.
61 // So, for float inputs, keep the results as float even if the other
62 // operand is a double, accepting a slight loss of precision.
63 template <class Units, class T>
64 struct common_type<mozilla::gfx::CoordTyped<Units, float>, T> {
65 using type = mozilla::gfx::CoordTyped<Units, float>;
68 } // namespace std
70 namespace mozilla {
72 template <typename>
73 struct IsPixel;
75 namespace gfx {
77 // Should only be used to define generic typedefs like Coord, Point, etc.
78 struct UnknownUnits {};
80 // This is a base class that provides mixed-type operator overloads between
81 // a strongly-typed Coord and a Primitive value. It is needed to avoid
82 // ambiguities at mixed-type call sites, because Coord classes are implicitly
83 // convertible to their underlying value type. As we transition more of our code
84 // to strongly-typed classes, we may be able to remove some or all of these
85 // overloads.
87 template <bool Enable, class Coord, class Primitive>
88 struct CoordOperatorsHelper {
89 // Using SFINAE (Substitution Failure Is Not An Error) to suppress redundant
90 // operators
93 template <class Coord, class Primitive>
94 struct CoordOperatorsHelper<true, Coord, Primitive> {
95 friend bool operator==(Coord aA, Primitive aB) { return aA.value == aB; }
96 friend bool operator==(Primitive aA, Coord aB) { return aA == aB.value; }
97 friend bool operator!=(Coord aA, Primitive aB) { return aA.value != aB; }
98 friend bool operator!=(Primitive aA, Coord aB) { return aA != aB.value; }
100 friend auto operator+(Coord aA, Primitive aB) { return aA.value + aB; }
101 friend auto operator+(Primitive aA, Coord aB) { return aA + aB.value; }
102 friend auto operator-(Coord aA, Primitive aB) { return aA.value - aB; }
103 friend auto operator-(Primitive aA, Coord aB) { return aA - aB.value; }
104 friend auto operator*(Coord aCoord, Primitive aScale) {
105 return std::common_type_t<Coord, Primitive>(aCoord.value * aScale);
107 friend auto operator*(Primitive aScale, Coord aCoord) {
108 return aCoord * aScale;
110 friend auto operator/(Coord aCoord, Primitive aScale) {
111 return std::common_type_t<Coord, Primitive>(aCoord.value / aScale);
113 // 'scale / coord' is intentionally omitted because it doesn't make sense.
116 template <class Units, class Rep>
117 struct MOZ_EMPTY_BASES IntCoordTyped
118 : public BaseCoord<Rep, IntCoordTyped<Units, Rep>>,
119 public CoordOperatorsHelper<true, IntCoordTyped<Units, Rep>, float>,
120 public CoordOperatorsHelper<true, IntCoordTyped<Units, Rep>, double> {
121 static_assert(IsPixel<Units>::value,
122 "'Units' must be a coordinate system tag");
124 using Super = BaseCoord<Rep, IntCoordTyped<Units, Rep>>;
126 constexpr IntCoordTyped() : Super() {
127 static_assert(sizeof(IntCoordTyped) == sizeof(Rep),
128 "Would be unfortunate otherwise!");
130 template <class T, typename = typename std::enable_if_t<
131 std::is_integral_v<T> || std::is_enum_v<T>>>
132 constexpr MOZ_IMPLICIT IntCoordTyped(T aValue) : Super(aValue) {
133 static_assert(sizeof(IntCoordTyped) == sizeof(Rep),
134 "Would be unfortunate otherwise!");
138 template <class Units, class F>
139 struct MOZ_EMPTY_BASES CoordTyped
140 : public BaseCoord<F, CoordTyped<Units, F>>,
141 public CoordOperatorsHelper<!std::is_same_v<F, int32_t>,
142 CoordTyped<Units, F>, int32_t>,
143 public CoordOperatorsHelper<!std::is_same_v<F, uint32_t>,
144 CoordTyped<Units, F>, uint32_t>,
145 public CoordOperatorsHelper<!std::is_same_v<F, double>,
146 CoordTyped<Units, F>, double>,
147 public CoordOperatorsHelper<!std::is_same_v<F, float>,
148 CoordTyped<Units, F>, float> {
149 static_assert(IsPixel<Units>::value,
150 "'Units' must be a coordinate system tag");
152 using Super = BaseCoord<F, CoordTyped<Units, F>>;
154 constexpr CoordTyped() : Super() {
155 static_assert(sizeof(CoordTyped) == sizeof(F),
156 "Would be unfortunate otherwise!");
158 constexpr MOZ_IMPLICIT CoordTyped(F aValue) : Super(aValue) {
159 static_assert(sizeof(CoordTyped) == sizeof(F),
160 "Would be unfortunate otherwise!");
162 explicit constexpr CoordTyped(const IntCoordTyped<Units>& aCoord)
163 : Super(F(aCoord.value)) {
164 static_assert(sizeof(CoordTyped) == sizeof(F),
165 "Would be unfortunate otherwise!");
168 void Round() { this->value = floor(this->value + 0.5); }
169 void Truncate() { this->value = int32_t(this->value); }
171 IntCoordTyped<Units> Rounded() const {
172 return IntCoordTyped<Units>(int32_t(floor(this->value + 0.5)));
174 IntCoordTyped<Units> Truncated() const {
175 return IntCoordTyped<Units>(int32_t(this->value));
179 typedef CoordTyped<UnknownUnits> Coord;
181 } // namespace gfx
183 template <class Units, class F>
184 static MOZ_ALWAYS_INLINE bool FuzzyEqualsAdditive(
185 gfx::CoordTyped<Units, F> aValue1, gfx::CoordTyped<Units, F> aValue2,
186 gfx::CoordTyped<Units, F> aEpsilon =
187 detail::FuzzyEqualsEpsilon<F>::value()) {
188 return FuzzyEqualsAdditive(aValue1.value, aValue2.value, aEpsilon.value);
191 template <class Units, class F>
192 static MOZ_ALWAYS_INLINE bool FuzzyEqualsMultiplicative(
193 gfx::CoordTyped<Units, F> aValue1, gfx::CoordTyped<Units, F> aValue2,
194 gfx::CoordTyped<Units, F> aEpsilon =
195 detail::FuzzyEqualsEpsilon<F>::value()) {
196 return FuzzyEqualsMultiplicative(aValue1.value, aValue2.value,
197 aEpsilon.value);
200 } // namespace mozilla
202 #endif /* MOZILLA_GFX_COORD_H_ */