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 "V8InjectedScriptHost.h"
34 #include "V8Database.h"
35 #include "V8EventTarget.h"
36 #include "V8HTMLAllCollection.h"
37 #include "V8HTMLCollection.h"
39 #include "V8NodeList.h"
40 #include "V8Storage.h"
41 #include "bindings/v8/BindingSecurity.h"
42 #include "bindings/v8/ExceptionState.h"
43 #include "bindings/v8/ScriptDebugServer.h"
44 #include "bindings/v8/ScriptValue.h"
45 #include "bindings/v8/V8AbstractEventListener.h"
46 #include "bindings/v8/V8Binding.h"
47 #include "bindings/v8/V8ScriptRunner.h"
48 #include "bindings/v8/custom/V8Float32ArrayCustom.h"
49 #include "bindings/v8/custom/V8Float64ArrayCustom.h"
50 #include "bindings/v8/custom/V8Int16ArrayCustom.h"
51 #include "bindings/v8/custom/V8Int32ArrayCustom.h"
52 #include "bindings/v8/custom/V8Int8ArrayCustom.h"
53 #include "bindings/v8/custom/V8Uint16ArrayCustom.h"
54 #include "bindings/v8/custom/V8Uint32ArrayCustom.h"
55 #include "bindings/v8/custom/V8Uint8ArrayCustom.h"
56 #include "bindings/v8/custom/V8Uint8ClampedArrayCustom.h"
57 #include "core/events/EventTarget.h"
58 #include "core/frame/DOMWindow.h"
59 #include "core/inspector/InjectedScript.h"
60 #include "core/inspector/InjectedScriptHost.h"
61 #include "core/inspector/InspectorDOMAgent.h"
62 #include "modules/webdatabase/Database.h"
63 #include "platform/JSONValues.h"
67 Node* InjectedScriptHost::scriptValueAsNode(ScriptValue value)
69 v8::HandleScope scope(value.isolate());
70 if (!value.isObject() || value.isNull())
72 return V8Node::toNative(v8::Handle<v8::Object>::Cast(value.v8Value()));
75 ScriptValue InjectedScriptHost::nodeAsScriptValue(ScriptState* state, Node* node)
77 v8::Isolate* isolate = state->isolate();
78 v8::HandleScope scope(isolate);
79 v8::Local<v8::Context> context = state->context();
80 v8::Context::Scope contextScope(context);
82 ExceptionState exceptionState(v8::Handle<v8::Object>(), isolate);
83 if (!BindingSecurity::shouldAllowAccessToNode(isolate, node, exceptionState))
84 return ScriptValue(v8::Null(isolate), isolate);
85 return ScriptValue(toV8(node, v8::Handle<v8::Object>(), isolate), isolate);
88 void V8InjectedScriptHost::inspectedObjectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
90 if (info.Length() < 1)
93 if (!info[0]->IsInt32()) {
94 throwTypeError("argument has to be an integer", info.GetIsolate());
98 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
99 InjectedScriptHost::InspectableObject* object = host->inspectedObject(info[0]->ToInt32()->Value());
100 v8SetReturnValue(info, object->get(ScriptState::current()).v8Value());
103 void V8InjectedScriptHost::internalConstructorNameMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
105 if (info.Length() < 1)
108 if (!info[0]->IsObject())
111 v8SetReturnValue(info, info[0]->ToObject()->GetConstructorName());
114 void V8InjectedScriptHost::isHTMLAllCollectionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
116 if (info.Length() < 1)
119 if (!info[0]->IsObject()) {
120 v8SetReturnValue(info, false);
124 v8SetReturnValue(info, V8HTMLAllCollection::hasInstance(info[0], info.GetIsolate()));
127 void V8InjectedScriptHost::typeMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
129 if (info.Length() < 1)
131 v8::Isolate* isolate = info.GetIsolate();
133 v8::Handle<v8::Value> value = info[0];
134 if (value->IsString()) {
135 v8SetReturnValue(info, v8AtomicString(isolate, "string"));
138 if (value->IsArray()) {
139 v8SetReturnValue(info, v8AtomicString(isolate, "array"));
142 if (value->IsBoolean()) {
143 v8SetReturnValue(info, v8AtomicString(isolate, "boolean"));
146 if (value->IsNumber()) {
147 v8SetReturnValue(info, v8AtomicString(isolate, "number"));
150 if (value->IsDate()) {
151 v8SetReturnValue(info, v8AtomicString(isolate, "date"));
154 if (value->IsRegExp()) {
155 v8SetReturnValue(info, v8AtomicString(isolate, "regexp"));
158 if (V8Node::hasInstance(value, isolate)) {
159 v8SetReturnValue(info, v8AtomicString(isolate, "node"));
162 if (V8NodeList::hasInstance(value, isolate)) {
163 v8SetReturnValue(info, v8AtomicString(isolate, "array"));
166 if (V8HTMLCollection::hasInstance(value, isolate)) {
167 v8SetReturnValue(info, v8AtomicString(isolate, "array"));
170 if (V8Int8Array::hasInstance(value, isolate) || V8Int16Array::hasInstance(value, isolate) || V8Int32Array::hasInstance(value, isolate)) {
171 v8SetReturnValue(info, v8AtomicString(isolate, "array"));
174 if (V8Uint8Array::hasInstance(value, isolate) || V8Uint16Array::hasInstance(value, isolate) || V8Uint32Array::hasInstance(value, isolate)) {
175 v8SetReturnValue(info, v8AtomicString(isolate, "array"));
178 if (V8Float32Array::hasInstance(value, isolate) || V8Float64Array::hasInstance(value, isolate)) {
179 v8SetReturnValue(info, v8AtomicString(isolate, "array"));
182 if (V8Uint8ClampedArray::hasInstance(value, isolate)) {
183 v8SetReturnValue(info, v8AtomicString(isolate, "array"));
188 static bool setFunctionName(v8::Handle<v8::Object>& result, const v8::Handle<v8::Value>& value, v8::Isolate* isolate)
190 if (value->IsString() && v8::Handle<v8::String>::Cast(value)->Length()) {
191 result->Set(v8AtomicString(isolate, "functionName"), value);
197 void V8InjectedScriptHost::functionDetailsMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
199 if (info.Length() < 1)
202 v8::Isolate* isolate = info.GetIsolate();
204 v8::Handle<v8::Value> value = info[0];
205 if (!value->IsFunction())
207 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
208 int lineNumber = function->GetScriptLineNumber();
209 int columnNumber = function->GetScriptColumnNumber();
211 v8::Local<v8::Object> location = v8::Object::New(isolate);
212 location->Set(v8AtomicString(isolate, "lineNumber"), v8::Integer::New(isolate, lineNumber));
213 location->Set(v8AtomicString(isolate, "columnNumber"), v8::Integer::New(isolate, columnNumber));
214 location->Set(v8AtomicString(isolate, "scriptId"), v8::Integer::New(isolate, function->ScriptId())->ToString());
216 v8::Local<v8::Object> result = v8::Object::New(isolate);
217 result->Set(v8AtomicString(isolate, "location"), location);
219 if (!setFunctionName(result, function->GetDisplayName(), isolate)
220 && !setFunctionName(result, function->GetName(), isolate)
221 && !setFunctionName(result, function->GetInferredName(), isolate))
222 result->Set(v8AtomicString(isolate, "functionName"), v8AtomicString(isolate, ""));
224 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
225 ScriptDebugServer& debugServer = host->scriptDebugServer();
226 v8::Handle<v8::Value> scopes = debugServer.functionScopes(function);
227 if (!scopes.IsEmpty() && scopes->IsArray())
228 result->Set(v8AtomicString(isolate, "rawScopes"), scopes);
230 v8SetReturnValue(info, result);
233 void V8InjectedScriptHost::getInternalPropertiesMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
235 if (info.Length() < 1)
238 v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(info[0]);
240 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
241 ScriptDebugServer& debugServer = host->scriptDebugServer();
242 v8SetReturnValue(info, debugServer.getInternalProperties(object));
245 static v8::Handle<v8::Array> getJSListenerFunctions(ExecutionContext* executionContext, const EventListenerInfo& listenerInfo, v8::Isolate* isolate)
247 v8::Local<v8::Array> result = v8::Array::New(isolate);
248 size_t handlersCount = listenerInfo.eventListenerVector.size();
249 for (size_t i = 0, outputIndex = 0; i < handlersCount; ++i) {
250 RefPtr<EventListener> listener = listenerInfo.eventListenerVector[i].listener;
251 if (listener->type() != EventListener::JSEventListenerType) {
252 ASSERT_NOT_REACHED();
255 V8AbstractEventListener* v8Listener = static_cast<V8AbstractEventListener*>(listener.get());
256 v8::Local<v8::Context> context = toV8Context(executionContext, v8Listener->world());
257 // Hide listeners from other contexts.
258 if (context != isolate->GetCurrentContext())
260 v8::Local<v8::Object> function;
262 // getListenerObject() may cause JS in the event attribute to get compiled, potentially unsuccessfully.
264 function = v8Listener->getListenerObject(executionContext);
265 if (block.HasCaught())
268 ASSERT(!function.IsEmpty());
269 v8::Local<v8::Object> listenerEntry = v8::Object::New(isolate);
270 listenerEntry->Set(v8AtomicString(isolate, "listener"), function);
271 listenerEntry->Set(v8AtomicString(isolate, "useCapture"), v8::Boolean::New(isolate, listenerInfo.eventListenerVector[i].useCapture));
272 result->Set(v8::Number::New(isolate, outputIndex++), listenerEntry);
277 void V8InjectedScriptHost::getEventListenersMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
279 if (info.Length() < 1)
282 EventTarget* target = 0;
283 v8::Local<v8::Value> value = info[0];
285 if (V8EventTarget::hasInstance(value, info.GetIsolate()))
286 target = V8EventTarget::toNative(value->ToObject());
288 // We need to handle a DOMWindow specially, because a DOMWindow 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 ScriptValue object(info[0], info.GetIsolate());
318 ScriptValue hints(info[1], info.GetIsolate());
319 host->inspectImpl(object.toJSONValue(ScriptState::current()), hints.toJSONValue(ScriptState::current()));
322 void V8InjectedScriptHost::evaluateMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
324 v8::Isolate* isolate = info.GetIsolate();
325 if (info.Length() < 1) {
326 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "One argument expected.")));
330 v8::Handle<v8::String> expression = info[0]->ToString();
331 if (expression.IsEmpty()) {
332 isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "The argument must be a string.")));
336 ASSERT(!isolate->GetCurrentContext().IsEmpty());
337 v8::TryCatch tryCatch;
338 v8::Handle<v8::Value> result = V8ScriptRunner::compileAndRunInternalScript(expression, info.GetIsolate());
339 if (tryCatch.HasCaught()) {
340 v8SetReturnValue(info, tryCatch.ReThrow());
343 v8SetReturnValue(info, result);
346 void V8InjectedScriptHost::setFunctionVariableValueMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
348 v8::Handle<v8::Value> functionValue = info[0];
349 int scopeIndex = info[1]->Int32Value();
350 String variableName = toCoreStringWithUndefinedOrNullCheck(info[2]);
351 v8::Handle<v8::Value> newValue = info[3];
353 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
354 ScriptDebugServer& debugServer = host->scriptDebugServer();
355 v8SetReturnValue(info, debugServer.setFunctionVariableValue(functionValue, scopeIndex, variableName, newValue));
358 static bool getFunctionLocation(const v8::FunctionCallbackInfo<v8::Value>& info, String* scriptId, int* lineNumber, int* columnNumber)
360 if (info.Length() < 1)
362 v8::Handle<v8::Value> fn = info[0];
363 if (!fn->IsFunction())
365 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(fn);
366 *lineNumber = function->GetScriptLineNumber();
367 *columnNumber = function->GetScriptColumnNumber();
368 if (*lineNumber == v8::Function::kLineOffsetNotFound || *columnNumber == v8::Function::kLineOffsetNotFound)
370 *scriptId = String::number(function->ScriptId());
374 void V8InjectedScriptHost::debugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
379 if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
382 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
383 host->debugFunction(scriptId, lineNumber, columnNumber);
386 void V8InjectedScriptHost::undebugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
391 if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
394 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
395 host->undebugFunction(scriptId, lineNumber, columnNumber);
398 void V8InjectedScriptHost::monitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
403 if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
406 v8::Handle<v8::Value> name;
407 if (info.Length() > 0 && info[0]->IsFunction()) {
408 v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(info[0]);
409 name = function->GetName();
410 if (!name->IsString() || !v8::Handle<v8::String>::Cast(name)->Length())
411 name = function->GetInferredName();
414 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
415 host->monitorFunction(scriptId, lineNumber, columnNumber, toCoreStringWithUndefinedOrNullCheck(name));
418 void V8InjectedScriptHost::unmonitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
423 if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
426 InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
427 host->unmonitorFunction(scriptId, lineNumber, columnNumber);
430 } // namespace WebCore