Index: Source/bindings/core/v8/PropertyBag.h |
diff --git a/Source/bindings/core/v8/PropertyBag.h b/Source/bindings/core/v8/PropertyBag.h |
new file mode 100644 |
index 0000000000000000000000000000000000000000..80750e2976ec872e25c3dd5f7ff096b8c61133e5 |
--- /dev/null |
+++ b/Source/bindings/core/v8/PropertyBag.h |
@@ -0,0 +1,266 @@ |
+// Copyright 2014 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. |
+ |
+#ifndef PropertyBag_h |
+#define PropertyBag_h |
+ |
+#include "bindings/core/v8/ArrayValue.h" |
+#include "bindings/core/v8/ExceptionMessages.h" |
+#include "bindings/core/v8/ExceptionState.h" |
+#include "bindings/core/v8/Nullable.h" |
+#include "bindings/core/v8/PropertyBagTraits.h" |
+#include "bindings/core/v8/V8Binding.h" |
+#include "bindings/core/v8/V8MessagePort.h" |
+#include "bindings/core/v8/custom/V8ArrayBufferViewCustom.h" |
+#include "bindings/core/v8/custom/V8Uint8ArrayCustom.h" |
+#include "core/html/track/TrackBase.h" |
+#include "wtf/HashSet.h" |
+#include "wtf/Noncopyable.h" |
+#include "wtf/Vector.h" |
+#include "wtf/text/AtomicString.h" |
+#include "wtf/text/WTFString.h" |
+#include <v8.h> |
+ |
+namespace blink { |
+ |
+class ArrayValue; |
+class Dictionary; |
+class LocalDOMWindow; |
+ |
+// FIXME: Remove these specialization. Maybe the IDL compiler |
+// should generate them. |
+template <> |
+struct PropertyBagTraits<Uint8Array> { |
+ typedef V8Uint8Array type; |
+}; |
+ |
+template <> |
+struct PropertyBagTraits<ArrayBufferView> { |
+ typedef V8ArrayBufferView type; |
+}; |
+ |
+// PropertyBag is used by bindings layer to retrieve native values from |
+// a V8 object. |
+class PropertyBag { |
+ WTF_MAKE_NONCOPYABLE(PropertyBag); |
+public: |
+ enum PropertyNullable { |
+ IsNullable, |
+ IsNotNullable |
+ }; |
+ |
+ PropertyBag(v8::Isolate* isolate, const v8::Handle<v8::Object>& object, ExceptionState& exceptionState) |
+ : m_isolate(isolate) |
+ , m_object(object) |
+ , m_exceptionState(exceptionState) |
+ { |
+ ASSERT(!m_object.IsEmpty()); |
+ } |
+ |
+ bool hasProperty(const String& key) const |
+ { |
+ v8::Handle<v8::String> v8Key = v8String(m_isolate, key); |
+ return m_object->Has(v8Key); |
+ } |
+ |
+ template <typename T> |
+ bool get(const String& key, T& value, bool& hasValue, PropertyNullable nullable = IsNotNullable) const |
+ { |
+ hasValue = false; |
+ v8::Handle<v8::String> v8Key = v8String(m_isolate, key); |
+ v8::Local<v8::Value> v8Value = m_object->Get(v8Key); |
+ if (v8Value.IsEmpty()) |
+ return false; |
+ |
+ hasValue = true; |
+ bool success; |
+ if (nullable == IsNullable) { |
+ // Try to get a value before isUndefinedOrNull() check |
+ // because getInternal() may handle null/undefined. |
+ success = getInternal(key, v8Value, value); |
+ if (isUndefinedOrNull(v8Value)) { |
+ m_exceptionState.clearException(); |
+ return true; |
+ } |
+ } else { |
+ if (isUndefinedOrNull(v8Value)) |
+ return false; |
+ success = getInternal(key, v8Value, value); |
+ } |
+ |
+ if (m_exceptionState.throwIfNeeded()) { |
+ m_exceptionState.clearException(); |
+ return false; |
+ } |
+ return success; |
+ } |
+ |
+ template <typename T> |
+ bool get(const String& key, T& value, PropertyNullable nullable = IsNotNullable) const |
+ { |
+ bool unused; |
+ return get(key, value, unused, nullable); |
+ } |
+ |
+ // Similar to get() but returns true when the V8 object doesn't have the given key. |
+ template <typename T> |
+ bool convert(const String& key, T& value) const |
+ { |
+ v8::Handle<v8::String> v8Key = v8String(m_isolate, key); |
+ v8::Local<v8::Value> v8Value = m_object->Get(v8Key); |
+ if (v8Value.IsEmpty()) |
+ return true; |
+ bool success = getInternal(key, v8Value, value); |
+ if (isUndefinedOrNull(v8Value)) { |
+ m_exceptionState.clearException(); |
+ return true; |
+ } |
+ return success; |
+ } |
+ |
+ template <typename T> |
+ bool set(const String& key, const T& value) |
+ { |
+ // FIXME: Use the right creationContext. |
+ v8::Handle<v8::Object> creationContext; |
+ return m_object->Set(v8String(m_isolate, key), V8ValueTraits<T>::toV8Value(value, creationContext, m_isolate)); |
+ } |
+ |
+private: |
+ // FIXME: Following specializations should be gone. |
+ bool getInternal(const String&, v8::Handle<v8::Value>&, ArrayValue&) const; |
+ bool getInternal(const String&, v8::Handle<v8::Value>&, RefPtrWillBeMember<LocalDOMWindow>&) const; |
+ bool getInternal(const String&, v8::Handle<v8::Value>&, MessagePortArray&) const; |
+ bool getInternal(const String&, v8::Handle<v8::Value>&, HashSet<AtomicString>&) const; |
+ bool getInternal(const String&, v8::Handle<v8::Value>&, RefPtrWillBeMember<TrackBase>&) const; |
+ bool getInternal(const String&, v8::Handle<v8::Value>&, RefPtrWillBeMember<EventTarget>&) const; |
+ |
+ // 'any' type use this function. |
+ bool getInternal(const String& key, v8::Handle<v8::Value>& v8Value, v8::Local<v8::Value>& value) const |
+ { |
+ value = v8Value; |
+ return true; |
+ } |
+ |
+ // IDL interface types use this template. |
+ template <template <typename> class PointerType, typename T> |
+ bool getInternal(const String& key, v8::Handle<v8::Value>& v8Value, PointerType<T>& value) const |
+ { |
+ value = PropertyBagTraits<T>::type::toImplWithTypeCheck(m_isolate, v8Value); |
+ return !!value; |
+ } |
+ |
+ // Container types use following templates. |
+ |
+ template <typename T> |
+ bool getInternal(const String& key, v8::Handle<v8::Value>& v8Value, Vector<T>& value) const |
+ { |
+ if (!v8Value->IsArray()) |
+ return false; |
+ value = toImplArray<T>(v8Value, 0, m_isolate); |
+ return true; |
+ } |
+ |
+ template <typename T> |
+ bool getInternal(const String& key, v8::Handle<v8::Value>& v8Value, Nullable<T>& value) const |
+ { |
+ if (isUndefinedOrNull(v8Value)) |
+ return true; |
+ |
+ T innerValue; |
+ if (getInternal(key, v8Value, innerValue)) { |
+ value.set(innerValue); |
+ return true; |
+ } |
+ return false; |
+ } |
+ |
+ // Default template, primitive types use this template. |
+ template <typename T> |
+ bool getInternal(const String& key, v8::Handle<v8::Value>& v8Value, T& value) const |
+ { |
+ value = NativeValueTraits<T>::nativeValueMayFail(m_isolate, v8Value, m_exceptionState); |
+ if (m_exceptionState.hadException()) |
+ return false; |
+ return true; |
+ } |
+ |
+ v8::Isolate* m_isolate; |
+ v8::Handle<v8::Object> m_object; |
+ ExceptionState& m_exceptionState; |
+ |
+ friend class Dictionary; |
+}; |
+ |
+// FIXME: Reduce duplication. Maybe move to V8Binding.h? |
+template <typename T> |
+struct TypeErrorMessage { |
+ static void throwTypeError(const String& key, const String& typeName, ExceptionState& exceptionState) |
+ { |
+ exceptionState.throwTypeError(ExceptionMessages::incorrectPropertyType(key, "does not have a " + typeName + " type.")); |
+ } |
+}; |
+ |
+template <typename T> |
+struct TypeErrorMessage<HashSet<T> > { |
+ static void throwTypeError(const String& key, const String& typeName, ExceptionState& exceptionState) |
+ { |
+ exceptionState.throwTypeError(ExceptionMessages::notASequenceTypeProperty(key)); |
+ } |
+}; |
+ |
+template <typename T> |
+struct TypeErrorMessage<Vector<T> > { |
+ static void throwTypeError(const String& key, const String& typeName, ExceptionState& exceptionState) |
+ { |
+ exceptionState.throwTypeError(ExceptionMessages::notASequenceTypeProperty(key)); |
+ } |
+}; |
+ |
+template <> |
+struct TypeErrorMessage<ArrayValue> { |
+ static void throwTypeError(const String& key, const String& typeName, ExceptionState& exceptionState) |
+ { |
+ exceptionState.throwTypeError(ExceptionMessages::notASequenceTypeProperty(key)); |
+ } |
+}; |
+ |
+// FIXME: Separate into its own header file. |
+class EventInitInitializer { |
+public: |
+ EventInitInitializer(const String& interfaceName, const PropertyBag& bag, ExceptionState& exceptionState) |
+ : m_interfaceName(interfaceName) |
+ , m_bag(bag) |
+ , m_exceptionState(exceptionState) |
+ { |
+ } |
+ |
+ template <typename T> |
+ bool initializeProperty(const String& key, T& value, const String& typeName, PropertyBag::PropertyNullable nullable) |
+ { |
+ if (!m_bag.hasProperty(key)) |
+ return true; |
+ |
+ if (m_bag.convert(key, value)) |
+ return true; |
+ |
+ if (m_exceptionState.throwIfNeeded()) |
+ return false; |
+ |
+ TypeErrorMessage<T>::throwTypeError(key, typeName, m_exceptionState); |
+ return false; |
+ } |
+ |
+ // FIXME: unnecessary? |
+ const String& interfaceName() const { return m_interfaceName; } |
+ |
+private: |
+ const String m_interfaceName; |
+ const PropertyBag& m_bag; |
+ ExceptionState& m_exceptionState; |
+}; |
+ |
+} // namespace blink |
+ |
+#endif // PropertyBag_h |