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
51namespace blink {
52
53class LocalDOMWindow;
54class Document;
55class EventListener;
56class ExecutionContext;
57class ExceptionState;
58class LocalFrame;
59class NodeFilter;
60class XPathNSResolver;
61
62namespace TraceEvent {
63class ConvertableToTraceFormat;
64}
65
66const int kMaxRecursionDepth = 22;
67
68// Helpers for throwing JavaScript TypeErrors for arity mismatches.
69void setArityTypeError(ExceptionState&, const char* valid, unsigned provided);
70v8::Local<v8::Value> createMinimumArityTypeErrorForMethod(const char* method, const char* type, unsigned expected, unsigned provided, v8::Isolate*);
71v8::Local<v8::Value> createMinimumArityTypeErrorForConstructor(const char* type, unsigned expected, unsigned provided, v8::Isolate*);
72void setMinimumArityTypeError(ExceptionState&, unsigned expected, unsigned provided);
73
74v8::ArrayBuffer::Allocator* v8ArrayBufferAllocator();
75
76template<typename CallbackInfo, typename V>
77inline void v8SetReturnValue(const CallbackInfo& info, V v)
78{
79    info.GetReturnValue().Set(v);
80}
81
82template<typename CallbackInfo>
83inline void v8SetReturnValueBool(const CallbackInfo& info, bool v)
84{
85    info.GetReturnValue().Set(v);
86}
87
88template<typename CallbackInfo>
89inline void v8SetReturnValueInt(const CallbackInfo& info, int v)
90{
91    info.GetReturnValue().Set(v);
92}
93
94template<typename CallbackInfo>
95inline void v8SetReturnValueUnsigned(const CallbackInfo& info, unsigned v)
96{
97    info.GetReturnValue().Set(v);
98}
99
100template<typename CallbackInfo>
101inline void v8SetReturnValueNull(const CallbackInfo& info)
102{
103    info.GetReturnValue().SetNull();
104}
105
106template<typename CallbackInfo>
107inline void v8SetReturnValueUndefined(const CallbackInfo& info)
108{
109    info.GetReturnValue().SetUndefined();
110}
111
112template<typename CallbackInfo>
113inline void v8SetReturnValueEmptyString(const CallbackInfo& info)
114{
115    info.GetReturnValue().SetEmptyString();
116}
117
118template <class CallbackInfo>
119inline 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
128template <class CallbackInfo>
129inline 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
138template <class CallbackInfo>
139inline 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.
151inline String toCoreString(v8::Handle<v8::String> value)
152{
153    return v8StringToWebCoreString<String>(value, Externalize);
154}
155
156inline String toCoreStringWithNullCheck(v8::Handle<v8::String> value)
157{
158    if (value.IsEmpty() || value->IsNull())
159        return String();
160    return toCoreString(value);
161}
162
163inline 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
170inline 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.
178inline 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.
189inline 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
196inline 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
202inline 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
208inline 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.
221template<typename T>
222v8::Handle<v8::Value> toV8NoInline(T* impl, v8::Handle<v8::Object> creationContext, v8::Isolate*);
223
224template <typename T>
225struct 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
234template<>
235struct 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
242template<>
243struct 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
250template<size_t n>
251struct 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
258template<size_t n>
259struct 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
266template<>
267struct 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
279template<>
280struct 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
287template<>
288struct 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
295template<>
296struct 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
303template<>
304struct 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
311template<>
312struct 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
319template<>
320struct 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
327template<>
328struct 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
335template<>
336struct 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.
344class V8NullType { };
345class V8UndefinedType { };
346
347template<>
348struct 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
355template<>
356struct 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
363template<>
364struct 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
371template<>
372struct 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
379template<>
380struct 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
387template<typename T, size_t inlineCapacity>
388v8::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
399template <typename T, size_t inlineCapacity, typename Allocator>
400struct 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
407template<typename T, size_t inlineCapacity>
408v8::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
419template <typename T, size_t inlineCapacity>
420struct 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.
428enum 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
437int8_t toInt8(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
438inline 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.
444int8_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
449uint8_t toUInt8(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
450inline 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.
456uint8_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
461int16_t toInt16(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
462inline 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.
468int16_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
473uint16_t toUInt16(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
474inline 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.
480uint16_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
485int32_t toInt32(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
486inline 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.
492int32_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
497uint32_t toUInt32(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
498inline 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.
504uint32_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
509int64_t toInt64(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
510inline 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.
516int64_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
521uint64_t toUInt64(v8::Handle<v8::Value>, IntegerConversionConfiguration, ExceptionState&);
522inline 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.
528uint64_t toUInt64(v8::Handle<v8::Value>);
529
530// Convert a value to a single precision float, which might fail.
531float toFloat(v8::Handle<v8::Value>, ExceptionState&);
532
533// Convert a value to a single precision float assuming the conversion cannot fail.
534inline 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.
540double toDouble(v8::Handle<v8::Value>, ExceptionState&);
541
542// Converts a value to a String, throwing if any code unit is outside 0-255.
543String toByteString(v8::Handle<v8::Value>, ExceptionState&);
544
545// Converts a value to a String, replacing unmatched UTF-16 surrogates with replacement characters.
546String toScalarValueString(v8::Handle<v8::Value>, ExceptionState&);
547
548inline v8::Handle<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate)
549{
550    return value ? v8::True(isolate) : v8::False(isolate);
551}
552
553inline 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
562inline 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.
569PassRefPtrWillBeRawPtr<NodeFilter> toNodeFilter(v8::Handle<v8::Value>, v8::Handle<v8::Object>, ScriptState*);
570PassRefPtrWillBeRawPtr<XPathNSResolver> toXPathNSResolver(v8::Handle<v8::Value>, v8::Isolate*);
571
572template<class T> struct NativeValueTraits;
573
574bool 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
578template <class T, class V8T>
579Vector<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
602template <class T, class V8T>
603Vector<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
617template <class T, class V8T>
618Vector<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
632template <class T, class V8T>
633WillBeHeapVector<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
666template <class T, class V8T>
667WillBeHeapVector<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
700template <class T, class V8T>
701HeapVector<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
736template <class T>
737Vector<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
767template <class T>
768Vector<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
785inline 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
826template<>
827struct 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
837template<>
838struct 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
845template<>
846struct 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
853template<>
854struct 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
861template<>
862struct 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
869template<>
870struct 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
877template<>
878struct 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
885template <typename T>
886struct 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
893v8::Isolate* toIsolate(ExecutionContext*);
894v8::Isolate* toIsolate(LocalFrame*);
895
896LocalDOMWindow* toDOMWindow(v8::Handle<v8::Value>, v8::Isolate*);
897LocalDOMWindow* toDOMWindow(v8::Handle<v8::Context>);
898LocalDOMWindow* enteredDOMWindow(v8::Isolate*);
899LocalDOMWindow* currentDOMWindow(v8::Isolate*);
900LocalDOMWindow* callingDOMWindow(v8::Isolate*);
901ExecutionContext* toExecutionContext(v8::Handle<v8::Context>);
902ExecutionContext* currentExecutionContext(v8::Isolate*);
903ExecutionContext* 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.
907v8::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.
910v8::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.
914LocalFrame* toFrameIfNotDetached(v8::Handle<v8::Context>);
915
916// If the current context causes out of memory, JavaScript setting
917// is disabled and it returns true.
918bool handleOutOfMemory();
919void crashIfV8IsDead();
920
921inline bool isUndefinedOrNull(v8::Handle<v8::Value> value)
922{
923    return value->IsNull() || value->IsUndefined();
924}
925v8::Handle<v8::Function> getBoundFunction(v8::Handle<v8::Function>);
926
927// Attaches |environment| to |function| and returns it.
928inline 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.
934template<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.
948void addHiddenValueToArray(v8::Handle<v8::Object>, v8::Local<v8::Value>, int cacheIndex, v8::Isolate*);
949void removeHiddenValueFromArray(v8::Handle<v8::Object>, v8::Local<v8::Value>, int cacheIndex, v8::Isolate*);
950void moveEventListenerToNewWrapper(v8::Handle<v8::Object>, EventListener* oldValue, v8::Local<v8::Value> newValue, int cacheIndex, v8::Isolate*);
951
952PassRefPtr<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
956enum DeleteResult {
957    DeleteSuccess,
958    DeleteReject,
959    DeleteUnknownProperty
960};
961
962class V8IsolateInterruptor : public ThreadState::Interruptor {
963public:
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
981private:
982    v8::Isolate* m_isolate;
983};
984
985class V8TestingScope {
986public:
987    explicit V8TestingScope(v8::Isolate*);
988    ScriptState* scriptState() const;
989    v8::Isolate* isolate() const;
990    ~V8TestingScope();
991
992private:
993    v8::HandleScope m_handleScope;
994    v8::Context::Scope m_contextScope;
995    RefPtr<ScriptState> m_scriptState;
996};
997
998void GetDevToolsFunctionInfo(v8::Handle<v8::Function>, v8::Isolate*, int& scriptId, String& resourceName, int& lineNumber);
999PassRefPtr<TraceEvent::ConvertableToTraceFormat> devToolsTraceEventData(ExecutionContext*, v8::Handle<v8::Function>, v8::Isolate*);
1000
1001class V8RethrowTryCatchScope FINAL {
1002public:
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
1010private:
1011    v8::TryCatch& m_block;
1012};
1013
1014// Returns an object representing {done: true, value: undefined}.
1015v8::Local<v8::Value> v8DoneIteratorResult(v8::Isolate*);
1016
1017// Returns an object representing {done: false, value: |value|}.
1018v8::Local<v8::Value> v8IteratorResult(v8::Isolate*, v8::Handle<v8::Value>);
1019template <typename T>
1020v8::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