| 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
|
|
|