2 * Copyright (C) 2007-2011 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
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
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.
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.
32 #include "bindings/core/v8/V8InjectedScriptHost.h"
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"
67 Node* InjectedScriptHost::scriptValueAsNode(ScriptState* scriptState, ScriptValue value)
69 ScriptState::Scope scope(scriptState);
70 if (!value.isObject() || value.isNull())
72 return V8Node::toNative(v8::Handle<v8::Object>::Cast(value.v8Value()));
75 ScriptValue InjectedScriptHost::nodeAsScriptValue(ScriptState* scriptState, Node* node)
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));
85 void V8InjectedScriptHost::inspectedObjectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
87 if (info.Length() < 1)
90 if (!info[0]->IsInt32()) {
91 V8ThrowException::throwTypeError("argument has to be an integer", info.GetIsolate());
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());
100 static v8::Handle<v8::String> functionDisplayName(v8::Handle<v8::Function> function)
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);
106 value = function->GetName();
107 if (value->IsString() && v8::Handle<v8::String>::Cast(value)->Length())
108 return v8::Handle<v8::String>::Cast(value);
110 value = function->GetInferredName();
111 if (value->IsString() && v8::Handle<v8::String>::Cast(value)->Length())
112 return v8::Handle<v8::String>::Cast(value);
114 return v8::Handle<v8::String>();
117 void V8InjectedScriptHost::internalConstructorNameMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
119 if (info.Length() < 1)
122 if (!info[0]->IsObject())
125 v8::Local<v8::Object> object = info[0]->ToObject();
126 v8::Local<v8::String> result = object->GetConstructorName();
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;
141 v8SetReturnValue(info, result);
144 void V8InjectedScriptHost::isHTMLAllCollectionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
146 if (info.Length() < 1)
149 if (!info[0]->IsObject()) {
150 v8SetReturnValue(info, false);
154 v8SetReturnValue(info, V8HTMLAllCollection::hasInstance(info[0], info.GetIsolate()));
157 void V8InjectedScriptHost::typeMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
159 if (info.Length() < 1)
161 v8::Isolate* isolate = info.GetIsolate();
163 v8::Handle<v8::Value> value = info[0];
164 if (value->IsString()) {
165 v8SetReturnValue(info, v8AtomicString(isolate, "string"));
168 if (value->IsArray() || value->IsTypedArray()) {
169 v8SetReturnValue(info, v8AtomicString(isolate, "array"));
172 if (value->IsBoolean()) {
173 v8SetReturnValue(info, v8AtomicString(isolate, "boolean"));
176 if (value->IsNumber()) {
177 v8SetReturnValue(info, v8AtomicString(isolate, "number"));
180 if (value->IsDate()) {
181 v8SetReturnValue(info, v8AtomicString(isolate, "date"));
184 if (value->IsRegExp()) {
185 v8SetReturnValue(info, v8AtomicString(isolate, "regexp"));
188 if (V8Node::hasInstance(value, isolate)) {
189 v8SetReturnValue(info, v8AtomicString(isolate, "node"));
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"));
201 void V8InjectedScriptHost::functionDetailsMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
203 if (info.Length() < 1)
206 v8::Isolate* isolate = info.GetIsolate();
208 v8::Handle<v8::Value> value = info[0];
209 if (!value->IsFunction())
211 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
212 int lineNumber = function->GetScriptLineNumber();
213 int columnNumber = function->GetScriptColumnNumber();
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());
220 v8::Local<v8::Object> result = v8::Object::New(isolate);
221 result->Set(v8AtomicString(isolate, "location"), location);
223 v8::Handle<v8::String> name = functionDisplayName(function);
224 result->Set(v8AtomicString(isolate, "functionName"), name.IsEmpty() ? v8AtomicString(isolate, "") : name);
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);
232 v8SetReturnValue(info, result);
235 void V8InjectedScriptHost::getInternalPropertiesMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
237 if (info.Length() < 1)
240 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(info[0]);
242 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
243 ScriptDebugServer& debugServer = host->scriptDebugServer();
244 v8SetReturnValue(info, debugServer.getInternalProperties(object));
247 static v8::Handle<v8::Array> getJSListenerFunctions(ExecutionContext* executionContext, const EventListenerInfo& listenerInfo, v8::Isolate* isolate)
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();
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())
262 v8::Local<v8::Object> function;
264 // getListenerObject() may cause JS in the event attribute to get compiled, potentially unsuccessfully.
266 function = v8Listener->getListenerObject(executionContext);
267 if (block.HasCaught())
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);
279 void V8InjectedScriptHost::getEventListenersMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
281 if (info.Length() < 1)
285 v8::Local<v8::Value> value = info[0];
286 EventTarget* target = V8EventTarget::toNativeWithTypeCheck(info.GetIsolate(), value);
288 // We need to handle a LocalDOMWindow specially, because a LocalDOMWindow wrapper exists on a prototype chain.
290 target = toDOMWindow(value, info.GetIsolate());
292 if (!target || !target->executionContext())
295 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
296 Vector<EventListenerInfo> listenersArray;
297 host->getEventListenersImpl(target, listenersArray);
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())
304 AtomicString eventType = listenersArray[i].eventType;
305 result->Set(v8String(info.GetIsolate(), eventType), listeners);
308 v8SetReturnValue(info, result);
311 void V8InjectedScriptHost::inspectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
313 if (info.Length() < 2)
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));
323 void V8InjectedScriptHost::evalMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
325 v8::Isolate* isolate = info.GetIsolate();
326 if (info.Length() < 1) {
327 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "One argument expected.")));
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.")));
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());
344 v8SetReturnValue(info, result);
347 void V8InjectedScriptHost::evaluateWithExceptionDetailsMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
349 v8::Isolate* isolate = info.GetIsolate();
350 if (info.Length() < 1) {
351 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "One argument expected.")));
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.")));
361 ASSERT(isolate->InContext());
362 v8::TryCatch tryCatch;
363 v8::Handle<v8::Value> result = V8ScriptRunner::compileAndRunInternalScript(expression, info.GetIsolate());
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));
370 wrappedResult->Set(v8::String::NewFromUtf8(isolate, "result"), result);
371 wrappedResult->Set(v8::String::NewFromUtf8(isolate, "exceptionDetails"), v8::Undefined(isolate));
373 v8SetReturnValue(info, wrappedResult);
376 void V8InjectedScriptHost::setFunctionVariableValueMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
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];
383 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
384 ScriptDebugServer& debugServer = host->scriptDebugServer();
385 v8SetReturnValue(info, debugServer.setFunctionVariableValue(functionValue, scopeIndex, variableName, newValue));
388 static bool getFunctionLocation(const v8::FunctionCallbackInfo<v8::Value>& info, String* scriptId, int* lineNumber, int* columnNumber)
390 if (info.Length() < 1)
392 v8::Handle<v8::Value> fn = info[0];
393 if (!fn->IsFunction())
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)
400 *scriptId = String::number(function->ScriptId());
404 void V8InjectedScriptHost::debugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
409 if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
412 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
413 host->debugFunction(scriptId, lineNumber, columnNumber);
416 void V8InjectedScriptHost::undebugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
421 if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
424 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
425 host->undebugFunction(scriptId, lineNumber, columnNumber);
428 void V8InjectedScriptHost::monitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
433 if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
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();
444 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
445 host->monitorFunction(scriptId, lineNumber, columnNumber, toCoreStringWithUndefinedOrNullCheck(name));
448 void V8InjectedScriptHost::unmonitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
453 if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
456 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
457 host->unmonitorFunction(scriptId, lineNumber, columnNumber);
460 void V8InjectedScriptHost::callFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
462 if (info.Length() < 2 || info.Length() > 3 || !info[0]->IsFunction()) {
463 ASSERT_NOT_REACHED();
467 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(info[0]);
468 v8::Handle<v8::Value> receiver = info[1];
470 if (info.Length() < 3 || info[2]->IsUndefined()) {
471 v8::Local<v8::Value> result = function->Call(receiver, 0, 0);
472 v8SetReturnValue(info, result);
476 if (!info[2]->IsArray()) {
477 ASSERT_NOT_REACHED();
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);
487 v8::Local<v8::Value> result = function->Call(receiver, argc, argv.get());
488 v8SetReturnValue(info, result);
491 void V8InjectedScriptHost::suppressWarningsAndCallFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
493 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
494 ScriptDebugServer& debugServer = host->scriptDebugServer();
495 debugServer.muteWarningsAndDeprecations();
497 callFunctionMethodCustom(info);
499 debugServer.unmuteWarningsAndDeprecations();