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>
v8SetReturnValue(const CallbackInfo & info,V v)77 inline void v8SetReturnValue(const CallbackInfo& info, V v)
78 {
79 info.GetReturnValue().Set(v);
80 }
81
82 template<typename CallbackInfo>
v8SetReturnValueBool(const CallbackInfo & info,bool v)83 inline void v8SetReturnValueBool(const CallbackInfo& info, bool v)
84 {
85 info.GetReturnValue().Set(v);
86 }
87
88 template<typename CallbackInfo>
v8SetReturnValueInt(const CallbackInfo & info,int v)89 inline void v8SetReturnValueInt(const CallbackInfo& info, int v)
90 {
91 info.GetReturnValue().Set(v);
92 }
93
94 template<typename CallbackInfo>
v8SetReturnValueUnsigned(const CallbackInfo & info,unsigned v)95 inline void v8SetReturnValueUnsigned(const CallbackInfo& info, unsigned v)
96 {
97 info.GetReturnValue().Set(v);
98 }
99
100 template<typename CallbackInfo>
v8SetReturnValueNull(const CallbackInfo & info)101 inline void v8SetReturnValueNull(const CallbackInfo& info)
102 {
103 info.GetReturnValue().SetNull();
104 }
105
106 template<typename CallbackInfo>
v8SetReturnValueUndefined(const CallbackInfo & info)107 inline void v8SetReturnValueUndefined(const CallbackInfo& info)
108 {
109 info.GetReturnValue().SetUndefined();
110 }
111
112 template<typename CallbackInfo>
v8SetReturnValueEmptyString(const CallbackInfo & info)113 inline void v8SetReturnValueEmptyString(const CallbackInfo& info)
114 {
115 info.GetReturnValue().SetEmptyString();
116 }
117
118 template <class CallbackInfo>
v8SetReturnValueString(const CallbackInfo & info,const String & string,v8::Isolate * isolate)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>
v8SetReturnValueStringOrNull(const CallbackInfo & info,const String & string,v8::Isolate * isolate)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>
v8SetReturnValueStringOrUndefined(const CallbackInfo & info,const String & string,v8::Isolate * isolate)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.
toCoreString(v8::Handle<v8::String> value)151 inline String toCoreString(v8::Handle<v8::String> value)
152 {
153 return v8StringToWebCoreString<String>(value, Externalize);
154 }
155
toCoreStringWithNullCheck(v8::Handle<v8::String> value)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
toCoreStringWithUndefinedOrNullCheck(v8::Handle<v8::String> value)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
toCoreAtomicString(v8::Handle<v8::String> value)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.
toCoreStringWithUndefinedOrNullCheck(v8::Handle<v8::Value> value)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.
v8String(v8::Isolate * isolate,const String & string)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
v8AtomicString(v8::Isolate * isolate,const char * str)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
v8AtomicString(v8::Isolate * isolate,const char * str,size_t length)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
v8Undefined()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 {
toV8ValueV8ValueTraits226 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 value’s 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