Chromium Code Reviews| 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 0d489a5a61344d525fca94219c5b60132b4187b8..1c4fa0527345ca76f016835c879f4031a45bdd5e 100644 |
| --- a/third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImpl.h |
| +++ b/third_party/WebKit/Source/bindings/core/v8/NativeValueTraitsImpl.h |
| @@ -307,6 +307,144 @@ struct NativeValueTraits<IDLSequence<T>> |
| } |
| }; |
| +// Records |
| +template <typename K, typename V> |
| +struct NativeValueTraits<IDLRecord<K, V>> |
| + : public NativeValueTraitsBase<IDLRecord<K, V>> { |
| + private: |
|
Yuki
2017/03/08 13:37:52
Sort the sections public: first and private: last
Raphael Kubo da Costa (rakuco)
2017/03/08 18:13:19
Done.
|
| + static inline bool isPropertyEnumerable(v8::Isolate* isolate, |
|
Yuki
2017/03/08 13:37:52
It's |inline| by default if member functions are d
Raphael Kubo da Costa (rakuco)
2017/03/08 18:13:19
Done.
|
| + v8::Local<v8::Value> descriptor, |
| + ExceptionState& exceptionState) { |
| + if (descriptor->IsUndefined()) |
|
Yuki
2017/03/08 13:37:52
We don't need this because we're checking IsObject
Raphael Kubo da Costa (rakuco)
2017/03/08 18:13:18
Done.
|
| + return false; |
| + if (!descriptor->IsObject()) |
| + return false; |
| + v8::Local<v8::Value> enumerable; |
| + if (!v8::Local<v8::Object>::Cast(descriptor) |
| + ->Get(isolate->GetCurrentContext(), |
| + v8String(isolate, "enumerable")) |
| + .ToLocal(&enumerable)) |
| + return false; |
| + return toBoolean(isolate, enumerable, exceptionState); |
| + } |
| + |
| + public: |
| + // 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. |
| + CORE_EXPORT static inline ImplType nativeValue( |
| + v8::Isolate* isolate, |
| + v8::Local<v8::Value> originalValue, |
|
Yuki
2017/03/08 13:37:52
Can we name this |value| simply?
Since this is a
Raphael Kubo da Costa (rakuco)
2017/03/08 18:13:19
We can, but I thought the preference was to leave
Yuki
2017/03/09 08:32:55
I didn't notice your intention, and later use of |
|
| + ExceptionState& exceptionState) { |
| + v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
| + |
| + // "1. If Type(O) is not Object, throw a TypeError." |
| + if (!originalValue->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(originalValue); |
| + 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:" |
| + if (!isPropertyEnumerable(isolate, desc, exceptionState)) { |
| + if (exceptionState.hadException()) |
| + return ImplType(); |
| + 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)." |
| + const size_t pos = result.size(); // We can take this shortcut because |
| + // we are always appending. |
| + seenKeys.set(typedKey, pos); |
| + result.uncheckedAppend(std::make_pair(typedKey, typedValue)); |
| + } |
| + } |
| + // "5. Return result." |
| + return result; |
| + } |
| +}; |
| + |
| } // namespace blink |
| #endif // NativeValueTraitsImpl_h |