1 /* 2 * Copyright (C) 2009 Google Inc. All rights reserved. 3 * Copyright (C) 2012 Ericsson AB. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are 7 * met: 8 * 9 * * Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * * Redistributions in binary form must reproduce the above 12 * copyright notice, this list of conditions and the following disclaimer 13 * in the documentation and/or other materials provided with the 14 * distribution. 15 * * Neither the name of Google Inc. nor the names of its 16 * contributors may be used to endorse or promote products derived from 17 * this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 20 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 21 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 22 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 23 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 24 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 25 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 26 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 27 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 28 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 29 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #ifndef V8Binding_h 33 #define V8Binding_h 34 35 #include "bindings/core/v8/DOMWrapperWorld.h" 36 #include "bindings/core/v8/ExceptionMessages.h" 37 #include "bindings/core/v8/ExceptionState.h" 38 #include "bindings/core/v8/ScriptValue.h" 39 #include "bindings/core/v8/ScriptWrappable.h" 40 #include "bindings/core/v8/V8BindingMacros.h" 41 #include "bindings/core/v8/V8PerIsolateData.h" 42 #include "bindings/core/v8/V8StringResource.h" 43 #include "bindings/core/v8/V8ThrowException.h" 44 #include "bindings/core/v8/V8ValueCache.h" 45 #include "platform/heap/Heap.h" 46 #include "wtf/GetPtr.h" 47 #include "wtf/MathExtras.h" 48 #include "wtf/text/AtomicString.h" 49 #include <v8.h> 50 51 namespace blink { 52 53 class LocalDOMWindow; 54 class Document; 55 class EventListener; 56 class ExecutionContext; 57 class ExceptionState; 58 class LocalFrame; 59 class NodeFilter; 60 class XPathNSResolver; 61 62 namespace TraceEvent { 63 class ConvertableToTraceFormat; 64 } 65 66 const int kMaxRecursionDepth = 22; 67 68 // Helpers for throwing JavaScript TypeErrors for arity mismatches. 69 void setArityTypeError(ExceptionState&, const char* valid, unsigned provided); 70 v8::Local<v8::Value> createMinimumArityTypeErrorForMethod(const char* method, const char* type, unsigned expected, unsigned provided, v8::Isolate*); 71 v8::Local<v8::Value> createMinimumArityTypeErrorForConstructor(const char* type, unsigned expected, unsigned provided, v8::Isolate*); 72 void setMinimumArityTypeError(ExceptionState&, unsigned expected, unsigned provided); 73 74 v8::ArrayBuffer::Allocator* v8ArrayBufferAllocator(); 75 76 template<typename CallbackInfo, typename V> 77 inline void v8SetReturnValue(const CallbackInfo& info, V v) 78 { 79 info.GetReturnValue().Set(v); 80 } 81 82 template<typename CallbackInfo> 83 inline void v8SetReturnValueBool(const CallbackInfo& info, bool v) 84 { 85 info.GetReturnValue().Set(v); 86 } 87 88 template<typename CallbackInfo> 89 inline void v8SetReturnValueInt(const CallbackInfo& info, int v) 90 { 91 info.GetReturnValue().Set(v); 92 } 93 94 template<typename CallbackInfo> 95 inline void v8SetReturnValueUnsigned(const CallbackInfo& info, unsigned v) 96 { 97 info.GetReturnValue().Set(v); 98 } 99 100 template<typename CallbackInfo> 101 inline void v8SetReturnValueNull(const CallbackInfo& info) 102 { 103 info.GetReturnValue().SetNull(); 104 } 105 106 template<typename CallbackInfo> 107 inline void v8SetReturnValueUndefined(const CallbackInfo& info) 108 { 109 info.GetReturnValue().SetUndefined(); 110 } 111 112 template<typename CallbackInfo> 113 inline void v8SetReturnValueEmptyString(const CallbackInfo& info) 114 { 115 info.GetReturnValue().SetEmptyString(); 116 } 117 118 template <class CallbackInfo> 119 inline void v8SetReturnValueString(const CallbackInfo& info, const String& string, v8::Isolate* isolate) 120 { 121 if (string.isNull()) { 122 v8SetReturnValueEmptyString(info); 123 return; 124 } 125 V8PerIsolateData::from(isolate)->stringCache()->setReturnValueFromString(info.GetReturnValue(), string.impl()); 126 } 127 128 template <class CallbackInfo> 129 inline void v8SetReturnValueStringOrNull(const CallbackInfo& info, const String& string, v8::Isolate* isolate) 130 { 131 if (string.isNull()) { 132 v8SetReturnValueNull(info); 133 return; 134 } 135 V8PerIsolateData::from(isolate)->stringCache()->setReturnValueFromString(info.GetReturnValue(), string.impl()); 136 } 137 138 template <class CallbackInfo> 139 inline void v8SetReturnValueStringOrUndefined(const CallbackInfo& info, const String& string, v8::Isolate* isolate) 140 { 141 if (string.isNull()) { 142 v8SetReturnValueUndefined(info); 143 return; 144 } 145 V8PerIsolateData::from(isolate)->stringCache()->setReturnValueFromString(info.GetReturnValue(), string.impl()); 146 } 147 148 // Convert v8::String to a WTF::String. If the V8 string is not already 149 // an external string then it is transformed into an external string at this 150 // point to avoid repeated conversions. 151 inline String toCoreString(v8::Handle<v8::String> value) 152 { 153 return v8StringToWebCoreString<String>(value, Externalize); 154 } 155 156 inline String toCoreStringWithNullCheck(v8::Handle<v8::String> value) 157 { 158 if (value.IsEmpty() || value->IsNull()) 159 return String(); 160 return toCoreString(value); 161 } 162 163 inline String toCoreStringWithUndefinedOrNullCheck(v8::Handle<v8::String> value) 164 { 165 if (value.IsEmpty() || value->IsNull() || value->IsUndefined()) 166 return String(); 167 return toCoreString(value); 168 } 169 170 inline AtomicString toCoreAtomicString(v8::Handle<v8::String> value) 171 { 172 return v8StringToWebCoreString<AtomicString>(value, Externalize); 173 } 174 175 // This method will return a null String if the v8::Value does not contain a v8::String. 176 // It will not call ToString() on the v8::Value. If you want ToString() to be called, 177 // please use the TONATIVE_FOR_V8STRINGRESOURCE_*() macros instead. 178 inline String toCoreStringWithUndefinedOrNullCheck(v8::Handle<v8::Value> value) 179 { 180 if (value.IsEmpty() || !value->IsString()) 181 return String(); 182 return toCoreString(value.As<v8::String>()); 183 } 184 185 // Convert a string to a V8 string. 186 // Return a V8 external string that shares the underlying buffer with the given 187 // WebCore string. The reference counting mechanism is used to keep the 188 // underlying buffer alive while the string is still live in the V8 engine. 189 inline v8::Handle<v8::String> v8String(v8::Isolate* isolate, const String& string) 190 { 191 if (string.isNull()) 192 return v8::String::Empty(isolate); 193 return V8PerIsolateData::from(isolate)->stringCache()->v8ExternalString(string.impl(), isolate); 194 } 195 196 inline v8::Handle<v8::String> v8AtomicString(v8::Isolate* isolate, const char* str) 197 { 198 ASSERT(isolate); 199 return v8::String::NewFromUtf8(isolate, str, v8::String::kInternalizedString, strlen(str)); 200 } 201 202 inline v8::Handle<v8::String> v8AtomicString(v8::Isolate* isolate, const char* str, size_t length) 203 { 204 ASSERT(isolate); 205 return v8::String::NewFromUtf8(isolate, str, v8::String::kInternalizedString, length); 206 } 207 208 inline v8::Handle<v8::Value> v8Undefined() 209 { 210 return v8::Handle<v8::Value>(); 211 } 212 213 // Converts a DOM object to a v8 value. This function is intended to be used 214 // internally. If you want to convert a DOM object to a V8 value, 215 // - Use toV8 if you can include V8X.h. 216 // - Use V8ValueTraits<T>::toV8Value if you cannot include V8X.h. 217 // Note: Including bindings/{core, modules}/v8/V8*.h from core and modules 218 // is fine. In such a case, perhaps toV8 is what you want. 219 // Note: toV8NoInline is a non-inline toV8 and V8ValueTraits::toV8Value offers 220 // more: You can handle value conversion generally with it. 221 template<typename T> 222 v8::Handle<v8::Value> toV8NoInline(T* impl, v8::Handle<v8::Object> creationContext, v8::Isolate*); 223 224 template <typename T> 225 struct V8ValueTraits { 226 static v8::Handle<v8::Value> toV8Value(const T& value, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 227 { 228 if (!WTF::getPtr(value)) 229 return v8::Null(isolate); 230 return toV8NoInline(WTF::getPtr(value), creationContext, isolate); 231 } 232 }; 233 234 template<> 235 struct V8ValueTraits<String> { 236 static inline v8::Handle<v8::Value> toV8Value(const String& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 237 { 238 return v8String(isolate, value); 239 } 240 }; 241 242 template<> 243 struct V8ValueTraits<AtomicString> { 244 static inline v8::Handle<v8::Value> toV8Value(const AtomicString& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 245 { 246 return v8String(isolate, value); 247 } 248 }; 249 250 template<size_t n> 251 struct V8ValueTraits<char[n]> { 252 static inline v8::Handle<v8::Value> toV8Value(char const (&value)[n], v8::Handle<v8::Object>, v8::Isolate* isolate) 253 { 254 return v8String(isolate, value); 255 } 256 }; 257 258 template<size_t n> 259 struct V8ValueTraits<char const[n]> { 260 static inline v8::Handle<v8::Value> toV8Value(char const (&value)[n], v8::Handle<v8::Object>, v8::Isolate* isolate) 261 { 262 return v8String(isolate, value); 263 } 264 }; 265 266 template<> 267 struct V8ValueTraits<const char*> { 268 static inline v8::Handle<v8::Value> toV8Value(const char* const& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 269 { 270 if (!value) { 271 // We return an empty string, not null, in order to align 272 // with v8String(isolate, String()). 273 return v8::String::Empty(isolate); 274 } 275 return v8String(isolate, value); 276 } 277 }; 278 279 template<> 280 struct V8ValueTraits<char*> { 281 static inline v8::Handle<v8::Value> toV8Value(char* const& value, v8::Handle<v8::Object> object, v8::Isolate* isolate) 282 { 283 return V8ValueTraits<const char*>::toV8Value(value, object, isolate); 284 } 285 }; 286 287 template<> 288 struct V8ValueTraits<int> { 289 static inline v8::Handle<v8::Value> toV8Value(const int& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 290 { 291 return v8::Integer::New(isolate, value); 292 } 293 }; 294 295 template<> 296 struct V8ValueTraits<long> { 297 static inline v8::Handle<v8::Value> toV8Value(const long& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 298 { 299 return v8::Integer::New(isolate, value); 300 } 301 }; 302 303 template<> 304 struct V8ValueTraits<unsigned> { 305 static inline v8::Handle<v8::Value> toV8Value(const unsigned& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 306 { 307 return v8::Integer::NewFromUnsigned(isolate, value); 308 } 309 }; 310 311 template<> 312 struct V8ValueTraits<unsigned long> { 313 static inline v8::Handle<v8::Value> toV8Value(const unsigned long& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 314 { 315 return v8::Integer::NewFromUnsigned(isolate, value); 316 } 317 }; 318 319 template<> 320 struct V8ValueTraits<float> { 321 static inline v8::Handle<v8::Value> toV8Value(const float& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 322 { 323 return v8::Number::New(isolate, value); 324 } 325 }; 326 327 template<> 328 struct V8ValueTraits<double> { 329 static inline v8::Handle<v8::Value> toV8Value(const double& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 330 { 331 return v8::Number::New(isolate, value); 332 } 333 }; 334 335 template<> 336 struct V8ValueTraits<bool> { 337 static inline v8::Handle<v8::Value> toV8Value(const bool& value, v8::Handle<v8::Object>, v8::Isolate* isolate) 338 { 339 return v8::Boolean::New(isolate, value); 340 } 341 }; 342 343 // V8NullType and V8UndefinedType are used only for the value conversion. 344 class V8NullType { }; 345 class V8UndefinedType { }; 346 347 template<> 348 struct V8ValueTraits<V8NullType> { 349 static inline v8::Handle<v8::Value> toV8Value(const V8NullType&, v8::Handle<v8::Object>, v8::Isolate* isolate) 350 { 351 return v8::Null(isolate); 352 } 353 }; 354 355 template<> 356 struct V8ValueTraits<V8UndefinedType> { 357 static inline v8::Handle<v8::Value> toV8Value(const V8UndefinedType&, v8::Handle<v8::Object>, v8::Isolate* isolate) 358 { 359 return v8::Undefined(isolate); 360 } 361 }; 362 363 template<> 364 struct V8ValueTraits<ScriptValue> { 365 static inline v8::Handle<v8::Value> toV8Value(const ScriptValue& value, v8::Handle<v8::Object>, v8::Isolate*) 366 { 367 return value.v8Value(); 368 } 369 }; 370 371 template<> 372 struct V8ValueTraits<v8::Handle<v8::Value> > { 373 static inline v8::Handle<v8::Value> toV8Value(const v8::Handle<v8::Value>& value, v8::Handle<v8::Object>, v8::Isolate*) 374 { 375 return value; 376 } 377 }; 378 379 template<> 380 struct V8ValueTraits<v8::Local<v8::Value> > { 381 static inline v8::Handle<v8::Value> toV8Value(const v8::Local<v8::Value>& value, v8::Handle<v8::Object>, v8::Isolate*) 382 { 383 return value; 384 } 385 }; 386 387 template<typename T, size_t inlineCapacity> 388 v8::Handle<v8::Value> v8Array(const Vector<T, inlineCapacity>& iterator, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 389 { 390 v8::Local<v8::Array> result = v8::Array::New(isolate, iterator.size()); 391 int index = 0; 392 typename Vector<T, inlineCapacity>::const_iterator end = iterator.end(); 393 typedef V8ValueTraits<T> TraitsType; 394 for (typename Vector<T, inlineCapacity>::const_iterator iter = iterator.begin(); iter != end; ++iter) 395 result->Set(v8::Integer::New(isolate, index++), TraitsType::toV8Value(*iter, creationContext, isolate)); 396 return result; 397 } 398 399 template <typename T, size_t inlineCapacity, typename Allocator> 400 struct V8ValueTraits<WTF::Vector<T, inlineCapacity, Allocator> > { 401 static v8::Handle<v8::Value> toV8Value(const Vector<T, inlineCapacity, Allocator>& value, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 402 { 403 return v8Array(value, creationContext, isolate); 404 } 405 }; 406 407 template<typename T, size_t inlineCapacity> 408 v8::Handle<v8::Value> v8Array(const HeapVector<T, inlineCapacity>& iterator, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 409 { 410 v8::Local<v8::Array> result = v8::Array::New(isolate, iterator.size()); 411 int index = 0; 412 typename HeapVector<T, inlineCapacity>::const_iterator end = iterator.end(); 413 typedef V8ValueTraits<T> TraitsType; 414 for (typename HeapVector<T, inlineCapacity>::const_iterator iter = iterator.begin(); iter != end; ++iter) 415 result->Set(v8::Integer::New(isolate, index++), TraitsType::toV8Value(*iter, creationContext, isolate)); 416 return result; 417 } 418 419 template <typename T, size_t inlineCapacity> 420 struct V8ValueTraits<HeapVector<T, inlineCapacity> > { 421 static v8::Handle<v8::Value> toV8Value(const HeapVector<T, inlineCapacity>& value, v8::Handle<v8::Object> creationContext, v8::Isolate* isolate) 422 { 423 return v8Array(value, creationContext, isolate); 424 } 425 }; 426 427 // Conversion flags, used in toIntXX/toUIntXX. 428 enum IntegerConversionConfiguration { 429 NormalConversion, 430 EnforceRange, 431 Clamp 432 }; 433 434 // Convert a value to a 8-bit signed integer. The conversion fails if the 435 // value cannot be converted to a number or the range violated per WebIDL: 436 // http://www.w3.org/TR/WebIDL/#es-byte 437 int8_t toInt8(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 438 inline int8_t toInt8(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 439 { 440 return toInt8(value, NormalConversion, exceptionState); 441 } 442 443 // Convert a value to a 8-bit integer assuming the conversion cannot fail. 444 int8_t toInt8(v8::Handle<v8::Value>); 445 446 // Convert a value to a 8-bit unsigned integer. The conversion fails if the 447 // value cannot be converted to a number or the range violated per WebIDL: 448 // http://www.w3.org/TR/WebIDL/#es-octet 449 uint8_t toUInt8(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 450 inline uint8_t toUInt8(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 451 { 452 return toUInt8(value, NormalConversion, exceptionState); 453 } 454 455 // Convert a value to a 8-bit unsigned integer assuming the conversion cannot fail. 456 uint8_t toUInt8(v8::Handle<v8::Value>); 457 458 // Convert a value to a 16-bit signed integer. The conversion fails if the 459 // value cannot be converted to a number or the range violated per WebIDL: 460 // http://www.w3.org/TR/WebIDL/#es-short 461 int16_t toInt16(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 462 inline int16_t toInt16(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 463 { 464 return toInt16(value, NormalConversion, exceptionState); 465 } 466 467 // Convert a value to a 16-bit integer assuming the conversion cannot fail. 468 int16_t toInt16(v8::Handle<v8::Value>); 469 470 // Convert a value to a 16-bit unsigned integer. The conversion fails if the 471 // value cannot be converted to a number or the range violated per WebIDL: 472 // http://www.w3.org/TR/WebIDL/#es-unsigned-short 473 uint16_t toUInt16(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 474 inline uint16_t toUInt16(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 475 { 476 return toUInt16(value, NormalConversion, exceptionState); 477 } 478 479 // Convert a value to a 16-bit unsigned integer assuming the conversion cannot fail. 480 uint16_t toUInt16(v8::Handle<v8::Value>); 481 482 // Convert a value to a 32-bit signed integer. The conversion fails if the 483 // value cannot be converted to a number or the range violated per WebIDL: 484 // http://www.w3.org/TR/WebIDL/#es-long 485 int32_t toInt32(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 486 inline int32_t toInt32(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 487 { 488 return toInt32(value, NormalConversion, exceptionState); 489 } 490 491 // Convert a value to a 32-bit integer assuming the conversion cannot fail. 492 int32_t toInt32(v8::Handle<v8::Value>); 493 494 // Convert a value to a 32-bit unsigned integer. The conversion fails if the 495 // value cannot be converted to a number or the range violated per WebIDL: 496 // http://www.w3.org/TR/WebIDL/#es-unsigned-long 497 uint32_t toUInt32(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 498 inline uint32_t toUInt32(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 499 { 500 return toUInt32(value, NormalConversion, exceptionState); 501 } 502 503 // Convert a value to a 32-bit unsigned integer assuming the conversion cannot fail. 504 uint32_t toUInt32(v8::Handle<v8::Value>); 505 506 // Convert a value to a 64-bit signed integer. The conversion fails if the 507 // value cannot be converted to a number or the range violated per WebIDL: 508 // http://www.w3.org/TR/WebIDL/#es-long-long 509 int64_t toInt64(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 510 inline int64_t toInt64(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 511 { 512 return toInt64(value, NormalConversion, exceptionState); 513 } 514 515 // Convert a value to a 64-bit integer assuming the conversion cannot fail. 516 int64_t toInt64(v8::Handle<v8::Value>); 517 518 // Convert a value to a 64-bit unsigned integer. The conversion fails if the 519 // value cannot be converted to a number or the range violated per WebIDL: 520 // http://www.w3.org/TR/WebIDL/#es-unsigned-long-long 521 uint64_t toUInt64(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&); 522 inline uint64_t toUInt64(v8::Handle<v8::Value> value, ExceptionState& exceptionState) 523 { 524 return toUInt64(value, NormalConversion, exceptionState); 525 } 526 527 // Convert a value to a 64-bit unsigned integer assuming the conversion cannot fail. 528 uint64_t toUInt64(v8::Handle<v8::Value>); 529 530 // Convert a value to a single precision float, which might fail. 531 float toFloat(v8::Handle<v8::Value>, ExceptionState&); 532 533 // Convert a value to a single precision float assuming the conversion cannot fail. 534 inline float toFloat(v8::Local<v8::Value> value) 535 { 536 return static_cast<float>(value->NumberValue()); 537 } 538 539 // Convert a value to a double precision float, which might fail. 540 double toDouble(v8::Handle<v8::Value>, ExceptionState&); 541 542 // Converts a value to a String, throwing if any code unit is outside 0-255. 543 String toByteString(v8::Handle<v8::Value>, ExceptionState&); 544 545 // Converts a value to a String, replacing unmatched UTF-16 surrogates with replacement characters. 546 String toScalarValueString(v8::Handle<v8::Value>, ExceptionState&); 547 548 inline v8::Handle<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate) 549 { 550 return value ? v8::True(isolate) : v8::False(isolate); 551 } 552 553 inline double toCoreDate(v8::Handle<v8::Value> object) 554 { 555 if (object->IsDate()) 556 return v8::Handle<v8::Date>::Cast(object)->ValueOf(); 557 if (object->IsNumber()) 558 return object->NumberValue(); 559 return std::numeric_limits<double>::quiet_NaN(); 560 } 561 562 inline v8::Handle<v8::Value> v8DateOrNaN(double value, v8::Isolate* isolate) 563 { 564 ASSERT(isolate); 565 return v8::Date::New(isolate, std::isfinite(value) ? value : std::numeric_limits<double>::quiet_NaN()); 566 } 567 568 // FIXME: Remove the special casing for NodeFilter and XPathNSResolver. 569 PassRefPtrWillBeRawPtr<NodeFilter> toNodeFilter(v8::Handle<v8::Value>, v8::Handle<v8::Object>, ScriptState*); 570 PassRefPtrWillBeRawPtr<XPathNSResolver> toXPathNSResolver(v8::Handle<v8::Value>, v8::Isolate*); 571 572 template<class T> struct NativeValueTraits; 573 574 bool toV8Sequence(v8::Handle<v8::Value>, uint32_t& length, v8::Isolate*, ExceptionState&); 575 576 // Converts a JavaScript value to an array as per the Web IDL specification: 577 // http://www.w3.org/TR/2012/CR-WebIDL-20120419/#es-array 578 template <class T, class V8T> 579 Vector<RefPtr<T> > toRefPtrNativeArrayUnchecked(v8::Local<v8::Value> v8Value, uint32_t length, v8::Isolate* isolate, ExceptionState& exceptionState) 580 { 581 Vector<RefPtr<T> > result; 582 result.reserveInitialCapacity(length); 583 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value); 584 v8::TryCatch block; 585 for (uint32_t i = 0; i < length; ++i) { 586 v8::Handle<v8::Value> element = object->Get(i); 587 if (block.HasCaught()) { 588 exceptionState.rethrowV8Exception(block.Exception()); 589 return Vector<RefPtr<T> >(); 590 } 591 if (V8T::hasInstance(element, isolate)) { 592 v8::Handle<v8::Object> elementObject = v8::Handle<v8::Object>::Cast(element); 593 result.uncheckedAppend(V8T::toImpl(elementObject)); 594 } else { 595 exceptionState.throwTypeError("Invalid Array element type"); 596 return Vector<RefPtr<T> >(); 597 } 598 } 599 return result; 600 } 601 602 template <class T, class V8T> 603 Vector<RefPtr<T> > toRefPtrNativeArray(v8::Handle<v8::Value> value, int argumentIndex, v8::Isolate* isolate, ExceptionState& exceptionState) 604 { 605 v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value)); 606 uint32_t length = 0; 607 if (value->IsArray()) { 608 length = v8::Local<v8::Array>::Cast(v8Value)->Length(); 609 } else if (!toV8Sequence(value, length, isolate, exceptionState)) { 610 if (!exceptionState.hadException()) 611 exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex)); 612 return Vector<RefPtr<T> >(); 613 } 614 return toRefPtrNativeArrayUnchecked<T, V8T>(v8Value, length, isolate, exceptionState); 615 } 616 617 template <class T, class V8T> 618 Vector<RefPtr<T> > toRefPtrNativeArray(v8::Handle<v8::Value> value, const String& propertyName, v8::Isolate* isolate, ExceptionState& exceptionState) 619 { 620 v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value)); 621 uint32_t length = 0; 622 if (value->IsArray()) { 623 length = v8::Local<v8::Array>::Cast(v8Value)->Length(); 624 } else if (!toV8Sequence(value, length, isolate, exceptionState)) { 625 if (!exceptionState.hadException()) 626 exceptionState.throwTypeError(ExceptionMessages::notASequenceTypeProperty(propertyName)); 627 return Vector<RefPtr<T> >(); 628 } 629 return toRefPtrNativeArrayUnchecked<T, V8T>(v8Value, length, isolate, exceptionState); 630 } 631 632 template <class T, class V8T> 633 WillBeHeapVector<RefPtrWillBeMember<T> > toRefPtrWillBeMemberNativeArray(v8::Handle<v8::Value> value, int argumentIndex, v8::Isolate* isolate, ExceptionState& exceptionState) 634 { 635 v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value)); 636 uint32_t length = 0; 637 if (value->IsArray()) { 638 length = v8::Local<v8::Array>::Cast(v8Value)->Length(); 639 } else if (!toV8Sequence(value, length, isolate, exceptionState)) { 640 if (!exceptionState.hadException()) 641 exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex)); 642 return WillBeHeapVector<RefPtrWillBeMember<T> >(); 643 } 644 645 WillBeHeapVector<RefPtrWillBeMember<T> > result; 646 result.reserveInitialCapacity(length); 647 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value); 648 v8::TryCatch block; 649 for (uint32_t i = 0; i < length; ++i) { 650 v8::Handle<v8::Value> element = object->Get(i); 651 if (block.HasCaught()) { 652 exceptionState.rethrowV8Exception(block.Exception()); 653 return WillBeHeapVector<RefPtrWillBeMember<T> >(); 654 } 655 if (V8T::hasInstance(element, isolate)) { 656 v8::Handle<v8::Object> elementObject = v8::Handle<v8::Object>::Cast(element); 657 result.uncheckedAppend(V8T::toImpl(elementObject)); 658 } else { 659 exceptionState.throwTypeError("Invalid Array element type"); 660 return WillBeHeapVector<RefPtrWillBeMember<T> >(); 661 } 662 } 663 return result; 664 } 665 666 template <class T, class V8T> 667 WillBeHeapVector<RefPtrWillBeMember<T> > toRefPtrWillBeMemberNativeArray(v8::Handle<v8::Value> value, const String& propertyName, v8::Isolate* isolate, ExceptionState& exceptionState) 668 { 669 v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value)); 670 uint32_t length = 0; 671 if (value->IsArray()) { 672 length = v8::Local<v8::Array>::Cast(v8Value)->Length(); 673 } else if (!toV8Sequence(value, length, isolate, exceptionState)) { 674 if (!exceptionState.hadException()) 675 exceptionState.throwTypeError(ExceptionMessages::notASequenceTypeProperty(propertyName)); 676 return WillBeHeapVector<RefPtrWillBeMember<T> >(); 677 } 678 679 WillBeHeapVector<RefPtrWillBeMember<T> > result; 680 result.reserveInitialCapacity(length); 681 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value); 682 v8::TryCatch block; 683 for (uint32_t i = 0; i < length; ++i) { 684 v8::Handle<v8::Value> element = object->Get(i); 685 if (block.HasCaught()) { 686 exceptionState.rethrowV8Exception(block.Exception()); 687 return WillBeHeapVector<RefPtrWillBeMember<T> >(); 688 } 689 if (V8T::hasInstance(element, isolate)) { 690 v8::Handle<v8::Object> elementObject = v8::Handle<v8::Object>::Cast(element); 691 result.uncheckedAppend(V8T::toImpl(elementObject)); 692 } else { 693 exceptionState.throwTypeError("Invalid Array element type"); 694 return WillBeHeapVector<RefPtrWillBeMember<T> >(); 695 } 696 } 697 return result; 698 } 699 700 template <class T, class V8T> 701 HeapVector<Member<T> > toMemberNativeArray(v8::Handle<v8::Value> value, int argumentIndex, v8::Isolate* isolate, ExceptionState& exceptionState) 702 { 703 v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value)); 704 uint32_t length = 0; 705 if (value->IsArray()) { 706 length = v8::Local<v8::Array>::Cast(v8Value)->Length(); 707 } else if (!toV8Sequence(value, length, isolate, exceptionState)) { 708 if (!exceptionState.hadException()) 709 exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex)); 710 return HeapVector<Member<T> >(); 711 } 712 713 HeapVector<Member<T> > result; 714 result.reserveInitialCapacity(length); 715 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value); 716 v8::TryCatch block; 717 for (uint32_t i = 0; i < length; ++i) { 718 v8::Handle<v8::Value> element = object->Get(i); 719 if (UNLIKELY(block.HasCaught())) { 720 exceptionState.rethrowV8Exception(block.Exception()); 721 return HeapVector<Member<T> >(); 722 } 723 if (V8T::hasInstance(element, isolate)) { 724 v8::Handle<v8::Object> elementObject = v8::Handle<v8::Object>::Cast(element); 725 result.uncheckedAppend(V8T::toImpl(elementObject)); 726 } else { 727 exceptionState.throwTypeError("Invalid Array element type"); 728 return HeapVector<Member<T> >(); 729 } 730 } 731 return result; 732 } 733 734 // Converts a JavaScript value to an array as per the Web IDL specification: 735 // http://www.w3.org/TR/2012/CR-WebIDL-20120419/#es-array 736 template <class T> 737 Vector<T> toImplArray(v8::Handle<v8::Value> value, int argumentIndex, v8::Isolate* isolate, ExceptionState& exceptionState) 738 { 739 v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value)); 740 uint32_t length = 0; 741 if (value->IsArray()) { 742 length = v8::Local<v8::Array>::Cast(v8Value)->Length(); 743 } else if (!toV8Sequence(value, length, isolate, exceptionState)) { 744 if (!exceptionState.hadException()) 745 exceptionState.throwTypeError(ExceptionMessages::notAnArrayTypeArgumentOrValue(argumentIndex)); 746 return Vector<T>(); 747 } 748 749 Vector<T> result; 750 result.reserveInitialCapacity(length); 751 typedef NativeValueTraits<T> TraitsType; 752 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value); 753 v8::TryCatch block; 754 for (uint32_t i = 0; i < length; ++i) { 755 v8::Handle<v8::Value> element = object->Get(i); 756 if (UNLIKELY(block.HasCaught())) { 757 exceptionState.rethrowV8Exception(block.Exception()); 758 return Vector<T>(); 759 } 760 result.uncheckedAppend(TraitsType::nativeValue(element, isolate, exceptionState)); 761 if (exceptionState.hadException()) 762 return Vector<T>(); 763 } 764 return result; 765 } 766 767 template <class T> 768 Vector<T> toImplArguments(const v8::FunctionCallbackInfo<v8::Value>& info, int startIndex, ExceptionState& exceptionState) 769 { 770 ASSERT(startIndex <= info.Length()); 771 Vector<T> result; 772 typedef NativeValueTraits<T> TraitsType; 773 int length = info.Length(); 774 result.reserveInitialCapacity(length); 775 for (int i = startIndex; i < length; ++i) { 776 result.uncheckedAppend(TraitsType::nativeValue(info[i], info.GetIsolate(), exceptionState)); 777 if (exceptionState.hadException()) 778 return Vector<T>(); 779 } 780 return result; 781 } 782 783 // Validates that the passed object is a sequence type per WebIDL spec 784 // http://www.w3.org/TR/2012/CR-WebIDL-20120419/#es-sequence 785 inline bool toV8Sequence(v8::Handle<v8::Value> value, uint32_t& length, v8::Isolate* isolate, ExceptionState& exceptionState) 786 { 787 // Attempt converting to a sequence if the value is not already an array but is 788 // any kind of object except for a native Date object or a native RegExp object. 789 ASSERT(!value->IsArray()); 790 // FIXME: Do we really need to special case Date and RegExp object? 791 // https://www.w3.org/Bugs/Public/show_bug.cgi?id=22806 792 if (!value->IsObject() || value->IsDate() || value->IsRegExp()) { 793 // The caller is responsible for reporting a TypeError. 794 return false; 795 } 796 797 v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(isolate, value)); 798 v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value); 799 v8::Local<v8::String> lengthSymbol = v8AtomicString(isolate, "length"); 800 801 // FIXME: The specification states that the length property should be used as fallback, if value 802 // is not a platform object that supports indexed properties. If it supports indexed properties, 803 // length should actually be one greater than values maximum indexed property index. 804 v8::TryCatch block; 805 v8::Local<v8::Value> lengthValue = object->Get(lengthSymbol); 806 if (block.HasCaught()) { 807 exceptionState.rethrowV8Exception(block.Exception()); 808 return false; 809 } 810 811 if (lengthValue->IsUndefined() || lengthValue->IsNull()) { 812 // The caller is responsible for reporting a TypeError. 813 return false; 814 } 815 816 uint32_t sequenceLength = lengthValue->Int32Value(); 817 if (block.HasCaught()) { 818 exceptionState.rethrowV8Exception(block.Exception()); 819 return false; 820 } 821 822 length = sequenceLength; 823 return true; 824 } 825 826 template<> 827 struct NativeValueTraits<String> { 828 static inline String nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState) 829 { 830 V8StringResource<> stringValue(value); 831 if (!stringValue.prepare(exceptionState)) 832 return String(); 833 return stringValue; 834 } 835 }; 836 837 template<> 838 struct NativeValueTraits<int> { 839 static inline int nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState) 840 { 841 return toInt32(value, exceptionState); 842 } 843 }; 844 845 template<> 846 struct NativeValueTraits<unsigned> { 847 static inline unsigned nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState) 848 { 849 return toUInt32(value, exceptionState); 850 } 851 }; 852 853 template<> 854 struct NativeValueTraits<float> { 855 static inline float nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState) 856 { 857 return toFloat(value, exceptionState); 858 } 859 }; 860 861 template<> 862 struct NativeValueTraits<double> { 863 static inline double nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState) 864 { 865 return toDouble(value, exceptionState); 866 } 867 }; 868 869 template<> 870 struct NativeValueTraits<v8::Handle<v8::Value> > { 871 static inline v8::Handle<v8::Value> nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState&) 872 { 873 return value; 874 } 875 }; 876 877 template<> 878 struct NativeValueTraits<ScriptValue> { 879 static inline ScriptValue nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState&) 880 { 881 return ScriptValue(ScriptState::current(isolate), value); 882 } 883 }; 884 885 template <typename T> 886 struct NativeValueTraits<Vector<T> > { 887 static inline Vector<T> nativeValue(const v8::Handle<v8::Value>& value, v8::Isolate* isolate, ExceptionState& exceptionState) 888 { 889 return toImplArray<T>(value, 0, isolate, exceptionState); 890 } 891 }; 892 893 v8::Isolate* toIsolate(ExecutionContext*); 894 v8::Isolate* toIsolate(LocalFrame*); 895 896 LocalDOMWindow* toDOMWindow(v8::Handle<v8::Value>, v8::Isolate*); 897 LocalDOMWindow* toDOMWindow(v8::Handle<v8::Context>); 898 LocalDOMWindow* enteredDOMWindow(v8::Isolate*); 899 LocalDOMWindow* currentDOMWindow(v8::Isolate*); 900 LocalDOMWindow* callingDOMWindow(v8::Isolate*); 901 ExecutionContext* toExecutionContext(v8::Handle<v8::Context>); 902 ExecutionContext* currentExecutionContext(v8::Isolate*); 903 ExecutionContext* callingExecutionContext(v8::Isolate*); 904 905 // Returns a V8 context associated with a ExecutionContext and a DOMWrapperWorld. 906 // This method returns an empty context if there is no frame or the frame is already detached. 907 v8::Local<v8::Context> toV8Context(ExecutionContext*, DOMWrapperWorld&); 908 // Returns a V8 context associated with a LocalFrame and a DOMWrapperWorld. 909 // This method returns an empty context if the frame is already detached. 910 v8::Local<v8::Context> toV8Context(LocalFrame*, DOMWrapperWorld&); 911 912 // Returns the frame object of the window object associated with 913 // a context, if the window is currently being displayed in the LocalFrame. 914 LocalFrame* toFrameIfNotDetached(v8::Handle<v8::Context>); 915 916 // If the current context causes out of memory, JavaScript setting 917 // is disabled and it returns true. 918 bool handleOutOfMemory(); 919 void crashIfV8IsDead(); 920 921 inline bool isUndefinedOrNull(v8::Handle<v8::Value> value) 922 { 923 return value->IsNull() || value->IsUndefined(); 924 } 925 v8::Handle<v8::Function> getBoundFunction(v8::Handle<v8::Function>); 926 927 // Attaches |environment| to |function| and returns it. 928 inline v8::Local<v8::Function> createClosure(v8::FunctionCallback function, v8::Handle<v8::Value> environment, v8::Isolate* isolate) 929 { 930 return v8::Function::New(isolate, function, environment); 931 } 932 933 // FIXME: This will be soon embedded in the generated code. 934 template<class Collection> static void indexedPropertyEnumerator(const v8::PropertyCallbackInfo<v8::Array>& info) 935 { 936 Collection* collection = toScriptWrappableBase(info.Holder())->toImpl<Collection>(); 937 int length = collection->length(); 938 v8::Handle<v8::Array> properties = v8::Array::New(info.GetIsolate(), length); 939 for (int i = 0; i < length; ++i) { 940 // FIXME: Do we need to check that the item function returns a non-null value for this index? 941 v8::Handle<v8::Integer> integer = v8::Integer::New(info.GetIsolate(), i); 942 properties->Set(integer, integer); 943 } 944 v8SetReturnValue(info, properties); 945 } 946 947 // These methods store hidden values into an array that is stored in the internal field of a DOM wrapper. 948 void addHiddenValueToArray(v8::Handle<v8::Object>, v8::Local<v8::Value>, int cacheIndex, v8::Isolate*); 949 void removeHiddenValueFromArray(v8::Handle<v8::Object>, v8::Local<v8::Value>, int cacheIndex, v8::Isolate*); 950 void moveEventListenerToNewWrapper(v8::Handle<v8::Object>, EventListener* oldValue, v8::Local<v8::Value> newValue, int cacheIndex, v8::Isolate*); 951 952 PassRefPtr<JSONValue> v8ToJSONValue(v8::Isolate*, v8::Handle<v8::Value>, int); 953 954 // Result values for platform object 'deleter' methods, 955 // http://www.w3.org/TR/WebIDL/#delete 956 enum DeleteResult { 957 DeleteSuccess, 958 DeleteReject, 959 DeleteUnknownProperty 960 }; 961 962 class V8IsolateInterruptor : public ThreadState::Interruptor { 963 public: 964 explicit V8IsolateInterruptor(v8::Isolate* isolate) : m_isolate(isolate) { } 965 966 static void onInterruptCallback(v8::Isolate* isolate, void* data) 967 { 968 reinterpret_cast<V8IsolateInterruptor*>(data)->onInterrupted(); 969 } 970 971 virtual void requestInterrupt() OVERRIDE 972 { 973 m_isolate->RequestInterrupt(&onInterruptCallback, this); 974 } 975 976 virtual void clearInterrupt() OVERRIDE 977 { 978 m_isolate->ClearInterrupt(); 979 } 980 981 private: 982 v8::Isolate* m_isolate; 983 }; 984 985 class V8TestingScope { 986 public: 987 explicit V8TestingScope(v8::Isolate*); 988 ScriptState* scriptState() const; 989 v8::Isolate* isolate() const; 990 ~V8TestingScope(); 991 992 private: 993 v8::HandleScope m_handleScope; 994 v8::Context::Scope m_contextScope; 995 RefPtr<ScriptState> m_scriptState; 996 }; 997 998 void GetDevToolsFunctionInfo(v8::Handle<v8::Function>, v8::Isolate*, int& scriptId, String& resourceName, int& lineNumber); 999 PassRefPtr<TraceEvent::ConvertableToTraceFormat> devToolsTraceEventData(ExecutionContext*, v8::Handle<v8::Function>, v8::Isolate*); 1000 1001 class V8RethrowTryCatchScope FINAL { 1002 public: 1003 explicit V8RethrowTryCatchScope(v8::TryCatch& block) : m_block(block) { } 1004 ~V8RethrowTryCatchScope() 1005 { 1006 // ReThrow() is a no-op if no exception has been caught, so always call. 1007 m_block.ReThrow(); 1008 } 1009 1010 private: 1011 v8::TryCatch& m_block; 1012 }; 1013 1014 // Returns an object representing {done: true, value: undefined}. 1015 v8::Local<v8::Value> v8DoneIteratorResult(v8::Isolate*); 1016 1017 // Returns an object representing {done: false, value: |value|}. 1018 v8::Local<v8::Value> v8IteratorResult(v8::Isolate*, v8::Handle<v8::Value>); 1019 template <typename T> 1020 v8::Local<v8::Value> v8IteratorResult(ScriptState* scriptState, const T& value) 1021 { 1022 return v8IteratorResult(scriptState->isolate(), V8ValueTraits<T>::toV8Value(value, scriptState->context()->Global(), scriptState->isolate())); 1023 } 1024 1025 } // namespace blink 1026 1027 #endif // V8Binding_h 1028