Bug 1732409 let fake:true getUserMedia() parameter override loopback prefs r=jib
[gecko.git] / dom / bindings / PrimitiveConversions.h
blob6e2960c5d39ddecb30103df37362952c07606929
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 file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 /**
8 * Conversions from jsval to primitive values
9 */
11 #ifndef mozilla_dom_PrimitiveConversions_h
12 #define mozilla_dom_PrimitiveConversions_h
14 #include <limits>
15 #include <math.h>
16 #include <stdint.h>
18 #include "js/Conversions.h"
19 #include "js/RootingAPI.h"
20 #include "mozilla/Assertions.h"
21 #include "mozilla/FloatingPoint.h"
22 #include "mozilla/dom/BindingCallContext.h"
24 namespace mozilla {
25 namespace dom {
27 template <typename T>
28 struct TypeName {};
30 template <>
31 struct TypeName<int8_t> {
32 static const char* value() { return "byte"; }
34 template <>
35 struct TypeName<uint8_t> {
36 static const char* value() { return "octet"; }
38 template <>
39 struct TypeName<int16_t> {
40 static const char* value() { return "short"; }
42 template <>
43 struct TypeName<uint16_t> {
44 static const char* value() { return "unsigned short"; }
46 template <>
47 struct TypeName<int32_t> {
48 static const char* value() { return "long"; }
50 template <>
51 struct TypeName<uint32_t> {
52 static const char* value() { return "unsigned long"; }
54 template <>
55 struct TypeName<int64_t> {
56 static const char* value() { return "long long"; }
58 template <>
59 struct TypeName<uint64_t> {
60 static const char* value() { return "unsigned long long"; }
63 enum ConversionBehavior { eDefault, eEnforceRange, eClamp };
65 template <typename T, ConversionBehavior B>
66 struct PrimitiveConversionTraits {};
68 template <typename T>
69 struct DisallowedConversion {
70 typedef int jstype;
71 typedef int intermediateType;
73 private:
74 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
75 const char* sourceDescription, jstype* retval) {
76 MOZ_CRASH("This should never be instantiated!");
80 struct PrimitiveConversionTraits_smallInt {
81 // The output of JS::ToInt32 is determined as follows:
82 // 1) The value is converted to a double
83 // 2) Anything that's not a finite double returns 0
84 // 3) The double is rounded towards zero to the nearest integer
85 // 4) The resulting integer is reduced mod 2^32. The output of this
86 // operation is an integer in the range [0, 2^32).
87 // 5) If the resulting number is >= 2^31, 2^32 is subtracted from it.
89 // The result of all this is a number in the range [-2^31, 2^31)
91 // WebIDL conversions for the 8-bit, 16-bit, and 32-bit integer types
92 // are defined in the same way, except that step 4 uses reduction mod
93 // 2^8 and 2^16 for the 8-bit and 16-bit types respectively, and step 5
94 // is only done for the signed types.
96 // C/C++ define integer conversion semantics to unsigned types as taking
97 // your input integer mod (1 + largest value representable in the
98 // unsigned type). Since 2^32 is zero mod 2^8, 2^16, and 2^32,
99 // converting to the unsigned int of the relevant width will correctly
100 // perform step 4; in particular, the 2^32 possibly subtracted in step 5
101 // will become 0.
103 // Once we have step 4 done, we're just going to assume 2s-complement
104 // representation and cast directly to the type we really want.
106 // So we can cast directly for all unsigned types and for int32_t; for
107 // the smaller-width signed types we need to cast through the
108 // corresponding unsigned type.
109 typedef int32_t jstype;
110 typedef int32_t intermediateType;
111 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
112 const char* sourceDescription, jstype* retval) {
113 return JS::ToInt32(cx, v, retval);
116 template <>
117 struct PrimitiveConversionTraits<int8_t, eDefault>
118 : PrimitiveConversionTraits_smallInt {
119 typedef uint8_t intermediateType;
121 template <>
122 struct PrimitiveConversionTraits<uint8_t, eDefault>
123 : PrimitiveConversionTraits_smallInt {};
124 template <>
125 struct PrimitiveConversionTraits<int16_t, eDefault>
126 : PrimitiveConversionTraits_smallInt {
127 typedef uint16_t intermediateType;
129 template <>
130 struct PrimitiveConversionTraits<uint16_t, eDefault>
131 : PrimitiveConversionTraits_smallInt {};
132 template <>
133 struct PrimitiveConversionTraits<int32_t, eDefault>
134 : PrimitiveConversionTraits_smallInt {};
135 template <>
136 struct PrimitiveConversionTraits<uint32_t, eDefault>
137 : PrimitiveConversionTraits_smallInt {};
139 template <>
140 struct PrimitiveConversionTraits<int64_t, eDefault> {
141 typedef int64_t jstype;
142 typedef int64_t intermediateType;
143 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
144 const char* sourceDescription, jstype* retval) {
145 return JS::ToInt64(cx, v, retval);
149 template <>
150 struct PrimitiveConversionTraits<uint64_t, eDefault> {
151 typedef uint64_t jstype;
152 typedef uint64_t intermediateType;
153 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
154 const char* sourceDescription, jstype* retval) {
155 return JS::ToUint64(cx, v, retval);
159 template <typename T>
160 struct PrimitiveConversionTraits_Limits {
161 static inline T min() { return std::numeric_limits<T>::min(); }
162 static inline T max() { return std::numeric_limits<T>::max(); }
165 template <>
166 struct PrimitiveConversionTraits_Limits<int64_t> {
167 static inline int64_t min() { return -(1LL << 53) + 1; }
168 static inline int64_t max() { return (1LL << 53) - 1; }
171 template <>
172 struct PrimitiveConversionTraits_Limits<uint64_t> {
173 static inline uint64_t min() { return 0; }
174 static inline uint64_t max() { return (1LL << 53) - 1; }
177 template <typename T, typename U,
178 bool (*Enforce)(U cx, const char* sourceDescription, const double& d,
179 T* retval)>
180 struct PrimitiveConversionTraits_ToCheckedIntHelper {
181 typedef T jstype;
182 typedef T intermediateType;
184 static inline bool converter(U cx, JS::Handle<JS::Value> v,
185 const char* sourceDescription, jstype* retval) {
186 double intermediate;
187 if (!JS::ToNumber(cx, v, &intermediate)) {
188 return false;
191 return Enforce(cx, sourceDescription, intermediate, retval);
195 template <typename T>
196 inline bool PrimitiveConversionTraits_EnforceRange(
197 BindingCallContext& cx, const char* sourceDescription, const double& d,
198 T* retval) {
199 static_assert(std::numeric_limits<T>::is_integer,
200 "This can only be applied to integers!");
202 if (!mozilla::IsFinite(d)) {
203 return cx.ThrowErrorMessage<MSG_ENFORCE_RANGE_NON_FINITE>(
204 sourceDescription, TypeName<T>::value());
207 bool neg = (d < 0);
208 double rounded = floor(neg ? -d : d);
209 rounded = neg ? -rounded : rounded;
210 if (rounded < PrimitiveConversionTraits_Limits<T>::min() ||
211 rounded > PrimitiveConversionTraits_Limits<T>::max()) {
212 return cx.ThrowErrorMessage<MSG_ENFORCE_RANGE_OUT_OF_RANGE>(
213 sourceDescription, TypeName<T>::value());
216 *retval = static_cast<T>(rounded);
217 return true;
220 template <typename T>
221 struct PrimitiveConversionTraits<T, eEnforceRange>
222 : public PrimitiveConversionTraits_ToCheckedIntHelper<
223 T, BindingCallContext&, PrimitiveConversionTraits_EnforceRange<T> > {
226 template <typename T>
227 inline bool PrimitiveConversionTraits_Clamp(JSContext* cx,
228 const char* sourceDescription,
229 const double& d, T* retval) {
230 static_assert(std::numeric_limits<T>::is_integer,
231 "This can only be applied to integers!");
233 if (mozilla::IsNaN(d)) {
234 *retval = 0;
235 return true;
237 if (d >= PrimitiveConversionTraits_Limits<T>::max()) {
238 *retval = PrimitiveConversionTraits_Limits<T>::max();
239 return true;
241 if (d <= PrimitiveConversionTraits_Limits<T>::min()) {
242 *retval = PrimitiveConversionTraits_Limits<T>::min();
243 return true;
246 MOZ_ASSERT(mozilla::IsFinite(d));
248 // Banker's rounding (round ties towards even).
249 // We move away from 0 by 0.5f and then truncate. That gets us the right
250 // answer for any starting value except plus or minus N.5. With a starting
251 // value of that form, we now have plus or minus N+1. If N is odd, this is
252 // the correct result. If N is even, plus or minus N is the correct result.
253 double toTruncate = (d < 0) ? d - 0.5 : d + 0.5;
255 T truncated = static_cast<T>(toTruncate);
257 if (truncated == toTruncate) {
259 * It was a tie (since moving away from 0 by 0.5 gave us the exact integer
260 * we want). Since we rounded away from 0, we either already have an even
261 * number or we have an odd number but the number we want is one closer to
262 * 0. So just unconditionally masking out the ones bit should do the trick
263 * to get us the value we want.
265 truncated &= ~1;
268 *retval = truncated;
269 return true;
272 template <typename T>
273 struct PrimitiveConversionTraits<T, eClamp>
274 : public PrimitiveConversionTraits_ToCheckedIntHelper<
275 T, JSContext*, PrimitiveConversionTraits_Clamp<T> > {};
277 template <ConversionBehavior B>
278 struct PrimitiveConversionTraits<bool, B> : public DisallowedConversion<bool> {
281 template <>
282 struct PrimitiveConversionTraits<bool, eDefault> {
283 typedef bool jstype;
284 typedef bool intermediateType;
285 static inline bool converter(JSContext* /* unused */, JS::Handle<JS::Value> v,
286 const char* sourceDescription, jstype* retval) {
287 *retval = JS::ToBoolean(v);
288 return true;
292 template <ConversionBehavior B>
293 struct PrimitiveConversionTraits<float, B>
294 : public DisallowedConversion<float> {};
296 template <ConversionBehavior B>
297 struct PrimitiveConversionTraits<double, B>
298 : public DisallowedConversion<double> {};
300 struct PrimitiveConversionTraits_float {
301 typedef double jstype;
302 typedef double intermediateType;
303 static inline bool converter(JSContext* cx, JS::Handle<JS::Value> v,
304 const char* sourceDescription, jstype* retval) {
305 return JS::ToNumber(cx, v, retval);
309 template <>
310 struct PrimitiveConversionTraits<float, eDefault>
311 : PrimitiveConversionTraits_float {};
312 template <>
313 struct PrimitiveConversionTraits<double, eDefault>
314 : PrimitiveConversionTraits_float {};
316 template <typename T, ConversionBehavior B, typename U>
317 bool ValueToPrimitive(U& cx, JS::Handle<JS::Value> v,
318 const char* sourceDescription, T* retval) {
319 typename PrimitiveConversionTraits<T, B>::jstype t;
320 if (!PrimitiveConversionTraits<T, B>::converter(cx, v, sourceDescription, &t))
321 return false;
323 *retval = static_cast<T>(
324 static_cast<typename PrimitiveConversionTraits<T, B>::intermediateType>(
325 t));
326 return true;
329 } // namespace dom
330 } // namespace mozilla
332 #endif /* mozilla_dom_PrimitiveConversions_h */