68cd8189fa943fb7fe22b663cf2687ab1e31f3ac
[WebKit-https.git] / Source / WebCore / bindings / 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 #if ENABLE(INSPECTOR)
33 #include "V8InjectedScriptHost.h"
34
35 #include "BindingState.h"
36 #include "Database.h"
37 #include "InjectedScript.h"
38 #include "InjectedScriptHost.h"
39 #include "InspectorDOMAgent.h"
40 #include "InspectorValues.h"
41 #include "ScriptDebugServer.h"
42 #include "ScriptValue.h"
43 #include "V8AbstractEventListener.h"
44 #include "V8Binding.h"
45 #include "V8Database.h"
46 #include "V8Float32Array.h"
47 #include "V8Float64Array.h"
48 #include "V8HTMLAllCollection.h"
49 #include "V8HTMLCollection.h"
50 #include "V8HiddenPropertyName.h"
51 #include "V8Int16Array.h"
52 #include "V8Int32Array.h"
53 #include "V8Int8Array.h"
54 #include "V8NodeList.h"
55 #include "V8Node.h"
56 #include "V8Storage.h"
57 #include "V8Uint16Array.h"
58 #include "V8Uint32Array.h"
59 #include "V8Uint8Array.h"
60 #include "V8Uint8ClampedArray.h"
61
62 namespace WebCore {
63
64 Node* InjectedScriptHost::scriptValueAsNode(ScriptValue value)
65 {
66     if (!value.isObject() || value.isNull())
67         return 0;
68     return V8Node::toNative(v8::Handle<v8::Object>::Cast(value.v8ValueRaw()));
69 }
70
71 ScriptValue InjectedScriptHost::nodeAsScriptValue(ScriptState* state, Node* node)
72 {
73     v8::HandleScope scope;
74     v8::Local<v8::Context> context = state->context();
75     v8::Context::Scope contextScope(context);
76
77     if (!BindingSecurity::shouldAllowAccessToNode(BindingState::instance(), node))
78         return ScriptValue(v8::Null());
79     return ScriptValue(toV8(node, v8::Handle<v8::Object>(), context->GetIsolate()));
80 }
81
82 v8::Handle<v8::Value> V8InjectedScriptHost::inspectedObjectMethodCustom(const v8::Arguments& args)
83 {
84     if (args.Length() < 1)
85         return v8::Undefined();
86
87     if (!args[0]->IsInt32())
88         return throwTypeError("argument has to be an integer", args.GetIsolate());
89
90     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
91     InjectedScriptHost::InspectableObject* object = host->inspectedObject(args[0]->ToInt32()->Value());
92     return object->get(ScriptState::current()).v8Value();
93 }
94
95 v8::Handle<v8::Value> V8InjectedScriptHost::internalConstructorNameMethodCustom(const v8::Arguments& args)
96 {
97     if (args.Length() < 1)
98         return v8::Undefined();
99
100     if (!args[0]->IsObject())
101         return v8::Undefined();
102
103     return args[0]->ToObject()->GetConstructorName();
104 }
105
106 v8::Handle<v8::Value> V8InjectedScriptHost::isHTMLAllCollectionMethodCustom(const v8::Arguments& args)
107 {
108     if (args.Length() < 1)
109         return v8::Undefined();
110
111     if (!args[0]->IsObject())
112         return v8Boolean(false, args.GetIsolate());
113
114     v8::HandleScope handleScope;
115     return v8::Boolean::New(V8HTMLAllCollection::HasInstance(args[0], args.GetIsolate()));
116 }
117
118 v8::Handle<v8::Value> V8InjectedScriptHost::typeMethodCustom(const v8::Arguments& args)
119 {
120     if (args.Length() < 1)
121         return v8::Undefined();
122
123     v8::Handle<v8::Value> value = args[0];
124     if (value->IsString())
125         return v8::String::NewSymbol("string");
126     if (value->IsArray())
127         return v8::String::NewSymbol("array");
128     if (value->IsBoolean())
129         return v8::String::NewSymbol("boolean");
130     if (value->IsNumber())
131         return v8::String::NewSymbol("number");
132     if (value->IsDate())
133         return v8::String::NewSymbol("date");
134     if (value->IsRegExp())
135         return v8::String::NewSymbol("regexp");
136     if (V8Node::HasInstance(value, args.GetIsolate()))
137         return v8::String::NewSymbol("node");
138     if (V8NodeList::HasInstance(value, args.GetIsolate()))
139         return v8::String::NewSymbol("array");
140     if (V8HTMLCollection::HasInstance(value, args.GetIsolate()))
141         return v8::String::NewSymbol("array");
142     if (V8Int8Array::HasInstance(value, args.GetIsolate()) || V8Int16Array::HasInstance(value, args.GetIsolate()) || V8Int32Array::HasInstance(value, args.GetIsolate()))
143         return v8::String::NewSymbol("array");
144     if (V8Uint8Array::HasInstance(value, args.GetIsolate()) || V8Uint16Array::HasInstance(value, args.GetIsolate()) || V8Uint32Array::HasInstance(value, args.GetIsolate()))
145         return v8::String::NewSymbol("array");
146     if (V8Float32Array::HasInstance(value, args.GetIsolate()) || V8Float64Array::HasInstance(value, args.GetIsolate()))
147         return v8::String::NewSymbol("array");
148     if (V8Uint8ClampedArray::HasInstance(value, args.GetIsolate()))
149         return v8::String::NewSymbol("array");
150     return v8::Undefined();
151 }
152
153 v8::Handle<v8::Value> V8InjectedScriptHost::functionDetailsMethodCustom(const v8::Arguments& args)
154 {
155     if (args.Length() < 1)
156         return v8::Undefined();
157
158     v8::HandleScope handleScope;
159
160     v8::Handle<v8::Value> value = args[0];
161     if (!value->IsFunction())
162         return v8::Undefined();
163     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
164     int lineNumber = function->GetScriptLineNumber();
165     int columnNumber = function->GetScriptColumnNumber();
166
167     v8::Local<v8::Object> location = v8::Object::New();
168     location->Set(v8::String::NewSymbol("lineNumber"), v8Integer(lineNumber, args.GetIsolate()));
169     location->Set(v8::String::NewSymbol("columnNumber"), v8Integer(columnNumber, args.GetIsolate()));
170     location->Set(v8::String::NewSymbol("scriptId"), function->GetScriptId()->ToString());
171
172     v8::Local<v8::Object> result = v8::Object::New();
173     result->Set(v8::String::NewSymbol("location"), location);
174
175     v8::Handle<v8::Value> name = function->GetName();
176     if (name->IsString() && v8::Handle<v8::String>::Cast(name)->Length())
177         result->Set(v8::String::NewSymbol("name"), name);
178
179     v8::Handle<v8::Value> inferredName = function->GetInferredName();
180     if (inferredName->IsString() && v8::Handle<v8::String>::Cast(inferredName)->Length())
181         result->Set(v8::String::NewSymbol("inferredName"), inferredName);
182
183     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
184     ScriptDebugServer& debugServer = host->scriptDebugServer();
185     v8::Handle<v8::Value> scopes = debugServer.functionScopes(function);
186     if (!scopes.IsEmpty() && scopes->IsArray())
187         result->Set(v8::String::NewSymbol("rawScopes"), scopes);
188
189     return result;
190 }
191
192 v8::Handle<v8::Value> V8InjectedScriptHost::getInternalPropertiesMethodCustom(const v8::Arguments& args)
193 {
194     if (args.Length() < 1)
195         return v8::Undefined();
196
197     v8::HandleScope handleScope;
198
199     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(args[0]);
200
201     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
202     ScriptDebugServer& debugServer = host->scriptDebugServer();
203     return debugServer.getInternalProperties(object);
204 }
205
206 static v8::Handle<v8::Array> getJSListenerFunctions(Document* document, const EventListenerInfo& listenerInfo)
207 {
208     v8::Local<v8::Array> result = v8::Array::New();
209     size_t handlersCount = listenerInfo.eventListenerVector.size();
210     for (size_t i = 0, outputIndex = 0; i < handlersCount; ++i) {
211         RefPtr<EventListener> listener = listenerInfo.eventListenerVector[i].listener;
212         if (listener->type() != EventListener::JSEventListenerType) {
213             ASSERT_NOT_REACHED();
214             continue;
215         }
216         V8AbstractEventListener* v8Listener = static_cast<V8AbstractEventListener*>(listener.get());
217         v8::Local<v8::Context> context = toV8Context(document, v8Listener->worldContext());
218         // Hide listeners from other contexts.
219         if (context != v8::Context::GetCurrent())
220             continue;
221         v8::Local<v8::Object> function;
222         {
223             // getListenerObject() may cause JS in the event attribute to get compiled, potentially unsuccessfully.
224             v8::TryCatch block;
225             function = v8Listener->getListenerObject(document);
226             if (block.HasCaught())
227                 continue;
228         }
229         ASSERT(!function.IsEmpty());
230         v8::Local<v8::Object> listenerEntry = v8::Object::New();
231         listenerEntry->Set(v8::String::NewSymbol("listener"), function);
232         listenerEntry->Set(v8::String::NewSymbol("useCapture"), v8::Boolean::New(listenerInfo.eventListenerVector[i].useCapture));
233         result->Set(v8::Number::New(outputIndex++), listenerEntry);
234     }
235     return result;
236 }
237
238 v8::Handle<v8::Value> V8InjectedScriptHost::getEventListenersMethodCustom(const v8::Arguments& args)
239 {
240     if (args.Length() < 1)
241         return v8::Undefined();
242
243     v8::HandleScope handleScope;
244
245     v8::Local<v8::Value> value = args[0];
246     if (!V8Node::HasInstance(value, args.GetIsolate()))
247         return v8::Undefined();
248     Node* node = V8Node::toNative(value->ToObject());
249     if (!node)
250         return v8::Undefined();
251     // This can only happen for orphan DocumentType nodes.
252     Document* document = node->document();
253     if (!node->document())
254         return v8::Undefined();
255
256     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
257     Vector<EventListenerInfo> listenersArray;
258     host->getEventListenersImpl(node, listenersArray);
259
260     v8::Local<v8::Object> result = v8::Object::New();
261     for (size_t i = 0; i < listenersArray.size(); ++i) {
262         v8::Handle<v8::Array> listeners = getJSListenerFunctions(document, listenersArray[i]);
263         if (!listeners->Length())
264             continue;
265         AtomicString eventType = listenersArray[i].eventType;
266         result->Set(v8String(eventType, args.GetIsolate()), listeners);
267     }
268
269     return result;
270 }
271
272 v8::Handle<v8::Value> V8InjectedScriptHost::inspectMethodCustom(const v8::Arguments& args)
273 {
274     if (args.Length() < 2)
275         return v8::Undefined();
276
277     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
278     ScriptValue object(args[0]);
279     ScriptValue hints(args[1]);
280     host->inspectImpl(object.toInspectorValue(ScriptState::current()), hints.toInspectorValue(ScriptState::current()));
281
282     return v8::Undefined();
283 }
284
285 v8::Handle<v8::Value> V8InjectedScriptHost::objectIdMethodCustom(const v8::Arguments& args)
286 {
287     if (args.Length() < 1)
288         return v8::Undefined();
289     v8::Handle<v8::Object> object = args[0]->ToObject();
290     if (object.IsEmpty())
291         return v8::Undefined();
292     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
293     unsigned id = host->objectId(ScriptObject(ScriptState::current(), object));
294     return v8::Number::New(id);
295 }
296
297 v8::Handle<v8::Value> V8InjectedScriptHost::releaseObjectIdMethodCustom(const v8::Arguments& args)
298 {
299     if (args.Length() < 1)
300         return v8::Undefined();
301     v8::Handle<v8::Object> object = args[0]->ToObject();
302     if (object.IsEmpty())
303         return v8::Undefined();
304     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
305     unsigned id = host->releaseObjectId(ScriptObject(ScriptState::current(), object));
306     return v8::Number::New(id);
307 }
308
309 v8::Handle<v8::Value> V8InjectedScriptHost::databaseIdMethodCustom(const v8::Arguments& args)
310 {
311     if (args.Length() < 1)
312         return v8::Undefined();
313 #if ENABLE(SQL_DATABASE)
314     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
315     Database* database = V8Database::toNative(v8::Handle<v8::Object>::Cast(args[0]));
316     if (database)
317         return v8StringOrUndefined(host->databaseIdImpl(database), args.GetIsolate());
318 #endif
319     return v8::Undefined();
320 }
321
322 v8::Handle<v8::Value> V8InjectedScriptHost::storageIdMethodCustom(const v8::Arguments& args)
323 {
324     if (args.Length() < 1)
325         return v8::Undefined();
326     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
327     Storage* storage = V8Storage::toNative(v8::Handle<v8::Object>::Cast(args[0]));
328     if (storage)
329         return v8StringOrUndefined(host->storageIdImpl(storage), args.GetIsolate());
330     return v8::Undefined();
331 }
332
333 v8::Handle<v8::Value> V8InjectedScriptHost::evaluateMethodCustom(const v8::Arguments& args)
334 {
335     if (args.Length() < 1)
336         return v8::ThrowException(v8::Exception::Error(v8::String::New("One argument expected.")));
337
338     v8::Handle<v8::String> expression = args[0]->ToString();
339     if (expression.IsEmpty())
340         return v8::ThrowException(v8::Exception::Error(v8::String::New("The argument must be a string.")));
341
342     v8::Handle<v8::Script> script = v8::Script::Compile(expression);
343     if (script.IsEmpty()) // Return immediately in case of exception to let the caller handle it.
344         return v8::Handle<v8::Value>();
345     return script->Run();
346 }
347
348 v8::Handle<v8::Value> V8InjectedScriptHost::setFunctionVariableValueMethodCustom(const v8::Arguments& args)
349 {
350     v8::Handle<v8::Value> functionValue = args[0];
351     int scopeIndex = args[1]->Int32Value();
352     String variableName = toWebCoreStringWithUndefinedOrNullCheck(args[2]);
353     v8::Handle<v8::Value> newValue = args[3];
354
355     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
356     ScriptDebugServer& debugServer = host->scriptDebugServer();
357     return debugServer.setFunctionVariableValue(functionValue, scopeIndex, variableName, newValue);
358 }
359
360
361 } // namespace WebCore
362
363 #endif // ENABLE(INSPECTOR)