c5053ba9cc9fc5eb3de7c6ac8719fa4f1ca257b4
[WebKit-https.git] / Source / WebCore / bindings / v8 / V8Binding.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2008, 2009 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are
6  * met:
7  *
8  *     * Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  *     * Redistributions in binary form must reproduce the above
11  * copyright notice, this list of conditions and the following disclaimer
12  * in the documentation and/or other materials provided with the
13  * distribution.
14  *     * Neither the name of Google Inc. nor the names of its
15  * contributors may be used to endorse or promote products derived from
16  * this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29  */
30
31 #include "config.h"
32 #include "V8Binding.h"
33
34 #include "BindingVisitors.h"
35 #include "DOMStringList.h"
36 #include "Element.h"
37 #include "Frame.h"
38 #include "FrameLoader.h"
39 #include "FrameLoaderClient.h"
40 #include "QualifiedName.h"
41 #include "Settings.h"
42 #include "V8DOMStringList.h"
43 #include "V8DOMWindow.h"
44 #include "V8Element.h"
45 #include "V8NodeFilterCondition.h"
46 #include "V8ObjectConstructor.h"
47 #include "V8WorkerContext.h"
48 #include "V8XPathNSResolver.h"
49 #include "WebCoreMemoryInstrumentation.h"
50 #include "WorkerContext.h"
51 #include "WorkerScriptController.h"
52 #include "WorldContextHandle.h"
53 #include "XPathNSResolver.h"
54 #include <wtf/MathExtras.h>
55 #include <wtf/MainThread.h>
56 #include <wtf/StdLibExtras.h>
57 #include <wtf/Threading.h>
58 #include <wtf/text/AtomicString.h>
59 #include <wtf/text/CString.h>
60 #include <wtf/text/StringBuffer.h>
61 #include <wtf/text/StringHash.h>
62 #include <wtf/text/WTFString.h>
63
64 namespace WebCore {
65
66 v8::Handle<v8::Value> setDOMException(int exceptionCode, v8::Isolate* isolate)
67 {
68     return V8ThrowException::setDOMException(exceptionCode, isolate);
69 }
70
71 v8::Handle<v8::Value> throwError(V8ErrorType errorType, const char* message, v8::Isolate* isolate)
72 {
73     return V8ThrowException::throwError(errorType, message, isolate);
74 }
75
76 v8::Handle<v8::Value> throwError(v8::Local<v8::Value> exception, v8::Isolate* isolate)
77 {
78     return V8ThrowException::throwError(exception, isolate);
79 }
80
81 v8::Handle<v8::Value> throwTypeError(const char* message, v8::Isolate* isolate)
82 {
83     return V8ThrowException::throwTypeError(message, isolate);
84 }
85
86 v8::Handle<v8::Value> throwNotEnoughArgumentsError(v8::Isolate* isolate)
87 {
88     return V8ThrowException::throwNotEnoughArgumentsError(isolate);
89 }
90
91 v8::Handle<v8::Value> v8Array(PassRefPtr<DOMStringList> stringList, v8::Isolate* isolate)
92 {
93     if (!stringList)
94         return v8::Array::New();
95     v8::Local<v8::Array> result = v8::Array::New(stringList->length());
96     for (unsigned i = 0; i < stringList->length(); ++i)
97         result->Set(v8Integer(i, isolate), v8String(stringList->item(i), isolate));
98     return result;
99 }
100
101 PassRefPtr<NodeFilter> toNodeFilter(v8::Handle<v8::Value> callback)
102 {
103     return NodeFilter::create(V8NodeFilterCondition::create(callback));
104 }
105
106 int toInt32(v8::Handle<v8::Value> value, bool& ok)
107 {
108     ok = true;
109     
110     // Fast case. The value is already a 32-bit integer.
111     if (value->IsInt32())
112         return value->Int32Value();
113     
114     // Can the value be converted to a number?
115     v8::Local<v8::Number> numberObject = value->ToNumber();
116     if (numberObject.IsEmpty()) {
117         ok = false;
118         return 0;
119     }
120     
121     // Does the value convert to nan or to an infinity?
122     double numberValue = numberObject->Value();
123     if (std::isnan(numberValue) || std::isinf(numberValue)) {
124         ok = false;
125         return 0;
126     }
127     
128     // Can the value be converted to a 32-bit integer?
129     v8::Local<v8::Int32> intValue = value->ToInt32();
130     if (intValue.IsEmpty()) {
131         ok = false;
132         return 0;
133     }
134     
135     // Return the result of the int32 conversion.
136     return intValue->Value();
137 }
138     
139 uint32_t toUInt32(v8::Handle<v8::Value> value, bool& ok)
140 {
141     ok = true;
142
143     // Fast case. The value is already a 32-bit unsigned integer.
144     if (value->IsUint32())
145         return value->Uint32Value();
146
147     if (value->IsInt32()) {
148         int32_t result = value->Int32Value();
149         if (result >= 0)
150             return result;
151     }
152
153     // Can the value be converted to a number?
154     v8::Local<v8::Number> numberObject = value->ToNumber();
155     if (numberObject.IsEmpty()) {
156         ok = false;
157         return 0;
158     }
159
160     // Does the value convert to nan or to an infinity?
161     double numberValue = numberObject->Value();
162     if (std::isnan(numberValue) || std::isinf(numberValue)) {
163         ok = false;
164         return 0;
165     }
166
167     // Can the value be converted to a 32-bit unsigned integer?
168     v8::Local<v8::Uint32> uintValue = value->ToUint32();
169     if (uintValue.IsEmpty()) {
170         ok = false;
171         return 0;
172     }
173
174     return uintValue->Value();
175 }
176
177 v8::Persistent<v8::FunctionTemplate> createRawTemplate(v8::Isolate* isolate)
178 {
179     v8::HandleScope scope;
180     v8::Local<v8::FunctionTemplate> result = v8::FunctionTemplate::New(V8ObjectConstructor::isValidConstructorMode);
181     return v8::Persistent<v8::FunctionTemplate>::New(isolate, result);
182 }        
183
184 PassRefPtr<DOMStringList> toDOMStringList(v8::Handle<v8::Value> value, v8::Isolate* isolate)
185 {
186     v8::Local<v8::Value> v8Value(v8::Local<v8::Value>::New(value));
187
188     if (V8DOMStringList::HasInstance(v8Value, isolate)) {
189         RefPtr<DOMStringList> ret = V8DOMStringList::toNative(v8::Handle<v8::Object>::Cast(v8Value));
190         return ret.release();
191     }
192
193     if (!v8Value->IsArray())
194         return 0;
195
196     RefPtr<DOMStringList> ret = DOMStringList::create();
197     v8::Local<v8::Array> v8Array = v8::Local<v8::Array>::Cast(v8Value);
198     for (size_t i = 0; i < v8Array->Length(); ++i) {
199         v8::Local<v8::Value> indexedValue = v8Array->Get(v8Integer(i, isolate));
200         ret->append(toWebCoreString(indexedValue));
201     }
202     return ret.release();
203 }
204
205 PassRefPtr<XPathNSResolver> toXPathNSResolver(v8::Handle<v8::Value> value, v8::Isolate* isolate)
206 {
207     RefPtr<XPathNSResolver> resolver;
208     if (V8XPathNSResolver::HasInstance(value, isolate))
209         resolver = V8XPathNSResolver::toNative(v8::Handle<v8::Object>::Cast(value));
210     else if (value->IsObject())
211         resolver = V8CustomXPathNSResolver::create(value->ToObject(), isolate);
212     return resolver;
213 }
214
215 v8::Handle<v8::Object> toInnerGlobalObject(v8::Handle<v8::Context> context)
216 {
217     return v8::Handle<v8::Object>::Cast(context->Global()->GetPrototype());
218 }
219
220 DOMWindow* toDOMWindow(v8::Handle<v8::Context> context)
221 {
222     v8::Handle<v8::Object> global = context->Global();
223     ASSERT(!global.IsEmpty());
224     v8::Handle<v8::Object> window = global->FindInstanceInPrototypeChain(V8DOMWindow::GetTemplate(context->GetIsolate(), MainWorld));
225     if (!window.IsEmpty())
226         return V8DOMWindow::toNative(window);
227     window = global->FindInstanceInPrototypeChain(V8DOMWindow::GetTemplate(context->GetIsolate(), IsolatedWorld));
228     ASSERT(!window.IsEmpty());
229     return V8DOMWindow::toNative(window);
230 }
231
232 ScriptExecutionContext* toScriptExecutionContext(v8::Handle<v8::Context> context)
233 {
234     v8::Handle<v8::Object> global = context->Global();
235     v8::Handle<v8::Object> windowWrapper = global->FindInstanceInPrototypeChain(V8DOMWindow::GetTemplate(context->GetIsolate(), MainWorld));
236     if (!windowWrapper.IsEmpty())
237         return V8DOMWindow::toNative(windowWrapper)->scriptExecutionContext();
238     windowWrapper = global->FindInstanceInPrototypeChain(V8DOMWindow::GetTemplate(context->GetIsolate(), IsolatedWorld));
239     if (!windowWrapper.IsEmpty())
240         return V8DOMWindow::toNative(windowWrapper)->scriptExecutionContext();
241 #if ENABLE(WORKERS)
242     v8::Handle<v8::Object> workerWrapper = global->FindInstanceInPrototypeChain(V8WorkerContext::GetTemplate(context->GetIsolate(), WorkerWorld));
243     if (!workerWrapper.IsEmpty())
244         return V8WorkerContext::toNative(workerWrapper)->scriptExecutionContext();
245 #endif
246     // FIXME: Is this line of code reachable?
247     return 0;
248 }
249
250 Frame* toFrameIfNotDetached(v8::Handle<v8::Context> context)
251 {
252     DOMWindow* window = toDOMWindow(context);
253     if (window->isCurrentlyDisplayedInFrame())
254         return window->frame();
255     // We return 0 here because |context| is detached from the Frame. If we
256     // did return |frame| we could get in trouble because the frame could be
257     // navigated to another security origin.
258     return 0;
259 }
260
261 v8::Local<v8::Context> toV8Context(ScriptExecutionContext* context, const WorldContextHandle& worldContext)
262 {
263     if (context->isDocument()) {
264         if (Frame* frame = static_cast<Document*>(context)->frame())
265             return worldContext.adjustedContext(frame->script());
266 #if ENABLE(WORKERS)
267     } else if (context->isWorkerContext()) {
268         if (WorkerScriptController* script = static_cast<WorkerContext*>(context)->script())
269             return script->context();
270 #endif
271     }
272     return v8::Local<v8::Context>();
273 }
274
275 v8::Local<v8::Context> toV8Context(ScriptExecutionContext* context, DOMWrapperWorld* world)
276 {
277     if (context->isDocument()) {
278         if (Frame* frame = static_cast<Document*>(context)->frame()) {
279             // FIXME: Store the DOMWrapperWorld for the main world in the v8::Context so callers
280             // that are looking up their world with DOMWrapperWorld::isolatedWorld(v8::Context::GetCurrent())
281             // won't end up passing null here when later trying to get their v8::Context back.
282             if (!world)
283                 return frame->script()->mainWorldContext();
284             return v8::Local<v8::Context>::New(frame->script()->windowShell(world)->context());
285         }
286 #if ENABLE(WORKERS)
287     } else if (context->isWorkerContext()) {
288         if (WorkerScriptController* script = static_cast<WorkerContext*>(context)->script())
289             return script->context();
290 #endif
291     }
292     return v8::Local<v8::Context>();
293 }
294
295 bool handleOutOfMemory()
296 {
297     v8::Local<v8::Context> context = v8::Context::GetCurrent();
298
299     if (!context->HasOutOfMemoryException())
300         return false;
301
302     // Warning, error, disable JS for this frame?
303     Frame* frame = toFrameIfNotDetached(context);
304     if (!frame)
305         return true;
306
307     frame->script()->clearForOutOfMemory();
308
309 #if PLATFORM(CHROMIUM)
310     frame->loader()->client()->didExhaustMemoryAvailableForScript();
311 #endif
312
313     if (Settings* settings = frame->settings())
314         settings->setScriptEnabled(false);
315
316     return true;
317 }
318
319 v8::Local<v8::Value> handleMaxRecursionDepthExceeded()
320 {
321     throwError(v8RangeError, "Maximum call stack size exceeded.", v8::Isolate::GetCurrent());
322     return v8::Local<v8::Value>();
323 }
324
325 void crashIfV8IsDead()
326 {
327     if (v8::V8::IsDead()) {
328         // FIXME: We temporarily deal with V8 internal error situations
329         // such as out-of-memory by crashing the renderer.
330         CRASH();
331     }
332 }
333
334 WrapperWorldType worldType(v8::Isolate* isolate)
335 {
336     V8PerIsolateData* data = V8PerIsolateData::from(isolate);
337     // FIXME: Rename domDataStore() to workerDataStore().
338     if (!data->domDataStore())
339         return worldTypeInMainThread(isolate);
340     return WorkerWorld;
341 }
342
343 WrapperWorldType worldTypeInMainThread(v8::Isolate* isolate)
344 {
345     if (!DOMWrapperWorld::isolatedWorldsExist())
346         return MainWorld;
347     ASSERT(!v8::Context::GetEntered().IsEmpty());
348     DOMWrapperWorld* isolatedWorld = DOMWrapperWorld::isolatedWorld(v8::Context::GetEntered());
349     if (isolatedWorld)
350         return IsolatedWorld;
351     return MainWorld;
352 }
353
354 } // namespace WebCore