/* * Copyright (C) 2016 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF * THE POSSIBILITY OF SUCH DAMAGE. */ #pragma once #include "IDLTypes.h" #include "JSDOMConvertBase.h" #include "JSDOMExceptionHandling.h" #include #include namespace WebCore { // The following functions convert values to integers as per the WebIDL specification. // The conversion fails if the value cannot be converted to a number or, if EnforceRange is specified, // the value is outside the range of the destination integer type. template T convertToInteger(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT int8_t convertToInteger(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT uint8_t convertToInteger(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT int16_t convertToInteger(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT uint16_t convertToInteger(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT int32_t convertToInteger(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT uint32_t convertToInteger(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT int64_t convertToInteger(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT uint64_t convertToInteger(JSC::JSGlobalObject&, JSC::JSValue); template T convertToIntegerEnforceRange(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT int8_t convertToIntegerEnforceRange(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT uint8_t convertToIntegerEnforceRange(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT int16_t convertToIntegerEnforceRange(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT uint16_t convertToIntegerEnforceRange(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT int32_t convertToIntegerEnforceRange(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT uint32_t convertToIntegerEnforceRange(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT int64_t convertToIntegerEnforceRange(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT uint64_t convertToIntegerEnforceRange(JSC::JSGlobalObject&, JSC::JSValue); template T convertToIntegerClamp(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT int8_t convertToIntegerClamp(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT uint8_t convertToIntegerClamp(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT int16_t convertToIntegerClamp(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT uint16_t convertToIntegerClamp(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT int32_t convertToIntegerClamp(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT uint32_t convertToIntegerClamp(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT int64_t convertToIntegerClamp(JSC::JSGlobalObject&, JSC::JSValue); template<> WEBCORE_EXPORT uint64_t convertToIntegerClamp(JSC::JSGlobalObject&, JSC::JSValue); // MARK: - // MARK: Integer types template<> struct Converter : DefaultConverter { static int8_t convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value) { return convertToInteger(lexicalGlobalObject, value); } }; template<> struct JSConverter { using Type = typename IDLByte::ImplementationType; static constexpr bool needsState = false; static constexpr bool needsGlobalObject = false; static JSC::JSValue convert(Type value) { return JSC::jsNumber(value); } }; template<> struct Converter : DefaultConverter { static uint8_t convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value) { return convertToInteger(lexicalGlobalObject, value); } }; template<> struct JSConverter { using Type = typename IDLOctet::ImplementationType; static constexpr bool needsState = false; static constexpr bool needsGlobalObject = false; static JSC::JSValue convert(Type value) { return JSC::jsNumber(value); } }; template<> struct Converter : DefaultConverter { static int16_t convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value) { return convertToInteger(lexicalGlobalObject, value); } }; template<> struct JSConverter { using Type = typename IDLShort::ImplementationType; static constexpr bool needsState = false; static constexpr bool needsGlobalObject = false; static JSC::JSValue convert(Type value) { return JSC::jsNumber(value); } }; template<> struct Converter : DefaultConverter { static uint16_t convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value) { return convertToInteger(lexicalGlobalObject, value); } }; template<> struct JSConverter { using Type = typename IDLUnsignedShort::ImplementationType; static constexpr bool needsState = false; static constexpr bool needsGlobalObject = false; static JSC::JSValue convert(Type value) { return JSC::jsNumber(value); } }; template<> struct Converter : DefaultConverter { static inline int32_t convert(JSC::JSGlobalObject&, JSC::ThrowScope&, double number) { return JSC::toInt32(number); } static int32_t convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value) { return convertToInteger(lexicalGlobalObject, value); } }; template<> struct JSConverter { using Type = typename IDLLong::ImplementationType; static constexpr bool needsState = false; static constexpr bool needsGlobalObject = false; static JSC::JSValue convert(Type value) { return JSC::jsNumber(value); } }; template<> struct Converter : DefaultConverter { static uint32_t convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value) { return convertToInteger(lexicalGlobalObject, value); } }; template<> struct JSConverter { using Type = typename IDLUnsignedLong::ImplementationType; static constexpr bool needsState = false; static constexpr bool needsGlobalObject = false; static JSC::JSValue convert(Type value) { return JSC::jsNumber(value); } }; template<> struct Converter : DefaultConverter { static int64_t convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value) { return convertToInteger(lexicalGlobalObject, value); } }; template<> struct JSConverter { using Type = typename IDLLongLong::ImplementationType; static constexpr bool needsState = false; static constexpr bool needsGlobalObject = false; static JSC::JSValue convert(Type value) { return JSC::jsNumber(value); } }; template<> struct Converter : DefaultConverter { static uint64_t convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value) { return convertToInteger(lexicalGlobalObject, value); } }; template<> struct JSConverter { using Type = typename IDLUnsignedLongLong::ImplementationType; static constexpr bool needsState = false; static constexpr bool needsGlobalObject = false; static JSC::JSValue convert(Type value) { return JSC::jsNumber(value); } }; // MARK: - // MARK: Annotated Integer types template struct Converter> : DefaultConverter> { using ReturnType = typename IDLClampAdaptor::ImplementationType; static ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value) { return convertToIntegerClamp(lexicalGlobalObject, value); } }; template struct JSConverter> { using Type = typename IDLClampAdaptor::ImplementationType; static constexpr bool needsState = false; static constexpr bool needsGlobalObject = false; static JSC::JSValue convert(Type value) { return JSConverter::convert(value); } }; template struct Converter> : DefaultConverter> { using ReturnType = typename IDLEnforceRangeAdaptor::ImplementationType; static ReturnType convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value) { return convertToIntegerEnforceRange(lexicalGlobalObject, value); } }; template struct JSConverter> { using Type = typename IDLEnforceRangeAdaptor::ImplementationType; static constexpr bool needsState = false; static constexpr bool needsGlobalObject = false; static JSC::JSValue convert(Type value) { return JSConverter::convert(value); } }; // MARK: - // MARK: Floating point types template<> struct Converter : DefaultConverter { static inline float convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, double number) { if (UNLIKELY(!std::isfinite(number))) throwNonFiniteTypeError(lexicalGlobalObject, scope); return static_cast(number); } static float convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value) { JSC::VM& vm = JSC::getVM(&lexicalGlobalObject); auto scope = DECLARE_THROW_SCOPE(vm); double number = value.toNumber(&lexicalGlobalObject); RETURN_IF_EXCEPTION(scope, 0.0); if (UNLIKELY(number < std::numeric_limits::lowest() || number > std::numeric_limits::max())) throwTypeError(&lexicalGlobalObject, scope, "The provided value is outside the range of a float"_s); if (UNLIKELY(!std::isfinite(number))) throwNonFiniteTypeError(lexicalGlobalObject, scope); return static_cast(number); } }; template<> struct JSConverter { using Type = typename IDLFloat::ImplementationType; static constexpr bool needsState = false; static constexpr bool needsGlobalObject = false; static JSC::JSValue convert(Type value) { return JSC::jsNumber(value); } }; template<> struct Converter : DefaultConverter { static inline float convert(JSC::JSGlobalObject&, JSC::ThrowScope&, double number) { return static_cast(number); } static float convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value) { JSC::VM& vm = JSC::getVM(&lexicalGlobalObject); auto scope = DECLARE_THROW_SCOPE(vm); double number = value.toNumber(&lexicalGlobalObject); RETURN_IF_EXCEPTION(scope, 0.0); if (UNLIKELY(number < std::numeric_limits::lowest())) return -std::numeric_limits::infinity(); if (UNLIKELY(number > std::numeric_limits::max())) return std::numeric_limits::infinity(); return static_cast(number); } }; template<> struct JSConverter { using Type = typename IDLUnrestrictedFloat::ImplementationType; static constexpr bool needsState = false; static constexpr bool needsGlobalObject = false; static JSC::JSValue convert(Type value) { return JSC::jsNumber(value); } }; template<> struct Converter : DefaultConverter { static inline double convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::ThrowScope& scope, double number) { if (UNLIKELY(!std::isfinite(number))) throwNonFiniteTypeError(lexicalGlobalObject, scope); return number; } static double convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value) { JSC::VM& vm = JSC::getVM(&lexicalGlobalObject); auto scope = DECLARE_THROW_SCOPE(vm); double number = value.toNumber(&lexicalGlobalObject); RETURN_IF_EXCEPTION(scope, 0.0); if (UNLIKELY(!std::isfinite(number))) throwNonFiniteTypeError(lexicalGlobalObject, scope); return number; } }; template<> struct JSConverter { using Type = typename IDLDouble::ImplementationType; static constexpr bool needsState = false; static constexpr bool needsGlobalObject = false; static JSC::JSValue convert(Type value) { ASSERT(!std::isnan(value)); return JSC::jsNumber(value); } }; template<> struct Converter : DefaultConverter { static inline double convert(JSC::JSGlobalObject&, JSC::ThrowScope&, double number) { return number; } static double convert(JSC::JSGlobalObject& lexicalGlobalObject, JSC::JSValue value) { return value.toNumber(&lexicalGlobalObject); } }; template<> struct JSConverter { using Type = typename IDLUnrestrictedDouble::ImplementationType; static constexpr bool needsState = false; static constexpr bool needsGlobalObject = false; static JSC::JSValue convert(Type value) { return JSC::jsNumber(JSC::purifyNaN(value)); } // Add overload for MediaTime. static JSC::JSValue convert(const MediaTime& value) { return JSC::jsNumber(JSC::purifyNaN(value.toDouble())); } }; } // namespace WebCore