a69e909e6fb2202cb09b0a2c124452fa59bc4777
[WebKit.git] / Source / WebCore / bindings / v8 / V8Binding.h
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 "BindingSecurity.h"
36 #include "DOMWrapperWorld.h"
37 #include "Document.h"
38 #include "NodeFilter.h"
39 #include "V8BindingMacros.h"
40 #include "V8DOMConfiguration.h"
41 #include "V8DOMWrapper.h"
42 #include "V8HiddenPropertyName.h"
43 #include "V8ObjectConstructor.h"
44 #include "V8PerIsolateData.h"
45 #include "V8StringResource.h"
46 #include "V8ThrowException.h"
47 #include "V8ValueCache.h"
48 #include <wtf/Noncopyable.h>
49 #include <wtf/text/AtomicString.h>
50 #include <v8.h>
51
52 namespace WebCore {
53
54     class DOMStringList;
55     class ScriptExecutionContext;
56     class WorldContextHandle;
57
58     const int kMaxRecursionDepth = 22;
59
60     // Schedule a DOM exception to be thrown, if the exception code is different
61     // from zero.
62     v8::Handle<v8::Value> setDOMException(int, v8::Isolate*);
63
64     // Schedule a JavaScript error to be thrown.
65     v8::Handle<v8::Value> throwError(V8ErrorType, const char*, v8::Isolate*);
66
67     // Schedule a JavaScript error to be thrown.
68     v8::Handle<v8::Value> throwError(v8::Local<v8::Value>, v8::Isolate*);
69
70     // A helper for throwing JavaScript TypeError.
71     v8::Handle<v8::Value> throwTypeError(const char*, v8::Isolate*);
72
73     // A helper for throwing JavaScript TypeError for not enough arguments.
74     v8::Handle<v8::Value> throwNotEnoughArgumentsError(v8::Isolate*);
75
76     // A fast accessor for v8::Null(isolate). isolate must not be 0.
77     // If isolate can be 0, use v8NullWithCheck().
78     inline v8::Handle<v8::Value> v8Null(v8::Isolate* isolate)
79     {
80         ASSERT(isolate);
81         return V8PerIsolateData::from(isolate)->v8Null();
82     }
83
84     // Since v8::Null(isolate) crashes if we pass a null isolate,
85     // we need to use v8NullWithCheck(isolate) if an isolate can be null.
86     //
87     // FIXME: Remove all null isolates from V8 bindings, and remove v8NullWithCheck(isolate).
88     inline v8::Handle<v8::Value> v8NullWithCheck(v8::Isolate* isolate)
89     {
90         return isolate ? v8Null(isolate) : v8::Handle<v8::Value>(v8::Null());
91     }
92
93     // Convert v8 types to a WTF::String. If the V8 string is not already
94     // an external string then it is transformed into an external string at this
95     // point to avoid repeated conversions.
96     //
97     // FIXME: Replace all the call sites with V8TRYCATCH_FOR_V8STRINGRESOURCE().
98     // Using this method will lead to a wrong behavior, because you cannot stop the
99     // execution when an exception is thrown inside stringResource.prepare().
100     inline String toWebCoreString(v8::Handle<v8::Value> value)
101     {
102         V8StringResource<> stringResource(value);
103         if (!stringResource.prepare())
104             return String();
105         return stringResource;
106     }
107
108     // FIXME: See the above comment.
109     inline String toWebCoreStringWithNullCheck(v8::Handle<v8::Value> value)
110     {
111         V8StringResource<WithNullCheck> stringResource(value);
112         if (!stringResource.prepare())
113             return String();
114         return stringResource;
115     }
116
117     // FIXME: See the above comment.
118     inline String toWebCoreStringWithUndefinedOrNullCheck(v8::Handle<v8::Value> value)
119     {
120         V8StringResource<WithUndefinedOrNullCheck> stringResource(value);
121         if (!stringResource.prepare())
122             return String();
123         return stringResource;
124     }
125
126     // FIXME: See the above comment.
127     inline AtomicString toWebCoreAtomicString(v8::Handle<v8::Value> value)
128     {
129         V8StringResource<> stringResource(value);
130         if (!stringResource.prepare())
131             return AtomicString();
132         return stringResource;
133     }
134
135     // FIXME: See the above comment.
136     inline AtomicString toWebCoreAtomicStringWithNullCheck(v8::Handle<v8::Value> value)
137     {
138         V8StringResource<WithNullCheck> stringResource(value);
139         if (!stringResource.prepare())
140             return AtomicString();
141         return stringResource;
142     }
143
144     // Convert a string to a V8 string.
145     // Return a V8 external string that shares the underlying buffer with the given
146     // WebCore string. The reference counting mechanism is used to keep the
147     // underlying buffer alive while the string is still live in the V8 engine.
148     inline v8::Handle<v8::String> v8String(const String& string, v8::Isolate* isolate, ReturnHandleType handleType = ReturnLocalHandle)
149     {
150         if (string.isNull())
151             return v8::String::Empty(isolate);
152         return V8PerIsolateData::from(isolate)->stringCache()->v8ExternalString(string.impl(), handleType, isolate);
153     }
154
155     inline v8::Handle<v8::Value> v8StringOrNull(const String& string, v8::Isolate* isolate, ReturnHandleType handleType = ReturnLocalHandle)
156     {
157         ASSERT(isolate);
158         if (string.isNull())
159             return v8Null(isolate);
160         return V8PerIsolateData::from(isolate)->stringCache()->v8ExternalString(string.impl(), handleType, isolate);
161     }
162
163     inline v8::Handle<v8::Value> v8StringOrUndefined(const String& string, v8::Isolate* isolate, ReturnHandleType handleType = ReturnLocalHandle)
164     {
165         ASSERT(isolate);
166         if (string.isNull())
167             return v8::Undefined(isolate);
168         return V8PerIsolateData::from(isolate)->stringCache()->v8ExternalString(string.impl(), handleType, isolate);
169     }
170
171     inline v8::Handle<v8::Integer> v8Integer(int value, v8::Isolate* isolate)
172     {
173         return V8PerIsolateData::from(isolate)->integerCache()->v8Integer(value, isolate);
174     }
175
176     inline v8::Handle<v8::Integer> v8UnsignedInteger(unsigned value, v8::Isolate* isolate)
177     {
178         ASSERT(isolate);
179         return V8PerIsolateData::from(isolate)->integerCache()->v8UnsignedInteger(value, isolate);
180     }
181
182     inline v8::Handle<v8::Value> v8Undefined()
183     {
184         return v8::Handle<v8::Value>();
185     }
186
187     template <class T>
188     struct V8ValueTraits {
189         static inline v8::Handle<v8::Value> arrayV8Value(const T& value, v8::Isolate* isolate)
190         {
191             return toV8(WTF::getPtr(value), v8::Handle<v8::Object>(), isolate);
192         }
193     };
194
195     template<>
196     struct V8ValueTraits<String> {
197         static inline v8::Handle<v8::Value> arrayV8Value(const String& value, v8::Isolate* isolate)
198         {
199             return v8String(value, isolate);
200         }
201     };
202
203     template<>
204     struct V8ValueTraits<unsigned long> {
205         static inline v8::Handle<v8::Value> arrayV8Value(const unsigned long& value, v8::Isolate* isolate)
206         {
207             return v8UnsignedInteger(value, isolate);
208         }
209     };
210
211     template<>
212     struct V8ValueTraits<float> {
213         static inline v8::Handle<v8::Value> arrayV8Value(const float& value, v8::Isolate*)
214         {
215             return v8::Number::New(value);
216         }
217     };
218
219     template<>
220     struct V8ValueTraits<double> {
221         static inline v8::Handle<v8::Value> arrayV8Value(const double& value, v8::Isolate*)
222         {
223             return v8::Number::New(value);
224         }
225     };
226
227     template<typename T>
228     v8::Handle<v8::Value> v8Array(const Vector<T>& iterator, v8::Isolate* isolate)
229     {
230         v8::Local<v8::Array> result = v8::Array::New(iterator.size());
231         int index = 0;
232         typename Vector<T>::const_iterator end = iterator.end();
233         typedef V8ValueTraits<T> TraitsType;
234         for (typename Vector<T>::const_iterator iter = iterator.begin(); iter != end; ++iter)
235             result->Set(v8Integer(index++, isolate), TraitsType::arrayV8Value(*iter, isolate));
236         return result;
237     }
238
239     v8::Handle<v8::Value> v8Array(PassRefPtr<DOMStringList>, v8::Isolate*);
240
241     template<class T> struct NativeValueTraits;
242
243     template<>
244     struct NativeValueTraits<String> {
245         static inline String nativeValue(const v8::Handle<v8::Value>& value)
246         {
247             return toWebCoreString(value);
248         }
249     };
250
251     template<>
252     struct NativeValueTraits<float> {
253         static inline float nativeValue(const v8::Handle<v8::Value>& value)
254         {
255             return static_cast<float>(value->NumberValue());
256         }
257     };
258
259     template<>
260     struct NativeValueTraits<double> {
261         static inline double nativeValue(const v8::Handle<v8::Value>& value)
262         {
263             return static_cast<double>(value->NumberValue());
264         }
265     };
266
267     template <class T, class V8T>
268     Vector<RefPtr<T> > toRefPtrNativeArray(v8::Handle<v8::Value> value, v8::Isolate* isolate)
269     {
270         if (!value->IsArray())
271             return Vector<RefPtr<T> >();
272
273         Vector<RefPtr<T> > result;
274         v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(value));
275         v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(v8Value);
276         size_t length = array->Length();
277         for (size_t i = 0; i < length; ++i) {
278             v8::Handle<v8::Value> element = array->Get(i);
279
280             if (V8T::HasInstance(element, isolate)) {
281                 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(element);
282                 result.append(V8T::toNative(object));
283             } else {
284                 throwTypeError("Invalid Array element type", isolate);
285                 return Vector<RefPtr<T> >();
286             }
287         }
288         return result;
289     }
290
291     template <class T>
292     Vector<T> toNativeArray(v8::Handle<v8::Value> value)
293     {
294         if (!value->IsArray())
295             return Vector<T>();
296
297         Vector<T> result;
298         typedef NativeValueTraits<T> TraitsType;
299         v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(value));
300         v8::Local<v8::Array> array = v8::Local<v8::Array>::Cast(v8Value);
301         size_t length = array->Length();
302         for (size_t i = 0; i < length; ++i)
303             result.append(TraitsType::nativeValue(array->Get(i)));
304         return result;
305     }
306
307     template <class T>
308     Vector<T> toNativeArguments(const v8::Arguments& args, int startIndex)
309     {
310         ASSERT(startIndex <= args.Length());
311         Vector<T> result;
312         typedef NativeValueTraits<T> TraitsType;
313         int length = args.Length();
314         for (int i = startIndex; i < length; ++i)
315             result.append(TraitsType::nativeValue(args[i]));
316         return result;
317     }
318
319     // Validates that the passed object is a sequence type per WebIDL spec
320     // http://www.w3.org/TR/2012/WD-WebIDL-20120207/#es-sequence
321     inline v8::Handle<v8::Value> toV8Sequence(v8::Handle<v8::Value> value, uint32_t& length, v8::Isolate* isolate)
322     {
323         if (!value->IsObject()) {
324             throwTypeError(0, isolate);
325             return v8Undefined();
326         }
327
328         v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(value));
329         v8::Local<v8::Object> object = v8::Local<v8::Object>::Cast(v8Value);
330
331         V8TRYCATCH(v8::Local<v8::Value>, lengthValue, object->Get(v8::String::NewSymbol("length")));
332
333         if (lengthValue->IsUndefined() || lengthValue->IsNull()) {
334             throwTypeError(0, isolate);
335             return v8Undefined();
336         }
337
338         V8TRYCATCH(uint32_t, sequenceLength, lengthValue->Int32Value());
339         length = sequenceLength;
340
341         return v8Value;
342     }
343
344     PassRefPtr<NodeFilter> toNodeFilter(v8::Handle<v8::Value>);
345
346     // Convert a value to a 32-bit integer.  The conversion fails if the
347     // value cannot be converted to an integer or converts to nan or to an infinity.
348     int toInt32(v8::Handle<v8::Value> value, bool& ok);
349
350     // Convert a value to a 32-bit integer assuming the conversion cannot fail.
351     inline int toInt32(v8::Handle<v8::Value> value)
352     {
353         bool ok;
354         return toInt32(value, ok);
355     }
356
357     // Convert a value to a 32-bit unsigned integer.  The conversion fails if the
358     // value cannot be converted to an unsigned integer or converts to nan or to an infinity.
359     uint32_t toUInt32(v8::Handle<v8::Value> value, bool& ok);
360
361     // Convert a value to a 32-bit unsigned integer assuming the conversion cannot fail.
362     inline uint32_t toUInt32(v8::Handle<v8::Value> value)
363     {
364         bool ok;
365         return toUInt32(value, ok);
366     }
367
368     inline float toFloat(v8::Local<v8::Value> value)
369     {
370         return static_cast<float>(value->NumberValue());
371     }
372
373     inline long long toInt64(v8::Local<v8::Value> value)
374     {
375         return static_cast<long long>(value->IntegerValue());
376     }
377
378     inline bool isUndefinedOrNull(v8::Handle<v8::Value> value)
379     {
380         return value->IsNull() || value->IsUndefined();
381     }
382
383     // Returns true if the provided object is to be considered a 'host object', as used in the
384     // HTML5 structured clone algorithm.
385     inline bool isHostObject(v8::Handle<v8::Object> object)
386     {
387         // If the object has any internal fields, then we won't be able to serialize or deserialize
388         // them; conveniently, this is also a quick way to detect DOM wrapper objects, because
389         // the mechanism for these relies on data stored in these fields. We should
390         // catch external array data as a special case.
391         return object->InternalFieldCount() || object->HasIndexedPropertiesInExternalArrayData();
392     }
393
394     inline v8::Handle<v8::Boolean> v8Boolean(bool value)
395     {
396         return value ? v8::True() : v8::False();
397     }
398
399     inline v8::Handle<v8::Boolean> v8Boolean(bool value, v8::Isolate* isolate)
400     {
401         return value ? v8::True(isolate) : v8::False(isolate);
402     }
403
404     // Since v8Boolean(value, isolate) crashes if we pass a null isolate,
405     // we need to use v8BooleanWithCheck(value, isolate) if an isolate can be null.
406     //
407     // FIXME: Remove all null isolates from V8 bindings, and remove v8BooleanWithCheck(value, isolate).
408     inline v8::Handle<v8::Boolean> v8BooleanWithCheck(bool value, v8::Isolate* isolate)
409     {
410         return isolate ? v8Boolean(value, isolate) : v8Boolean(value);
411     }
412
413     inline double toWebCoreDate(v8::Handle<v8::Value> object)
414     {
415         return (object->IsDate() || object->IsNumber()) ? object->NumberValue() : std::numeric_limits<double>::quiet_NaN();
416     }
417
418     inline v8::Handle<v8::Value> v8DateOrNull(double value, v8::Isolate* isolate)
419     {
420         ASSERT(isolate);
421         return isfinite(value) ? v8::Date::New(value) : v8NullWithCheck(isolate);
422     }
423
424     v8::Persistent<v8::FunctionTemplate> createRawTemplate(v8::Isolate*);
425
426     PassRefPtr<DOMStringList> toDOMStringList(v8::Handle<v8::Value>, v8::Isolate*);
427     PassRefPtr<XPathNSResolver> toXPathNSResolver(v8::Handle<v8::Value>, v8::Isolate*);
428
429     v8::Handle<v8::Object> toInnerGlobalObject(v8::Handle<v8::Context>);
430     DOMWindow* toDOMWindow(v8::Handle<v8::Context>);
431     ScriptExecutionContext* toScriptExecutionContext(v8::Handle<v8::Context>);
432
433     // Returns the context associated with a ScriptExecutionContext.
434     v8::Local<v8::Context> toV8Context(ScriptExecutionContext*, const WorldContextHandle&);
435
436     // Returns the frame object of the window object associated with
437     // a context, if the window is currently being displayed in the Frame.
438     Frame* toFrameIfNotDetached(v8::Handle<v8::Context>);
439
440     inline DOMWrapperWorld* worldForEnteredContext()
441     {
442         v8::Handle<v8::Context> context = v8::Context::GetEntered();
443         if (context.IsEmpty())
444             return 0;
445         return DOMWrapperWorld::getWorld(context);
446     }
447
448     // This is a slightly different version of worldForEnteredContext().
449     // The difference is just that worldForEnteredContextWithoutContextCheck()
450     // does not call assertContextHasCorrectPrototype() (which is enabled on
451     // Debug builds only). Because assertContextHasCorrectPrototype() crashes
452     // if it is called when a current context is not completely initialized,
453     // you have to use worldForEnteredContextWithoutContextCheck() if you need
454     // to get a DOMWrapperWorld while a current context is being initialized.
455     // See https://bugs.webkit.org/show_bug.cgi?id=108579#c15 for more details.
456     inline DOMWrapperWorld* worldForEnteredContextWithoutContextCheck()
457     {
458         v8::Handle<v8::Context> context = v8::Context::GetEntered();
459         if (context.IsEmpty())
460             return 0;
461         return DOMWrapperWorld::getWorldWithoutContextCheck(context);
462     }
463
464     // If the current context causes out of memory, JavaScript setting
465     // is disabled and it returns true.
466     bool handleOutOfMemory();
467     // FIXME: This should receive an Isolate.
468     v8::Local<v8::Value> handleMaxRecursionDepthExceeded();
469
470     void crashIfV8IsDead();
471
472 } // namespace WebCore
473
474 #endif // V8Binding_h