OLD | NEW |
1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2017 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef NativeValueTraitsImpl_h | 5 #ifndef NativeValueTraitsImpl_h |
6 #define NativeValueTraitsImpl_h | 6 #define NativeValueTraitsImpl_h |
7 | 7 |
8 #include "bindings/core/v8/IDLTypes.h" | 8 #include "bindings/core/v8/IDLTypes.h" |
9 #include "bindings/core/v8/NativeValueTraits.h" | 9 #include "bindings/core/v8/NativeValueTraits.h" |
10 #include "bindings/core/v8/V8Binding.h" | 10 #include "bindings/core/v8/V8Binding.h" |
(...skipping 265 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
276 } | 276 } |
277 }; | 277 }; |
278 | 278 |
279 // Sequences | 279 // Sequences |
280 template <typename T> | 280 template <typename T> |
281 struct NativeValueTraits<IDLSequence<T>> | 281 struct NativeValueTraits<IDLSequence<T>> |
282 : public NativeValueTraitsBase<IDLSequence<T>> { | 282 : public NativeValueTraitsBase<IDLSequence<T>> { |
283 // Nondependent types need to be explicitly qualified to be accessible. | 283 // Nondependent types need to be explicitly qualified to be accessible. |
284 using typename NativeValueTraitsBase<IDLSequence<T>>::ImplType; | 284 using typename NativeValueTraitsBase<IDLSequence<T>>::ImplType; |
285 | 285 |
| 286 // https://heycam.github.io/webidl/#es-sequence |
286 static ImplType NativeValue(v8::Isolate* isolate, | 287 static ImplType NativeValue(v8::Isolate* isolate, |
287 v8::Local<v8::Value> value, | 288 v8::Local<v8::Value> value, |
288 ExceptionState& exception_state) { | 289 ExceptionState& exception_state) { |
289 return NativeValue(isolate, value, exception_state, 0); | 290 if (!value->IsObject()) { |
| 291 exception_state.ThrowTypeError( |
| 292 "The provided value cannot be converted to a sequence."); |
| 293 return ImplType(); |
| 294 } |
| 295 |
| 296 ImplType result; |
| 297 // TODO(rakuco): Checking for IsArray() may not be enough. Other engines |
| 298 // also prefer regular array iteration over a custom @@iterator when the |
| 299 // latter is defined, but it is not clear if this is a valid optimization. |
| 300 if (value->IsArray()) { |
| 301 ConvertSequenceFast(isolate, value.As<v8::Array>(), exception_state, |
| 302 result); |
| 303 } else { |
| 304 ConvertSequenceSlow(isolate, value.As<v8::Object>(), exception_state, |
| 305 result); |
| 306 } |
| 307 |
| 308 if (exception_state.HadException()) |
| 309 return ImplType(); |
| 310 return result; |
290 } | 311 } |
291 | 312 |
292 static ImplType NativeValue(v8::Isolate* isolate, | 313 private: |
293 v8::Local<v8::Value> value, | 314 // Fast case: we're interating over an Array that adheres to |
294 ExceptionState& exception_state, | 315 // %ArrayIteratorPrototype%'s protocol. |
295 int index) { | 316 static void ConvertSequenceFast(v8::Isolate* isolate, |
296 return ToImplArray<ImplType, T>(value, index, isolate, exception_state); | 317 v8::Local<v8::Array> v8_array, |
| 318 ExceptionState& exception_state, |
| 319 ImplType& result) { |
| 320 const uint32_t length = v8_array->Length(); |
| 321 if (length > ImplType::MaxCapacity()) { |
| 322 exception_state.ThrowRangeError("Array length exceeds supported limit."); |
| 323 return; |
| 324 } |
| 325 result.ReserveInitialCapacity(length); |
| 326 v8::TryCatch block(isolate); |
| 327 for (uint32_t i = 0; i < length; ++i) { |
| 328 v8::Local<v8::Value> element; |
| 329 if (!v8_array->Get(isolate->GetCurrentContext(), i).ToLocal(&element)) { |
| 330 exception_state.RethrowV8Exception(block.Exception()); |
| 331 return; |
| 332 } |
| 333 result.UncheckedAppend( |
| 334 NativeValueTraits<T>::NativeValue(isolate, element, exception_state)); |
| 335 if (exception_state.HadException()) |
| 336 return; |
| 337 } |
| 338 } |
| 339 |
| 340 // Slow case: follow WebIDL's "Creating a sequence from an iterable" steps to |
| 341 // iterate through each element. |
| 342 // https://heycam.github.io/webidl/#create-sequence-from-iterable |
| 343 static void ConvertSequenceSlow(v8::Isolate* isolate, |
| 344 v8::Local<v8::Object> v8_object, |
| 345 ExceptionState& exception_state, |
| 346 ImplType& result) { |
| 347 v8::TryCatch block(isolate); |
| 348 |
| 349 v8::Local<v8::Object> iterator = |
| 350 GetEsIterator(isolate, v8_object, exception_state); |
| 351 if (exception_state.HadException()) |
| 352 return; |
| 353 |
| 354 v8::Local<v8::String> next_key = V8String(isolate, "next"); |
| 355 v8::Local<v8::String> value_key = V8String(isolate, "value"); |
| 356 v8::Local<v8::String> done_key = V8String(isolate, "done"); |
| 357 v8::Local<v8::Context> context = isolate->GetCurrentContext(); |
| 358 while (true) { |
| 359 v8::Local<v8::Value> next; |
| 360 if (!iterator->Get(context, next_key).ToLocal(&next)) { |
| 361 exception_state.RethrowV8Exception(block.Exception()); |
| 362 return; |
| 363 } |
| 364 if (!next->IsFunction()) { |
| 365 exception_state.ThrowTypeError("Iterator.next should be callable."); |
| 366 return; |
| 367 } |
| 368 v8::Local<v8::Value> next_result; |
| 369 if (!V8ScriptRunner::CallFunction(next.As<v8::Function>(), |
| 370 ToExecutionContext(context), iterator, |
| 371 0, nullptr, isolate) |
| 372 .ToLocal(&next_result)) { |
| 373 exception_state.RethrowV8Exception(block.Exception()); |
| 374 return; |
| 375 } |
| 376 if (!next_result->IsObject()) { |
| 377 exception_state.ThrowTypeError( |
| 378 "Iterator.next() did not return an object."); |
| 379 return; |
| 380 } |
| 381 v8::Local<v8::Object> result_object = next_result.As<v8::Object>(); |
| 382 v8::Local<v8::Value> element; |
| 383 v8::Local<v8::Value> done; |
| 384 if (!result_object->Get(context, value_key).ToLocal(&element) || |
| 385 !result_object->Get(context, done_key).ToLocal(&done)) { |
| 386 exception_state.RethrowV8Exception(block.Exception()); |
| 387 return; |
| 388 } |
| 389 bool done_boolean; |
| 390 if (!done->BooleanValue(context).To(&done_boolean)) { |
| 391 exception_state.RethrowV8Exception(block.Exception()); |
| 392 return; |
| 393 } |
| 394 if (done_boolean) |
| 395 break; |
| 396 result.emplace_back( |
| 397 NativeValueTraits<T>::NativeValue(isolate, element, exception_state)); |
| 398 if (exception_state.HadException()) |
| 399 return; |
| 400 } |
297 } | 401 } |
298 }; | 402 }; |
299 | 403 |
300 // Records | 404 // Records |
301 template <typename K, typename V> | 405 template <typename K, typename V> |
302 struct NativeValueTraits<IDLRecord<K, V>> | 406 struct NativeValueTraits<IDLRecord<K, V>> |
303 : public NativeValueTraitsBase<IDLRecord<K, V>> { | 407 : public NativeValueTraitsBase<IDLRecord<K, V>> { |
304 // Nondependent types need to be explicitly qualified to be accessible. | 408 // Nondependent types need to be explicitly qualified to be accessible. |
305 using typename NativeValueTraitsBase<IDLRecord<K, V>>::ImplType; | 409 using typename NativeValueTraitsBase<IDLRecord<K, V>>::ImplType; |
306 | 410 |
(...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
420 } | 524 } |
421 } | 525 } |
422 // "5. Return result." | 526 // "5. Return result." |
423 return result; | 527 return result; |
424 } | 528 } |
425 }; | 529 }; |
426 | 530 |
427 } // namespace blink | 531 } // namespace blink |
428 | 532 |
429 #endif // NativeValueTraitsImpl_h | 533 #endif // NativeValueTraitsImpl_h |
OLD | NEW |