Upstream version 9.38.198.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / bindings / core / v8 / custom / V8InjectedScriptHostCustom.cpp
1 /*
2  * Copyright (C) 2007-2011 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 "bindings/core/v8/V8InjectedScriptHost.h"
33
34 #include "bindings/core/v8/BindingSecurity.h"
35 #include "bindings/core/v8/ExceptionState.h"
36 #include "bindings/core/v8/ScriptDebugServer.h"
37 #include "bindings/core/v8/ScriptValue.h"
38 #include "bindings/core/v8/V8AbstractEventListener.h"
39 #include "bindings/core/v8/V8Binding.h"
40 #include "bindings/core/v8/V8DOMTokenList.h"
41 #include "bindings/core/v8/V8EventTarget.h"
42 #include "bindings/core/v8/V8HTMLAllCollection.h"
43 #include "bindings/core/v8/V8HTMLCollection.h"
44 #include "bindings/core/v8/V8Node.h"
45 #include "bindings/core/v8/V8NodeList.h"
46 #include "bindings/core/v8/V8ScriptRunner.h"
47 #include "bindings/core/v8/V8Storage.h"
48 #include "bindings/core/v8/custom/V8Float32ArrayCustom.h"
49 #include "bindings/core/v8/custom/V8Float64ArrayCustom.h"
50 #include "bindings/core/v8/custom/V8Int16ArrayCustom.h"
51 #include "bindings/core/v8/custom/V8Int32ArrayCustom.h"
52 #include "bindings/core/v8/custom/V8Int8ArrayCustom.h"
53 #include "bindings/core/v8/custom/V8Uint16ArrayCustom.h"
54 #include "bindings/core/v8/custom/V8Uint32ArrayCustom.h"
55 #include "bindings/core/v8/custom/V8Uint8ArrayCustom.h"
56 #include "bindings/core/v8/custom/V8Uint8ClampedArrayCustom.h"
57 #include "core/events/EventTarget.h"
58 #include "core/frame/LocalDOMWindow.h"
59 #include "core/inspector/InjectedScript.h"
60 #include "core/inspector/InjectedScriptHost.h"
61 #include "core/inspector/InspectorDOMAgent.h"
62 #include "core/inspector/JavaScriptCallFrame.h"
63 #include "platform/JSONValues.h"
64
65 namespace blink {
66
67 Node* InjectedScriptHost::scriptValueAsNode(ScriptState* scriptState, ScriptValue value)
68 {
69     ScriptState::Scope scope(scriptState);
70     if (!value.isObject() || value.isNull())
71         return 0;
72     return V8Node::toNative(v8::Handle<v8::Object>::Cast(value.v8Value()));
73 }
74
75 ScriptValue InjectedScriptHost::nodeAsScriptValue(ScriptState* scriptState, Node* node)
76 {
77     ScriptState::Scope scope(scriptState);
78     v8::Isolate* isolate = scriptState->isolate();
79     ExceptionState exceptionState(ExceptionState::ExecutionContext, "nodeAsScriptValue", "InjectedScriptHost", scriptState->context()->Global(), isolate);
80     if (!BindingSecurity::shouldAllowAccessToNode(isolate, node, exceptionState))
81         return ScriptValue(scriptState, v8::Null(isolate));
82     return ScriptValue(scriptState, toV8(node, scriptState->context()->Global(), isolate));
83 }
84
85 void V8InjectedScriptHost::inspectedObjectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
86 {
87     if (info.Length() < 1)
88         return;
89
90     if (!info[0]->IsInt32()) {
91         V8ThrowException::throwTypeError("argument has to be an integer", info.GetIsolate());
92         return;
93     }
94
95     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
96     InjectedScriptHost::InspectableObject* object = host->inspectedObject(info[0]->ToInt32()->Value());
97     v8SetReturnValue(info, object->get(ScriptState::current(info.GetIsolate())).v8Value());
98 }
99
100 static v8::Handle<v8::String> functionDisplayName(v8::Handle<v8::Function> function)
101 {
102     v8::Handle<v8::Value> value = function->GetDisplayName();
103     if (value->IsString() && v8::Handle<v8::String>::Cast(value)->Length())
104         return v8::Handle<v8::String>::Cast(value);
105
106     value = function->GetName();
107     if (value->IsString() && v8::Handle<v8::String>::Cast(value)->Length())
108         return v8::Handle<v8::String>::Cast(value);
109
110     value = function->GetInferredName();
111     if (value->IsString() && v8::Handle<v8::String>::Cast(value)->Length())
112         return v8::Handle<v8::String>::Cast(value);
113
114     return v8::Handle<v8::String>();
115 }
116
117 void V8InjectedScriptHost::internalConstructorNameMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
118 {
119     if (info.Length() < 1)
120         return;
121
122     if (!info[0]->IsObject())
123         return;
124
125     v8::Local<v8::Object> object = info[0]->ToObject();
126     v8::Local<v8::String> result = object->GetConstructorName();
127
128     if (!result.IsEmpty() && toCoreStringWithUndefinedOrNullCheck(result) == "Object") {
129         v8::Local<v8::String> constructorSymbol = v8AtomicString(info.GetIsolate(), "constructor");
130         if (object->HasRealNamedProperty(constructorSymbol) && !object->HasRealNamedCallbackProperty(constructorSymbol)) {
131             v8::TryCatch tryCatch;
132             v8::Local<v8::Value> constructor = object->GetRealNamedProperty(constructorSymbol);
133             if (!constructor.IsEmpty() && constructor->IsFunction()) {
134                 v8::Local<v8::String> constructorName = functionDisplayName(v8::Handle<v8::Function>::Cast(constructor));
135                 if (!constructorName.IsEmpty() && !tryCatch.HasCaught())
136                     result = constructorName;
137             }
138         }
139     }
140
141     v8SetReturnValue(info, result);
142 }
143
144 void V8InjectedScriptHost::isHTMLAllCollectionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
145 {
146     if (info.Length() < 1)
147         return;
148
149     if (!info[0]->IsObject()) {
150         v8SetReturnValue(info, false);
151         return;
152     }
153
154     v8SetReturnValue(info, V8HTMLAllCollection::hasInstance(info[0], info.GetIsolate()));
155 }
156
157 void V8InjectedScriptHost::typeMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
158 {
159     if (info.Length() < 1)
160         return;
161     v8::Isolate* isolate = info.GetIsolate();
162
163     v8::Handle<v8::Value> value = info[0];
164     if (value->IsString()) {
165         v8SetReturnValue(info, v8AtomicString(isolate, "string"));
166         return;
167     }
168     if (value->IsArray() || value->IsTypedArray()) {
169         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
170         return;
171     }
172     if (value->IsBoolean()) {
173         v8SetReturnValue(info, v8AtomicString(isolate, "boolean"));
174         return;
175     }
176     if (value->IsNumber()) {
177         v8SetReturnValue(info, v8AtomicString(isolate, "number"));
178         return;
179     }
180     if (value->IsDate()) {
181         v8SetReturnValue(info, v8AtomicString(isolate, "date"));
182         return;
183     }
184     if (value->IsRegExp()) {
185         v8SetReturnValue(info, v8AtomicString(isolate, "regexp"));
186         return;
187     }
188     if (V8Node::hasInstance(value, isolate)) {
189         v8SetReturnValue(info, v8AtomicString(isolate, "node"));
190         return;
191     }
192     if (V8NodeList::hasInstance(value, isolate)
193         || V8DOMTokenList::hasInstance(value, isolate)
194         || V8HTMLCollection::hasInstance(value, isolate)
195         || V8HTMLAllCollection::hasInstance(value, isolate)) {
196         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
197         return;
198     }
199 }
200
201 void V8InjectedScriptHost::functionDetailsMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
202 {
203     if (info.Length() < 1)
204         return;
205
206     v8::Isolate* isolate = info.GetIsolate();
207
208     v8::Handle<v8::Value> value = info[0];
209     if (!value->IsFunction())
210         return;
211     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
212     int lineNumber = function->GetScriptLineNumber();
213     int columnNumber = function->GetScriptColumnNumber();
214
215     v8::Local<v8::Object> location = v8::Object::New(isolate);
216     location->Set(v8AtomicString(isolate, "lineNumber"), v8::Integer::New(isolate, lineNumber));
217     location->Set(v8AtomicString(isolate, "columnNumber"), v8::Integer::New(isolate, columnNumber));
218     location->Set(v8AtomicString(isolate, "scriptId"), v8::Integer::New(isolate, function->ScriptId())->ToString());
219
220     v8::Local<v8::Object> result = v8::Object::New(isolate);
221     result->Set(v8AtomicString(isolate, "location"), location);
222
223     v8::Handle<v8::String> name = functionDisplayName(function);
224     result->Set(v8AtomicString(isolate, "functionName"), name.IsEmpty() ? v8AtomicString(isolate, "") : name);
225
226     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
227     ScriptDebugServer& debugServer = host->scriptDebugServer();
228     v8::Handle<v8::Value> scopes = debugServer.functionScopes(function);
229     if (!scopes.IsEmpty() && scopes->IsArray())
230         result->Set(v8AtomicString(isolate, "rawScopes"), scopes);
231
232     v8SetReturnValue(info, result);
233 }
234
235 void V8InjectedScriptHost::getInternalPropertiesMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
236 {
237     if (info.Length() < 1)
238         return;
239
240     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(info[0]);
241
242     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
243     ScriptDebugServer& debugServer = host->scriptDebugServer();
244     v8SetReturnValue(info, debugServer.getInternalProperties(object));
245 }
246
247 static v8::Handle<v8::Array> getJSListenerFunctions(ExecutionContext* executionContext, const EventListenerInfo& listenerInfo, v8::Isolate* isolate)
248 {
249     v8::Local<v8::Array> result = v8::Array::New(isolate);
250     size_t handlersCount = listenerInfo.eventListenerVector.size();
251     for (size_t i = 0, outputIndex = 0; i < handlersCount; ++i) {
252         RefPtr<EventListener> listener = listenerInfo.eventListenerVector[i].listener;
253         if (listener->type() != EventListener::JSEventListenerType) {
254             ASSERT_NOT_REACHED();
255             continue;
256         }
257         V8AbstractEventListener* v8Listener = static_cast<V8AbstractEventListener*>(listener.get());
258         v8::Local<v8::Context> context = toV8Context(executionContext, v8Listener->world());
259         // Hide listeners from other contexts.
260         if (context != isolate->GetCurrentContext())
261             continue;
262         v8::Local<v8::Object> function;
263         {
264             // getListenerObject() may cause JS in the event attribute to get compiled, potentially unsuccessfully.
265             v8::TryCatch block;
266             function = v8Listener->getListenerObject(executionContext);
267             if (block.HasCaught())
268                 continue;
269         }
270         ASSERT(!function.IsEmpty());
271         v8::Local<v8::Object> listenerEntry = v8::Object::New(isolate);
272         listenerEntry->Set(v8AtomicString(isolate, "listener"), function);
273         listenerEntry->Set(v8AtomicString(isolate, "useCapture"), v8::Boolean::New(isolate, listenerInfo.eventListenerVector[i].useCapture));
274         result->Set(v8::Number::New(isolate, outputIndex++), listenerEntry);
275     }
276     return result;
277 }
278
279 void V8InjectedScriptHost::getEventListenersMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
280 {
281     if (info.Length() < 1)
282         return;
283
284
285     v8::Local<v8::Value> value = info[0];
286     EventTarget* target = V8EventTarget::toNativeWithTypeCheck(info.GetIsolate(), value);
287
288     // We need to handle a LocalDOMWindow specially, because a LocalDOMWindow wrapper exists on a prototype chain.
289     if (!target)
290         target = toDOMWindow(value, info.GetIsolate());
291
292     if (!target || !target->executionContext())
293         return;
294
295     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
296     Vector<EventListenerInfo> listenersArray;
297     host->getEventListenersImpl(target, listenersArray);
298
299     v8::Local<v8::Object> result = v8::Object::New(info.GetIsolate());
300     for (size_t i = 0; i < listenersArray.size(); ++i) {
301         v8::Handle<v8::Array> listeners = getJSListenerFunctions(target->executionContext(), listenersArray[i], info.GetIsolate());
302         if (!listeners->Length())
303             continue;
304         AtomicString eventType = listenersArray[i].eventType;
305         result->Set(v8String(info.GetIsolate(), eventType), listeners);
306     }
307
308     v8SetReturnValue(info, result);
309 }
310
311 void V8InjectedScriptHost::inspectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
312 {
313     if (info.Length() < 2)
314         return;
315
316     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
317     ScriptState* scriptState = ScriptState::current(info.GetIsolate());
318     ScriptValue object(scriptState, info[0]);
319     ScriptValue hints(scriptState, info[1]);
320     host->inspectImpl(object.toJSONValue(scriptState), hints.toJSONValue(scriptState));
321 }
322
323 void V8InjectedScriptHost::evalMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
324 {
325     v8::Isolate* isolate = info.GetIsolate();
326     if (info.Length() < 1) {
327         isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "One argument expected.")));
328         return;
329     }
330
331     v8::Handle<v8::String> expression = info[0]->ToString();
332     if (expression.IsEmpty()) {
333         isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "The argument must be a string.")));
334         return;
335     }
336
337     ASSERT(isolate->InContext());
338     v8::TryCatch tryCatch;
339     v8::Handle<v8::Value> result = V8ScriptRunner::compileAndRunInternalScript(expression, info.GetIsolate());
340     if (tryCatch.HasCaught()) {
341         v8SetReturnValue(info, tryCatch.ReThrow());
342         return;
343     }
344     v8SetReturnValue(info, result);
345 }
346
347 void V8InjectedScriptHost::evaluateWithExceptionDetailsMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
348 {
349     v8::Isolate* isolate = info.GetIsolate();
350     if (info.Length() < 1) {
351         isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "One argument expected.")));
352         return;
353     }
354
355     v8::Handle<v8::String> expression = info[0]->ToString();
356     if (expression.IsEmpty()) {
357         isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "The argument must be a string.")));
358         return;
359     }
360
361     ASSERT(isolate->InContext());
362     v8::TryCatch tryCatch;
363     v8::Handle<v8::Value> result = V8ScriptRunner::compileAndRunInternalScript(expression, info.GetIsolate());
364
365     v8::Local<v8::Object> wrappedResult = v8::Object::New(isolate);
366     if (tryCatch.HasCaught()) {
367         wrappedResult->Set(v8::String::NewFromUtf8(isolate, "result"), tryCatch.Exception());
368         wrappedResult->Set(v8::String::NewFromUtf8(isolate, "exceptionDetails"), JavaScriptCallFrame::createExceptionDetails(tryCatch.Message(), isolate));
369     } else {
370         wrappedResult->Set(v8::String::NewFromUtf8(isolate, "result"), result);
371         wrappedResult->Set(v8::String::NewFromUtf8(isolate, "exceptionDetails"), v8::Undefined(isolate));
372     }
373     v8SetReturnValue(info, wrappedResult);
374 }
375
376 void V8InjectedScriptHost::setFunctionVariableValueMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
377 {
378     v8::Handle<v8::Value> functionValue = info[0];
379     int scopeIndex = info[1]->Int32Value();
380     String variableName = toCoreStringWithUndefinedOrNullCheck(info[2]);
381     v8::Handle<v8::Value> newValue = info[3];
382
383     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
384     ScriptDebugServer& debugServer = host->scriptDebugServer();
385     v8SetReturnValue(info, debugServer.setFunctionVariableValue(functionValue, scopeIndex, variableName, newValue));
386 }
387
388 static bool getFunctionLocation(const v8::FunctionCallbackInfo<v8::Value>& info, String* scriptId, int* lineNumber, int* columnNumber)
389 {
390     if (info.Length() < 1)
391         return false;
392     v8::Handle<v8::Value> fn = info[0];
393     if (!fn->IsFunction())
394         return false;
395     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(fn);
396     *lineNumber = function->GetScriptLineNumber();
397     *columnNumber = function->GetScriptColumnNumber();
398     if (*lineNumber == v8::Function::kLineOffsetNotFound || *columnNumber == v8::Function::kLineOffsetNotFound)
399         return false;
400     *scriptId = String::number(function->ScriptId());
401     return true;
402 }
403
404 void V8InjectedScriptHost::debugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
405 {
406     String scriptId;
407     int lineNumber;
408     int columnNumber;
409     if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
410         return;
411
412     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
413     host->debugFunction(scriptId, lineNumber, columnNumber);
414 }
415
416 void V8InjectedScriptHost::undebugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
417 {
418     String scriptId;
419     int lineNumber;
420     int columnNumber;
421     if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
422         return;
423
424     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
425     host->undebugFunction(scriptId, lineNumber, columnNumber);
426 }
427
428 void V8InjectedScriptHost::monitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
429 {
430     String scriptId;
431     int lineNumber;
432     int columnNumber;
433     if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
434         return;
435
436     v8::Handle<v8::Value> name;
437     if (info.Length() > 0 && info[0]->IsFunction()) {
438         v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(info[0]);
439         name = function->GetName();
440         if (!name->IsString() || !v8::Handle<v8::String>::Cast(name)->Length())
441             name = function->GetInferredName();
442     }
443
444     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
445     host->monitorFunction(scriptId, lineNumber, columnNumber, toCoreStringWithUndefinedOrNullCheck(name));
446 }
447
448 void V8InjectedScriptHost::unmonitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
449 {
450     String scriptId;
451     int lineNumber;
452     int columnNumber;
453     if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
454         return;
455
456     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
457     host->unmonitorFunction(scriptId, lineNumber, columnNumber);
458 }
459
460 void V8InjectedScriptHost::callFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
461 {
462     if (info.Length() < 2 || info.Length() > 3 || !info[0]->IsFunction()) {
463         ASSERT_NOT_REACHED();
464         return;
465     }
466
467     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(info[0]);
468     v8::Handle<v8::Value> receiver = info[1];
469
470     if (info.Length() < 3 || info[2]->IsUndefined()) {
471         v8::Local<v8::Value> result = function->Call(receiver, 0, 0);
472         v8SetReturnValue(info, result);
473         return;
474     }
475
476     if (!info[2]->IsArray()) {
477         ASSERT_NOT_REACHED();
478         return;
479     }
480
481     v8::Handle<v8::Array> arguments = v8::Handle<v8::Array>::Cast(info[2]);
482     size_t argc = arguments->Length();
483     OwnPtr<v8::Handle<v8::Value>[]> argv = adoptArrayPtr(new v8::Handle<v8::Value>[argc]);
484     for (size_t i = 0; i < argc; ++i)
485         argv[i] = arguments->Get(i);
486
487     v8::Local<v8::Value> result = function->Call(receiver, argc, argv.get());
488     v8SetReturnValue(info, result);
489 }
490
491 void V8InjectedScriptHost::suppressWarningsAndCallFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
492 {
493     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
494     ScriptDebugServer& debugServer = host->scriptDebugServer();
495     debugServer.muteWarningsAndDeprecations();
496
497     callFunctionMethodCustom(info);
498
499     debugServer.unmuteWarningsAndDeprecations();
500 }
501
502 } // namespace blink