text: // Copyright 2020 The Chromium Authors. All rights reserved.
  // Use of this source code is governed by a BSD-style license that can be
  // found in the LICENSE file.
  
  #include "third_party/blink/renderer/bindings/core/v8/native_value_traits_impl.h"
  
  #include "third_party/blink/renderer/bindings/core/v8/custom/v8_custom_xpath_ns_resolver.h"
  #include "third_party/blink/renderer/bindings/core/v8/js_event_handler.h"
  #include "third_party/blink/renderer/bindings/core/v8/v8_array_buffer.h"
  #include "third_party/blink/renderer/bindings/core/v8/v8_array_buffer_view.h"
  #include "third_party/blink/renderer/bindings/core/v8/v8_big_int_64_array.h"
  #include "third_party/blink/renderer/bindings/core/v8/v8_big_uint_64_array.h"
  #include "third_party/blink/renderer/bindings/core/v8/v8_data_view.h"
  #include "third_party/blink/renderer/bindings/core/v8/v8_float32_array.h"
  #include "third_party/blink/renderer/bindings/core/v8/v8_float64_array.h"
  #include "third_party/blink/renderer/bindings/core/v8/v8_int16_array.h"
  #include "third_party/blink/renderer/bindings/core/v8/v8_int32_array.h"
  #include "third_party/blink/renderer/bindings/core/v8/v8_int8_array.h"
  #include "third_party/blink/renderer/bindings/core/v8/v8_uint16_array.h"
  #include "third_party/blink/renderer/bindings/core/v8/v8_uint32_array.h"
  #include "third_party/blink/renderer/bindings/core/v8/v8_uint8_array.h"
  #include "third_party/blink/renderer/bindings/core/v8/v8_uint8_clamped_array.h"
  #include "third_party/blink/renderer/bindings/core/v8/v8_xpath_ns_resolver.h"
  #include "third_party/blink/renderer/core/typed_arrays/typed_flexible_array_buffer_view.h"
  #include "third_party/blink/renderer/platform/bindings/exception_messages.h"
  
  namespace blink {
  
  namespace bindings {
  
  static_assert(static_cast<IntegerConversionConfiguration>(
                    IDLIntegerConvMode::kDefault) == kNormalConversion,
                "IDLIntegerConvMode::kDefault == kNormalConversion");
  static_assert(static_cast<IntegerConversionConfiguration>(
                    IDLIntegerConvMode::kClamp) == kClamp,
                "IDLIntegerConvMode::kClamp == kClamp");
  static_assert(static_cast<IntegerConversionConfiguration>(
                    IDLIntegerConvMode::kEnforceRange) == kEnforceRange,
                "IDLIntegerConvMode::kEnforceRange == kEnforceRange");
  
  void NativeValueTraitsInterfaceNotOfType(
      const WrapperTypeInfo* wrapper_type_info,
      ExceptionState& exception_state) {
    exception_state.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
        wrapper_type_info->interface_name));
  }
  
  void NativeValueTraitsInterfaceNotOfType(
      const WrapperTypeInfo* wrapper_type_info,
      int argument_index,
      ExceptionState& exception_state) {
    exception_state.ThrowTypeError(ExceptionMessages::ArgumentNotOfType(
        argument_index, wrapper_type_info->interface_name));
  }
  
  }  // namespace bindings
  
  // Buffer source types
  
  namespace {
  
  enum class IDLBufferSourceTypeConvMode {
    kDefault,
    kNullable,
  };
  
  template <
      typename T,
      typename V8T,
      IDLBufferSourceTypeConvMode mode = IDLBufferSourceTypeConvMode::kDefault>
  T* NativeValueTraitsBufferSourcePtrNativeValue(
      v8::Isolate* isolate,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    T* native_value = V8T::ToImplWithTypeCheck(isolate, value);
    if (native_value)
      return native_value;
  
    if (mode == IDLBufferSourceTypeConvMode::kNullable) {
      if (value->IsNullOrUndefined())
        return nullptr;
    }
  
    exception_state.ThrowTypeError(ExceptionMessages::FailedToConvertJSValue(
        V8T::GetWrapperTypeInfo()->interface_name));
    return nullptr;
  }
  
  template <
      typename T,
      typename V8T,
      IDLBufferSourceTypeConvMode mode = IDLBufferSourceTypeConvMode::kDefault>
  T* NativeValueTraitsBufferSourcePtrArgumentValue(
      v8::Isolate* isolate,
      int argument_index,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    T* native_value = V8T::ToImplWithTypeCheck(isolate, value);
    if (native_value)
      return native_value;
  
    if (mode == IDLBufferSourceTypeConvMode::kNullable) {
      if (value->IsNullOrUndefined())
        return nullptr;
    }
  
    exception_state.ThrowTypeError(ExceptionMessages::ArgumentNotOfType(
        argument_index, V8T::GetWrapperTypeInfo()->interface_name));
    return nullptr;
  }
  
  template <
      typename T,
      typename V8T,
      IDLBufferSourceTypeConvMode mode = IDLBufferSourceTypeConvMode::kDefault>
  NotShared<T> NativeValueTraitsBufferSourceNotSharedNativeValue(
      v8::Isolate* isolate,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    T* native_value = NativeValueTraitsBufferSourcePtrNativeValue<T, V8T, mode>(
        isolate, value, exception_state);
    if (!native_value)
      return NotShared<T>();
    if (native_value->IsShared()) {
      exception_state.ThrowTypeError(
          "The provided ArrayBufferView value must not be shared.");
      return NotShared<T>();
    }
    return NotShared<T>(native_value);
  }
  
  template <
      typename T,
      typename V8T,
      IDLBufferSourceTypeConvMode mode = IDLBufferSourceTypeConvMode::kDefault>
  NotShared<T> NativeValueTraitsBufferSourceNotSharedArgumentValue(
      v8::Isolate* isolate,
      int argument_index,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    T* native_value = NativeValueTraitsBufferSourcePtrArgumentValue<T, V8T, mode>(
        isolate, argument_index, value, exception_state);
    if (!native_value)
      return NotShared<T>();
    if (native_value->IsShared()) {
      exception_state.ThrowTypeError(
          "The provided ArrayBufferView value must not be shared.");
      return NotShared<T>();
    }
    return NotShared<T>(native_value);
  }
  
  template <
      typename T,
      typename V8T,
      IDLBufferSourceTypeConvMode mode = IDLBufferSourceTypeConvMode::kDefault>
  MaybeShared<T> NativeValueTraitsBufferSourceMaybeSharedNativeValue(
      v8::Isolate* isolate,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    return MaybeShared<T>(
        NativeValueTraitsBufferSourcePtrNativeValue<T, V8T, mode>(
            isolate, value, exception_state));
  }
  
  template <
      typename T,
      typename V8T,
      IDLBufferSourceTypeConvMode mode = IDLBufferSourceTypeConvMode::kDefault>
  MaybeShared<T> NativeValueTraitsBufferSourceMaybeSharedArgumentValue(
      v8::Isolate* isolate,
      int argument_index,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    return MaybeShared<T>(
        NativeValueTraitsBufferSourcePtrArgumentValue<T, V8T, mode>(
            isolate, argument_index, value, exception_state));
  }
  
  template <
      typename T,
      typename V8T,
      typename FLEXIBLE,
      IDLBufferSourceTypeConvMode mode = IDLBufferSourceTypeConvMode::kDefault>
  FLEXIBLE NativeValueTraitsBufferSourceFlexibleArgumentValue(
      v8::Isolate* isolate,
      int argument_index,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    if (V8T::HasInstance(isolate, value))
      return FLEXIBLE(value.As<v8::ArrayBufferView>());
  
    if (mode == IDLBufferSourceTypeConvMode::kNullable) {
      if (value->IsNullOrUndefined())
        return FLEXIBLE();
    }
  
    exception_state.ThrowTypeError(ExceptionMessages::ArgumentNotOfType(
        argument_index, V8T::GetWrapperTypeInfo()->interface_name));
    return FLEXIBLE();
  }
  
  }  // namespace
  
  DOMArrayBuffer* NativeValueTraits<DOMArrayBuffer>::NativeValue(
      v8::Isolate* isolate,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    return NativeValueTraitsBufferSourcePtrNativeValue<DOMArrayBuffer,
                                                       V8ArrayBuffer>(
        isolate, value, exception_state);
  }
  
  DOMArrayBuffer* NativeValueTraits<DOMArrayBuffer>::ArgumentValue(
      v8::Isolate* isolate,
      int argument_index,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    return NativeValueTraitsBufferSourcePtrArgumentValue<DOMArrayBuffer,
                                                         V8ArrayBuffer>(
        isolate, argument_index, value, exception_state);
  }
  
  DOMArrayBuffer* NativeValueTraits<IDLNullable<DOMArrayBuffer>>::NativeValue(
      v8::Isolate* isolate,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    return NativeValueTraitsBufferSourcePtrNativeValue<
        DOMArrayBuffer, V8ArrayBuffer, IDLBufferSourceTypeConvMode::kNullable>(
        isolate, value, exception_state);
  }
  
  DOMArrayBuffer* NativeValueTraits<IDLNullable<DOMArrayBuffer>>::ArgumentValue(
      v8::Isolate* isolate,
      int argument_index,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    return NativeValueTraitsBufferSourcePtrArgumentValue<
        DOMArrayBuffer, V8ArrayBuffer, IDLBufferSourceTypeConvMode::kNullable>(
        isolate, argument_index, value, exception_state);
  }
  
  #define DEFINE_NATIVE_VALUE_TRAITS_BUFFER_SOURCE_TYPE_NOT_SHARED(T, V8T)    \
    template <>                                                               \
    CORE_EXPORT NotShared<T> NativeValueTraits<NotShared<T>>::NativeValue(    \
        v8::Isolate* isolate, v8::Local<v8::Value> value,                     \
        ExceptionState& exception_state) {                                    \
      return NativeValueTraitsBufferSourceNotSharedNativeValue<T, V8T>(       \
          isolate, value, exception_state);                                   \
    }                                                                         \
    template <>                                                               \
    CORE_EXPORT NotShared<T> NativeValueTraits<NotShared<T>>::ArgumentValue(  \
        v8::Isolate* isolate, int argument_index, v8::Local<v8::Value> value, \
        ExceptionState& exception_state) {                                    \
      return NativeValueTraitsBufferSourceNotSharedArgumentValue<T, V8T>(     \
          isolate, argument_index, value, exception_state);                   \
    }                                                                         \
    template <>                                                               \
    CORE_EXPORT NotShared<T>                                                  \
    NativeValueTraits<IDLNullable<NotShared<T>>>::NativeValue(                \
        v8::Isolate* isolate, v8::Local<v8::Value> value,                     \
        ExceptionState& exception_state) {                                    \
      return NativeValueTraitsBufferSourceNotSharedNativeValue<               \
          T, V8T, IDLBufferSourceTypeConvMode::kNullable>(isolate, value,     \
                                                          exception_state);   \
    }                                                                         \
    template <>                                                               \
    CORE_EXPORT NotShared<T>                                                  \
    NativeValueTraits<IDLNullable<NotShared<T>>>::ArgumentValue(              \
        v8::Isolate* isolate, int argument_index, v8::Local<v8::Value> value, \
        ExceptionState& exception_state) {                                    \
      return NativeValueTraitsBufferSourceNotSharedArgumentValue<             \
          T, V8T, IDLBufferSourceTypeConvMode::kNullable>(                    \
          isolate, argument_index, value, exception_state);                   \
    }
  #define DEFINE_NATIVE_VALUE_TRAITS_BUFFER_SOURCE_TYPE_MAYBE_SHARED(T, V8T)     \
    template <>                                                                  \
    CORE_EXPORT MaybeShared<T> NativeValueTraits<MaybeShared<T>>::NativeValue(   \
        v8::Isolate* isolate, v8::Local<v8::Value> value,                        \
        ExceptionState& exception_state) {                                       \
      return NativeValueTraitsBufferSourceMaybeSharedNativeValue<T, V8T>(        \
          isolate, value, exception_state);                                      \
    }                                                                            \
    template <>                                                                  \
    CORE_EXPORT MaybeShared<T> NativeValueTraits<MaybeShared<T>>::ArgumentValue( \
        v8::Isolate* isolate, int argument_index, v8::Local<v8::Value> value,    \
        ExceptionState& exception_state) {                                       \
      return NativeValueTraitsBufferSourceMaybeSharedArgumentValue<T, V8T>(      \
          isolate, argument_index, value, exception_state);                      \
    }                                                                            \
    template <>                                                                  \
    CORE_EXPORT MaybeShared<T>                                                   \
    NativeValueTraits<IDLNullable<MaybeShared<T>>>::NativeValue(                 \
        v8::Isolate* isolate, v8::Local<v8::Value> value,                        \
        ExceptionState& exception_state) {                                       \
      return NativeValueTraitsBufferSourceMaybeSharedNativeValue<                \
          T, V8T, IDLBufferSourceTypeConvMode::kNullable>(isolate, value,        \
                                                          exception_state);      \
    }                                                                            \
    template <>                                                                  \
    CORE_EXPORT MaybeShared<T>                                                   \
    NativeValueTraits<IDLNullable<MaybeShared<T>>>::ArgumentValue(               \
        v8::Isolate* isolate, int argument_index, v8::Local<v8::Value> value,    \
        ExceptionState& exception_state) {                                       \
      return NativeValueTraitsBufferSourceMaybeSharedArgumentValue<              \
          T, V8T, IDLBufferSourceTypeConvMode::kNullable>(                       \
          isolate, argument_index, value, exception_state);                      \
    }
  #define DEFINE_NATIVE_VALUE_TRAITS_BUFFER_SOURCE_TYPE_FLEXIBLE(T, V8T,      \
                                                                 FLEXIBLE)    \
    template <>                                                               \
    CORE_EXPORT FLEXIBLE NativeValueTraits<FLEXIBLE>::ArgumentValue(          \
        v8::Isolate* isolate, int argument_index, v8::Local<v8::Value> value, \
        ExceptionState& exception_state) {                                    \
      return NativeValueTraitsBufferSourceFlexibleArgumentValue<T, V8T,       \
                                                                FLEXIBLE>(    \
          isolate, argument_index, value, exception_state);                   \
    }                                                                         \
    template <>                                                               \
    CORE_EXPORT FLEXIBLE                                                      \
    NativeValueTraits<IDLNullable<FLEXIBLE>>::ArgumentValue(                  \
        v8::Isolate* isolate, int argument_index, v8::Local<v8::Value> value, \
        ExceptionState& exception_state) {                                    \
      return NativeValueTraitsBufferSourceFlexibleArgumentValue<              \
          T, V8T, FLEXIBLE, IDLBufferSourceTypeConvMode::kNullable>(          \
          isolate, argument_index, value, exception_state);                   \
    }
  #define DEFINE_NATIVE_VALUE_TRAITS_TYPED_ARRAY(T)                           \
    DEFINE_NATIVE_VALUE_TRAITS_BUFFER_SOURCE_TYPE_NOT_SHARED(DOM##T, V8##T)   \
    DEFINE_NATIVE_VALUE_TRAITS_BUFFER_SOURCE_TYPE_MAYBE_SHARED(DOM##T, V8##T) \
    DEFINE_NATIVE_VALUE_TRAITS_BUFFER_SOURCE_TYPE_FLEXIBLE(DOM##T, V8##T,     \
                                                           Flexible##T)
  #define DEFINE_NATIVE_VALUE_TRAITS_DATA_VIEW(T)                           \
    DEFINE_NATIVE_VALUE_TRAITS_BUFFER_SOURCE_TYPE_NOT_SHARED(DOM##T, V8##T) \
    DEFINE_NATIVE_VALUE_TRAITS_BUFFER_SOURCE_TYPE_MAYBE_SHARED(DOM##T, V8##T)
  
  DEFINE_NATIVE_VALUE_TRAITS_TYPED_ARRAY(ArrayBufferView)
  DEFINE_NATIVE_VALUE_TRAITS_TYPED_ARRAY(Int8Array)
  DEFINE_NATIVE_VALUE_TRAITS_TYPED_ARRAY(Int16Array)
  DEFINE_NATIVE_VALUE_TRAITS_TYPED_ARRAY(Int32Array)
  DEFINE_NATIVE_VALUE_TRAITS_TYPED_ARRAY(Uint8Array)
  DEFINE_NATIVE_VALUE_TRAITS_TYPED_ARRAY(Uint8ClampedArray)
  DEFINE_NATIVE_VALUE_TRAITS_TYPED_ARRAY(Uint16Array)
  DEFINE_NATIVE_VALUE_TRAITS_TYPED_ARRAY(Uint32Array)
  DEFINE_NATIVE_VALUE_TRAITS_TYPED_ARRAY(BigInt64Array)
  DEFINE_NATIVE_VALUE_TRAITS_TYPED_ARRAY(BigUint64Array)
  DEFINE_NATIVE_VALUE_TRAITS_TYPED_ARRAY(Float32Array)
  DEFINE_NATIVE_VALUE_TRAITS_TYPED_ARRAY(Float64Array)
  DEFINE_NATIVE_VALUE_TRAITS_DATA_VIEW(DataView)
  
  // EventHandler
  EventListener* NativeValueTraits<IDLEventHandler>::NativeValue(
      v8::Isolate* isolate,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    return JSEventHandler::CreateOrNull(
        value, JSEventHandler::HandlerType::kEventHandler);
  }
  
  EventListener* NativeValueTraits<IDLOnBeforeUnloadEventHandler>::NativeValue(
      v8::Isolate* isolate,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    return JSEventHandler::CreateOrNull(
        value, JSEventHandler::HandlerType::kOnBeforeUnloadEventHandler);
  }
  
  EventListener* NativeValueTraits<IDLOnErrorEventHandler>::NativeValue(
      v8::Isolate* isolate,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    return JSEventHandler::CreateOrNull(
        value, JSEventHandler::HandlerType::kOnErrorEventHandler);
  }
  
  // Workaround https://crbug.com/345529
  XPathNSResolver* NativeValueTraits<XPathNSResolver>::NativeValue(
      v8::Isolate* isolate,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    if (XPathNSResolver* xpath_ns_resolver =
            V8XPathNSResolver::ToImplWithTypeCheck(isolate, value)) {
      return xpath_ns_resolver;
    }
    if (value->IsObject()) {
      ScriptState* script_state = ScriptState::From(isolate->GetCurrentContext());
      return MakeGarbageCollected<V8CustomXPathNSResolver>(
          script_state, value.As<v8::Object>());
    }
  
    exception_state.ThrowTypeError(
        ExceptionMessages::FailedToConvertJSValue("XPathNSResolver"));
    return nullptr;
  }
  
  XPathNSResolver* NativeValueTraits<XPathNSResolver>::ArgumentValue(
      v8::Isolate* isolate,
      int argument_index,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    if (XPathNSResolver* xpath_ns_resolver =
            V8XPathNSResolver::ToImplWithTypeCheck(isolate, value)) {
      return xpath_ns_resolver;
    }
    if (value->IsObject()) {
      ScriptState* script_state = ScriptState::From(isolate->GetCurrentContext());
      return MakeGarbageCollected<V8CustomXPathNSResolver>(
          script_state, value.As<v8::Object>());
    }
  
    exception_state.ThrowTypeError(
        ExceptionMessages::ArgumentNotOfType(argument_index, "XPathNSResolver"));
    return nullptr;
  }
  
  XPathNSResolver* NativeValueTraits<IDLNullable<XPathNSResolver>>::NativeValue(
      v8::Isolate* isolate,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    if (XPathNSResolver* xpath_ns_resolver =
            V8XPathNSResolver::ToImplWithTypeCheck(isolate, value)) {
      return xpath_ns_resolver;
    }
    if (value->IsObject()) {
      ScriptState* script_state = ScriptState::From(isolate->GetCurrentContext());
      return MakeGarbageCollected<V8CustomXPathNSResolver>(
          script_state, value.As<v8::Object>());
    }
    if (value->IsNullOrUndefined())
      return nullptr;
  
    exception_state.ThrowTypeError(
        ExceptionMessages::FailedToConvertJSValue("XPathNSResolver"));
    return nullptr;
  }
  
  XPathNSResolver* NativeValueTraits<IDLNullable<XPathNSResolver>>::ArgumentValue(
      v8::Isolate* isolate,
      int argument_index,
      v8::Local<v8::Value> value,
      ExceptionState& exception_state) {
    if (XPathNSResolver* xpath_ns_resolver =
            V8XPathNSResolver::ToImplWithTypeCheck(isolate, value)) {
      return xpath_ns_resolver;
    }
    if (value->IsObject()) {
      ScriptState* script_state = ScriptState::From(isolate->GetCurrentContext());
      return MakeGarbageCollected<V8CustomXPathNSResolver>(
          script_state, value.As<v8::Object>());
    }
    if (value->IsNullOrUndefined())
      return nullptr;
  
    exception_state.ThrowTypeError(
        ExceptionMessages::ArgumentNotOfType(argument_index, "XPathNSResolver"));
    return nullptr;
  }
  
  }  // namespace blink
  