1/*
2 * Copyright (C) 2016 Apple Inc. All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
6 * are met:
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 *
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
14 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23 * THE POSSIBILITY OF SUCH DAMAGE.
24 */
25
26#pragma once
27
28#include "IDLTypes.h"
29#include "JSDOMConvertBase.h"
30#include "JSDOMExceptionHandling.h"
31#include <JavaScriptCore/JSCJSValueInlines.h>
32#include <JavaScriptCore/PureNaN.h>
33
34namespace WebCore {
35
36// The following functions convert values to integers as per the WebIDL specification.
37// The conversion fails if the value cannot be converted to a number or, if EnforceRange is specified,
38// the value is outside the range of the destination integer type.
39
40template<typename T> T convertToInteger(JSC::ExecState&, JSC::JSValue);
41template<> WEBCORE_EXPORT int8_t convertToInteger<int8_t>(JSC::ExecState&, JSC::JSValue);
42template<> WEBCORE_EXPORT uint8_t convertToInteger<uint8_t>(JSC::ExecState&, JSC::JSValue);
43template<> WEBCORE_EXPORT int16_t convertToInteger<int16_t>(JSC::ExecState&, JSC::JSValue);
44template<> WEBCORE_EXPORT uint16_t convertToInteger<uint16_t>(JSC::ExecState&, JSC::JSValue);
45template<> WEBCORE_EXPORT int32_t convertToInteger<int32_t>(JSC::ExecState&, JSC::JSValue);
46template<> WEBCORE_EXPORT uint32_t convertToInteger<uint32_t>(JSC::ExecState&, JSC::JSValue);
47template<> WEBCORE_EXPORT int64_t convertToInteger<int64_t>(JSC::ExecState&, JSC::JSValue);
48template<> WEBCORE_EXPORT uint64_t convertToInteger<uint64_t>(JSC::ExecState&, JSC::JSValue);
49
50template<typename T> T convertToIntegerEnforceRange(JSC::ExecState&, JSC::JSValue);
51template<> WEBCORE_EXPORT int8_t convertToIntegerEnforceRange<int8_t>(JSC::ExecState&, JSC::JSValue);
52template<> WEBCORE_EXPORT uint8_t convertToIntegerEnforceRange<uint8_t>(JSC::ExecState&, JSC::JSValue);
53template<> WEBCORE_EXPORT int16_t convertToIntegerEnforceRange<int16_t>(JSC::ExecState&, JSC::JSValue);
54template<> WEBCORE_EXPORT uint16_t convertToIntegerEnforceRange<uint16_t>(JSC::ExecState&, JSC::JSValue);
55template<> WEBCORE_EXPORT int32_t convertToIntegerEnforceRange<int32_t>(JSC::ExecState&, JSC::JSValue);
56template<> WEBCORE_EXPORT uint32_t convertToIntegerEnforceRange<uint32_t>(JSC::ExecState&, JSC::JSValue);
57template<> WEBCORE_EXPORT int64_t convertToIntegerEnforceRange<int64_t>(JSC::ExecState&, JSC::JSValue);
58template<> WEBCORE_EXPORT uint64_t convertToIntegerEnforceRange<uint64_t>(JSC::ExecState&, JSC::JSValue);
59
60template<typename T> T convertToIntegerClamp(JSC::ExecState&, JSC::JSValue);
61template<> WEBCORE_EXPORT int8_t convertToIntegerClamp<int8_t>(JSC::ExecState&, JSC::JSValue);
62template<> WEBCORE_EXPORT uint8_t convertToIntegerClamp<uint8_t>(JSC::ExecState&, JSC::JSValue);
63template<> WEBCORE_EXPORT int16_t convertToIntegerClamp<int16_t>(JSC::ExecState&, JSC::JSValue);
64template<> WEBCORE_EXPORT uint16_t convertToIntegerClamp<uint16_t>(JSC::ExecState&, JSC::JSValue);
65template<> WEBCORE_EXPORT int32_t convertToIntegerClamp<int32_t>(JSC::ExecState&, JSC::JSValue);
66template<> WEBCORE_EXPORT uint32_t convertToIntegerClamp<uint32_t>(JSC::ExecState&, JSC::JSValue);
67template<> WEBCORE_EXPORT int64_t convertToIntegerClamp<int64_t>(JSC::ExecState&, JSC::JSValue);
68template<> WEBCORE_EXPORT uint64_t convertToIntegerClamp<uint64_t>(JSC::ExecState&, JSC::JSValue);
69
70// MARK: -
71// MARK: Integer types
72
73template<> struct Converter<IDLByte> : DefaultConverter<IDLByte> {
74 static int8_t convert(JSC::ExecState& state, JSC::JSValue value)
75 {
76 return convertToInteger<int8_t>(state, value);
77 }
78};
79
80template<> struct JSConverter<IDLByte> {
81 using Type = typename IDLByte::ImplementationType;
82
83 static constexpr bool needsState = false;
84 static constexpr bool needsGlobalObject = false;
85
86 static JSC::JSValue convert(Type value)
87 {
88 return JSC::jsNumber(value);
89 }
90};
91
92template<> struct Converter<IDLOctet> : DefaultConverter<IDLOctet> {
93 static uint8_t convert(JSC::ExecState& state, JSC::JSValue value)
94 {
95 return convertToInteger<uint8_t>(state, value);
96 }
97};
98
99template<> struct JSConverter<IDLOctet> {
100 using Type = typename IDLOctet::ImplementationType;
101
102 static constexpr bool needsState = false;
103 static constexpr bool needsGlobalObject = false;
104
105 static JSC::JSValue convert(Type value)
106 {
107 return JSC::jsNumber(value);
108 }
109};
110
111template<> struct Converter<IDLShort> : DefaultConverter<IDLShort> {
112 static int16_t convert(JSC::ExecState& state, JSC::JSValue value)
113 {
114 return convertToInteger<int16_t>(state, value);
115 }
116};
117
118template<> struct JSConverter<IDLShort> {
119 using Type = typename IDLShort::ImplementationType;
120
121 static constexpr bool needsState = false;
122 static constexpr bool needsGlobalObject = false;
123
124 static JSC::JSValue convert(Type value)
125 {
126 return JSC::jsNumber(value);
127 }
128};
129
130template<> struct Converter<IDLUnsignedShort> : DefaultConverter<IDLUnsignedShort> {
131 static uint16_t convert(JSC::ExecState& state, JSC::JSValue value)
132 {
133 return convertToInteger<uint16_t>(state, value);
134 }
135};
136
137template<> struct JSConverter<IDLUnsignedShort> {
138 using Type = typename IDLUnsignedShort::ImplementationType;
139
140 static constexpr bool needsState = false;
141 static constexpr bool needsGlobalObject = false;
142
143 static JSC::JSValue convert(Type value)
144 {
145 return JSC::jsNumber(value);
146 }
147};
148
149template<> struct Converter<IDLLong> : DefaultConverter<IDLLong> {
150 static inline int32_t convert(JSC::ExecState&, JSC::ThrowScope&, double number)
151 {
152 return JSC::toInt32(number);
153 }
154
155 static int32_t convert(JSC::ExecState& state, JSC::JSValue value)
156 {
157 return convertToInteger<int32_t>(state, value);
158 }
159};
160
161template<> struct JSConverter<IDLLong> {
162 using Type = typename IDLLong::ImplementationType;
163
164 static constexpr bool needsState = false;
165 static constexpr bool needsGlobalObject = false;
166
167 static JSC::JSValue convert(Type value)
168 {
169 return JSC::jsNumber(value);
170 }
171};
172
173template<> struct Converter<IDLUnsignedLong> : DefaultConverter<IDLUnsignedLong> {
174 static uint32_t convert(JSC::ExecState& state, JSC::JSValue value)
175 {
176 return convertToInteger<uint32_t>(state, value);
177 }
178};
179
180template<> struct JSConverter<IDLUnsignedLong> {
181 using Type = typename IDLUnsignedLong::ImplementationType;
182
183 static constexpr bool needsState = false;
184 static constexpr bool needsGlobalObject = false;
185
186 static JSC::JSValue convert(Type value)
187 {
188 return JSC::jsNumber(value);
189 }
190};
191
192template<> struct Converter<IDLLongLong> : DefaultConverter<IDLLongLong> {
193 static int64_t convert(JSC::ExecState& state, JSC::JSValue value)
194 {
195 return convertToInteger<int64_t>(state, value);
196 }
197};
198
199template<> struct JSConverter<IDLLongLong> {
200 using Type = typename IDLLongLong::ImplementationType;
201
202 static constexpr bool needsState = false;
203 static constexpr bool needsGlobalObject = false;
204
205 static JSC::JSValue convert(Type value)
206 {
207 return JSC::jsNumber(value);
208 }
209};
210
211template<> struct Converter<IDLUnsignedLongLong> : DefaultConverter<IDLUnsignedLongLong> {
212 static uint64_t convert(JSC::ExecState& state, JSC::JSValue value)
213 {
214 return convertToInteger<uint64_t>(state, value);
215 }
216};
217
218template<> struct JSConverter<IDLUnsignedLongLong> {
219 using Type = typename IDLUnsignedLongLong::ImplementationType;
220
221 static constexpr bool needsState = false;
222 static constexpr bool needsGlobalObject = false;
223
224 static JSC::JSValue convert(Type value)
225 {
226 return JSC::jsNumber(value);
227 }
228};
229
230// MARK: -
231// MARK: Annotated Integer types
232
233template<typename T> struct Converter<IDLClampAdaptor<T>> : DefaultConverter<IDLClampAdaptor<T>> {
234 using ReturnType = typename IDLClampAdaptor<T>::ImplementationType;
235
236 static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
237 {
238 return convertToIntegerClamp<ReturnType>(state, value);
239 }
240};
241
242template<typename T> struct JSConverter<IDLClampAdaptor<T>> {
243 using Type = typename IDLClampAdaptor<T>::ImplementationType;
244
245 static constexpr bool needsState = false;
246 static constexpr bool needsGlobalObject = false;
247
248 static JSC::JSValue convert(Type value)
249 {
250 return JSConverter<T>::convert(value);
251 }
252};
253
254
255template<typename T> struct Converter<IDLEnforceRangeAdaptor<T>> : DefaultConverter<IDLEnforceRangeAdaptor<T>> {
256 using ReturnType = typename IDLEnforceRangeAdaptor<T>::ImplementationType;
257
258 static ReturnType convert(JSC::ExecState& state, JSC::JSValue value)
259 {
260 return convertToIntegerEnforceRange<ReturnType>(state, value);
261 }
262};
263
264template<typename T> struct JSConverter<IDLEnforceRangeAdaptor<T>> {
265 using Type = typename IDLEnforceRangeAdaptor<T>::ImplementationType;
266
267 static constexpr bool needsState = false;
268 static constexpr bool needsGlobalObject = false;
269
270 static JSC::JSValue convert(Type value)
271 {
272 return JSConverter<T>::convert(value);
273 }
274};
275
276
277// MARK: -
278// MARK: Floating point types
279
280template<> struct Converter<IDLFloat> : DefaultConverter<IDLFloat> {
281
282 static inline float convert(JSC::ExecState& state, JSC::ThrowScope& scope, double number)
283 {
284 if (UNLIKELY(!std::isfinite(number)))
285 throwNonFiniteTypeError(state, scope);
286 return static_cast<float>(number);
287 }
288
289 static float convert(JSC::ExecState& state, JSC::JSValue value)
290 {
291 JSC::VM& vm = state.vm();
292 auto scope = DECLARE_THROW_SCOPE(vm);
293 double number = value.toNumber(&state);
294 if (UNLIKELY(!std::isfinite(number)))
295 throwNonFiniteTypeError(state, scope);
296 return static_cast<float>(number);
297 }
298};
299
300template<> struct JSConverter<IDLFloat> {
301 using Type = typename IDLFloat::ImplementationType;
302
303 static constexpr bool needsState = false;
304 static constexpr bool needsGlobalObject = false;
305
306 static JSC::JSValue convert(Type value)
307 {
308 return JSC::jsNumber(value);
309 }
310};
311
312template<> struct Converter<IDLUnrestrictedFloat> : DefaultConverter<IDLUnrestrictedFloat> {
313 static inline float convert(JSC::ExecState&, JSC::ThrowScope&, double number)
314 {
315 return static_cast<float>(number);
316 }
317
318 static float convert(JSC::ExecState& state, JSC::JSValue value)
319 {
320 return static_cast<float>(value.toNumber(&state));
321 }
322};
323
324template<> struct JSConverter<IDLUnrestrictedFloat> {
325 using Type = typename IDLUnrestrictedFloat::ImplementationType;
326
327 static constexpr bool needsState = false;
328 static constexpr bool needsGlobalObject = false;
329
330 static JSC::JSValue convert(Type value)
331 {
332 return JSC::jsNumber(value);
333 }
334};
335
336template<> struct Converter<IDLDouble> : DefaultConverter<IDLDouble> {
337 static inline double convert(JSC::ExecState& state, JSC::ThrowScope& scope, double number)
338 {
339 if (UNLIKELY(!std::isfinite(number)))
340 throwNonFiniteTypeError(state, scope);
341 return number;
342 }
343
344 static double convert(JSC::ExecState& state, JSC::JSValue value)
345 {
346 JSC::VM& vm = state.vm();
347 auto scope = DECLARE_THROW_SCOPE(vm);
348 double number = value.toNumber(&state);
349 if (UNLIKELY(!std::isfinite(number)))
350 throwNonFiniteTypeError(state, scope);
351 return number;
352 }
353};
354
355template<> struct JSConverter<IDLDouble> {
356 using Type = typename IDLDouble::ImplementationType;
357
358 static constexpr bool needsState = false;
359 static constexpr bool needsGlobalObject = false;
360
361 static JSC::JSValue convert(Type value)
362 {
363 ASSERT(!std::isnan(value));
364 return JSC::jsNumber(value);
365 }
366};
367
368template<> struct Converter<IDLUnrestrictedDouble> : DefaultConverter<IDLUnrestrictedDouble> {
369 static inline double convert(JSC::ExecState&, JSC::ThrowScope&, double number)
370 {
371 return number;
372 }
373
374 static double convert(JSC::ExecState& state, JSC::JSValue value)
375 {
376 return value.toNumber(&state);
377 }
378};
379
380template<> struct JSConverter<IDLUnrestrictedDouble> {
381 using Type = typename IDLUnrestrictedDouble::ImplementationType;
382
383 static constexpr bool needsState = false;
384 static constexpr bool needsGlobalObject = false;
385
386 static JSC::JSValue convert(Type value)
387 {
388 return JSC::jsNumber(JSC::purifyNaN(value));
389 }
390
391 // Add overload for MediaTime.
392 static JSC::JSValue convert(const MediaTime& value)
393 {
394 return JSC::jsNumber(JSC::purifyNaN(value.toDouble()));
395 }
396};
397
398} // namespace WebCore
399