| Index: third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImpl.h
|
| diff --git a/third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImpl.h b/third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImpl.h
|
| index 7dfb3fb50b7d23fed67908e571dd9e1170078899..ca596228c5f29f91007c89f0ded32eb8e262ec39 100644
|
| --- a/third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImpl.h
|
| +++ b/third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImpl.h
|
| @@ -305,6 +305,131 @@ struct NativeValueTraits<IDLSequence<T>>
|
| }
|
| };
|
|
|
| +// Records
|
| +template <typename K, typename V>
|
| +struct NativeValueTraits<IDLRecord<K, V>>
|
| + : public NativeValueTraitsBase<IDLRecord<K, V>> {
|
| + // Nondependent types need to be explicitly qualified to be accessible.
|
| + using typename NativeValueTraitsBase<IDLRecord<K, V>>::ImplType;
|
| +
|
| + // Converts a JavaScript value |O| to an IDL record<K, V> value. In C++, a
|
| + // record is represented as a Vector<std::pair<k, v>> (or a HeapVector if
|
| + // necessary). See https://heycam.github.io/webidl/#es-record.
|
| + static ImplType nativeValue(v8::Isolate* isolate,
|
| + v8::Local<v8::Value> v8Value,
|
| + ExceptionState& exceptionState) {
|
| + v8::Local<v8::Context> context = isolate->GetCurrentContext();
|
| +
|
| + // "1. If Type(O) is not Object, throw a TypeError."
|
| + if (!v8Value->IsObject()) {
|
| + exceptionState.throwTypeError(
|
| + "Only objects can be converted to record<K,V> types");
|
| + return ImplType();
|
| + }
|
| + v8::Local<v8::Object> v8Object = v8::Local<v8::Object>::Cast(v8Value);
|
| + v8::TryCatch block(isolate);
|
| +
|
| + // "3. Let keys be ? O.[[OwnPropertyKeys]]()."
|
| + v8::Local<v8::Array> keys;
|
| + // While we could pass v8::ONLY_ENUMERABLE below, doing so breaks
|
| + // web-platform-tests' headers-record.html and deviates from the spec
|
| + // algorithm.
|
| + // Symbols are being skipped due to
|
| + // https://github.com/heycam/webidl/issues/294.
|
| + if (!v8Object
|
| + ->GetOwnPropertyNames(context,
|
| + static_cast<v8::PropertyFilter>(
|
| + v8::PropertyFilter::ALL_PROPERTIES |
|
| + v8::PropertyFilter::SKIP_SYMBOLS))
|
| + .ToLocal(&keys)) {
|
| + exceptionState.rethrowV8Exception(block.Exception());
|
| + return ImplType();
|
| + }
|
| + if (keys->Length() > ImplType::maxCapacity()) {
|
| + exceptionState.throwRangeError("Array length exceeds supported limit.");
|
| + return ImplType();
|
| + }
|
| +
|
| + // "2. Let result be a new empty instance of record<K, V>."
|
| + ImplType result;
|
| + result.reserveInitialCapacity(keys->Length());
|
| +
|
| + // The conversion algorithm needs a data structure with fast insertion at
|
| + // the end while at the same time requiring fast checks for previous insert
|
| + // of a given key. |seenKeys| is a key/position in |result| map that aids in
|
| + // the latter part.
|
| + HashMap<String, size_t> seenKeys;
|
| +
|
| + for (uint32_t i = 0; i < keys->Length(); ++i) {
|
| + // "4. Repeat, for each element key of keys in List order:"
|
| + v8::Local<v8::Value> key;
|
| + if (!keys->Get(context, i).ToLocal(&key)) {
|
| + exceptionState.rethrowV8Exception(block.Exception());
|
| + return ImplType();
|
| + }
|
| +
|
| + // "4.1. Let desc be ? O.[[GetOwnProperty]](key)."
|
| + v8::Local<v8::Value> desc;
|
| + if (!v8Object
|
| + ->GetOwnPropertyDescriptor(
|
| + context, key->ToString(context).ToLocalChecked())
|
| + .ToLocal(&desc)) {
|
| + exceptionState.rethrowV8Exception(block.Exception());
|
| + return ImplType();
|
| + }
|
| +
|
| + // "4.2. If desc is not undefined and desc.[[Enumerable]] is true:"
|
| + // We can call ToLocalChecked() and ToChecked() here because
|
| + // GetOwnPropertyDescriptor is responsible for catching any exceptions
|
| + // and failures, and if we got to this point of the code we have a proper
|
| + // object that was not created by a user.
|
| + DCHECK(desc->IsObject());
|
| + v8::Local<v8::Value> enumerable =
|
| + v8::Local<v8::Object>::Cast(desc)
|
| + ->Get(context, v8String(isolate, "enumerable"))
|
| + .ToLocalChecked();
|
| + if (!enumerable->BooleanValue(context).ToChecked())
|
| + continue;
|
| +
|
| + // "4.2.1. Let typedKey be key converted to an IDL value of type K."
|
| + String typedKey =
|
| + NativeValueTraits<K>::nativeValue(isolate, key, exceptionState);
|
| + if (exceptionState.hadException())
|
| + return ImplType();
|
| +
|
| + // "4.2.2. Let value be ? Get(O, key)."
|
| + v8::Local<v8::Value> value;
|
| + if (!v8Object->Get(context, key).ToLocal(&value)) {
|
| + exceptionState.rethrowV8Exception(block.Exception());
|
| + return ImplType();
|
| + }
|
| +
|
| + // "4.2.3. Let typedValue be value converted to an IDL value of type V."
|
| + typename ImplType::ValueType::second_type typedValue =
|
| + NativeValueTraits<V>::nativeValue(isolate, value, exceptionState);
|
| + if (exceptionState.hadException())
|
| + return ImplType();
|
| +
|
| + if (seenKeys.contains(typedKey)) {
|
| + // "4.2.4. If typedKey is already a key in result, set its value to
|
| + // typedValue.
|
| + // Note: This can happen when O is a proxy object."
|
| + const size_t pos = seenKeys.at(typedKey);
|
| + result[pos] = std::make_pair(typedKey, typedValue);
|
| + } else {
|
| + // "4.2.5. Otherwise, append to result a mapping (typedKey,
|
| + // typedValue)."
|
| + // Note we can take this shortcut because we are always appending.
|
| + const size_t pos = result.size();
|
| + seenKeys.set(typedKey, pos);
|
| + result.uncheckedAppend(std::make_pair(typedKey, typedValue));
|
| + }
|
| + }
|
| + // "5. Return result."
|
| + return result;
|
| + }
|
| +};
|
| +
|
| } // namespace blink
|
|
|
| #endif // NativeValueTraitsImpl_h
|
|
|