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