Foo::s_info should be Foo::info(), so that you can change how the s_info is actually...
[WebKit-https.git] / Source / WebCore / bindings / js / JSInjectedScriptHostCustom.cpp
1 /*
2  * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
3  * Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
4  * Copyright (C) 2010-2011 Google Inc. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions are
8  * met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above
13  * copyright notice, this list of conditions and the following disclaimer
14  * in the documentation and/or other materials provided with the
15  * distribution.
16  *     * Neither the name of Google Inc. nor the names of its
17  * contributors may be used to endorse or promote products derived from
18  * this software without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include "config.h"
34
35 #if ENABLE(INSPECTOR)
36
37 #include "JSInjectedScriptHost.h"
38
39 #if ENABLE(SQL_DATABASE)
40 #include "Database.h"
41 #include "JSDatabase.h"
42 #endif
43 #include "ExceptionCode.h"
44 #include "InjectedScriptHost.h"
45 #include "InspectorDOMAgent.h"
46 #include "InspectorDebuggerAgent.h"
47 #include "InspectorValues.h"
48 #include "JSEventListener.h"
49 #include "JSFloat32Array.h"
50 #include "JSFloat64Array.h"
51 #include "JSHTMLAllCollection.h"
52 #include "JSHTMLCollection.h"
53 #include "JSInt16Array.h"
54 #include "JSInt32Array.h"
55 #include "JSInt8Array.h"
56 #include "JSNode.h"
57 #include "JSNodeList.h"
58 #include "JSStorage.h"
59 #include "JSUint16Array.h"
60 #include "JSUint32Array.h"
61 #include "JSUint8Array.h"
62 #include "ScriptValue.h"
63 #include "Storage.h"
64 #include <parser/SourceCode.h>
65 #include <runtime/DateInstance.h>
66 #include <runtime/Error.h>
67 #include <runtime/JSArray.h>
68 #include <runtime/JSFunction.h>
69 #include <runtime/JSLock.h>
70 #include <runtime/ObjectConstructor.h>
71 #include <runtime/RegExpObject.h>
72
73 using namespace JSC;
74
75 namespace WebCore {
76
77 Node* InjectedScriptHost::scriptValueAsNode(ScriptValue value)
78 {
79     if (!value.isObject() || value.isNull())
80         return 0;
81     return toNode(value.jsValue());
82 }
83
84 ScriptValue InjectedScriptHost::nodeAsScriptValue(ScriptState* state, Node* node)
85 {
86     if (!shouldAllowAccessToNode(state, node))
87         return ScriptValue(state->vm(), jsNull());
88
89     JSLockHolder lock(state);
90     return ScriptValue(state->vm(), toJS(state, deprecatedGlobalObjectForPrototype(state), node));
91 }
92
93 JSValue JSInjectedScriptHost::inspectedObject(ExecState* exec)
94 {
95     if (exec->argumentCount() < 1)
96         return jsUndefined();
97
98     InjectedScriptHost::InspectableObject* object = impl()->inspectedObject(exec->argument(0).toInt32(exec));
99     if (!object)
100         return jsUndefined();
101
102     JSLockHolder lock(exec);
103     ScriptValue scriptValue = object->get(exec);
104     if (scriptValue.hasNoValue())
105         return jsUndefined();
106
107     return scriptValue.jsValue();
108 }
109
110 JSValue JSInjectedScriptHost::internalConstructorName(ExecState* exec)
111 {
112     if (exec->argumentCount() < 1)
113         return jsUndefined();
114
115     JSObject* thisObject = jsCast<JSObject*>(exec->argument(0).toThis(exec, NotStrictMode));
116     String result = thisObject->methodTable()->className(thisObject);
117     return jsStringWithCache(exec, result);
118 }
119
120 JSValue JSInjectedScriptHost::isHTMLAllCollection(ExecState* exec)
121 {
122     if (exec->argumentCount() < 1)
123         return jsUndefined();
124
125     JSValue value = exec->argument(0);
126     return jsBoolean(value.inherits(JSHTMLAllCollection::info()));
127 }
128
129 JSValue JSInjectedScriptHost::type(ExecState* exec)
130 {
131     if (exec->argumentCount() < 1)
132         return jsUndefined();
133
134     JSValue value = exec->argument(0);
135     if (value.isString())
136         return jsString(exec, String("string"));
137     if (value.inherits(JSArray::info()))
138         return jsString(exec, String("array"));
139     if (value.isBoolean())
140         return jsString(exec, String("boolean"));
141     if (value.isNumber())
142         return jsString(exec, String("number"));
143     if (value.inherits(DateInstance::info()))
144         return jsString(exec, String("date"));
145     if (value.inherits(RegExpObject::info()))
146         return jsString(exec, String("regexp"));
147     if (value.inherits(JSNode::info()))
148         return jsString(exec, String("node"));
149     if (value.inherits(JSNodeList::info()))
150         return jsString(exec, String("array"));
151     if (value.inherits(JSHTMLCollection::info()))
152         return jsString(exec, String("array"));
153     if (value.inherits(JSInt8Array::info()) || value.inherits(JSInt16Array::info()) || value.inherits(JSInt32Array::info()))
154         return jsString(exec, String("array"));
155     if (value.inherits(JSUint8Array::info()) || value.inherits(JSUint16Array::info()) || value.inherits(JSUint32Array::info()))
156         return jsString(exec, String("array"));
157     if (value.inherits(JSFloat32Array::info()) || value.inherits(JSFloat64Array::info()))
158         return jsString(exec, String("array"));
159     return jsUndefined();
160 }
161
162 JSValue JSInjectedScriptHost::functionDetails(ExecState* exec)
163 {
164     if (exec->argumentCount() < 1)
165         return jsUndefined();
166     JSValue value = exec->argument(0);
167     if (!value.asCell()->inherits(JSFunction::info()))
168         return jsUndefined();
169     JSFunction* function = jsCast<JSFunction*>(value);
170
171     const SourceCode* sourceCode = function->sourceCode();
172     if (!sourceCode)
173         return jsUndefined();
174     int lineNumber = sourceCode->firstLine();
175     if (lineNumber)
176         lineNumber -= 1; // In the inspector protocol all positions are 0-based while in SourceCode they are 1-based
177     String scriptId = String::number(sourceCode->provider()->asID());
178
179     JSObject* location = constructEmptyObject(exec);
180     location->putDirect(exec->vm(), Identifier(exec, "lineNumber"), jsNumber(lineNumber));
181     location->putDirect(exec->vm(), Identifier(exec, "scriptId"), jsString(exec, scriptId));
182
183     JSObject* result = constructEmptyObject(exec);
184     result->putDirect(exec->vm(), Identifier(exec, "location"), location);
185     String name = function->name(exec);
186     if (!name.isEmpty())
187         result->putDirect(exec->vm(), Identifier(exec, "name"), jsStringWithCache(exec, name));
188     String displayName = function->displayName(exec);
189     if (!displayName.isEmpty())
190         result->putDirect(exec->vm(), Identifier(exec, "displayName"), jsStringWithCache(exec, displayName));
191     // FIXME: provide function scope data in "scopesRaw" property when JSC supports it.
192     //     https://bugs.webkit.org/show_bug.cgi?id=87192
193     return result;
194 }
195
196 JSValue JSInjectedScriptHost::getInternalProperties(ExecState*)
197 {
198     // FIXME: implement this. https://bugs.webkit.org/show_bug.cgi?id=94533
199     return jsUndefined();
200 }
201
202 static JSArray* getJSListenerFunctions(ExecState* exec, Document* document, const EventListenerInfo& listenerInfo)
203 {
204     JSArray* result = constructEmptyArray(exec, 0);
205     size_t handlersCount = listenerInfo.eventListenerVector.size();
206     for (size_t i = 0, outputIndex = 0; i < handlersCount; ++i) {
207         const JSEventListener* jsListener = JSEventListener::cast(listenerInfo.eventListenerVector[i].listener.get());
208         if (!jsListener) {
209             ASSERT_NOT_REACHED();
210             continue;
211         }
212         // Hide listeners from other contexts.
213         if (jsListener->isolatedWorld() != currentWorld(exec))
214             continue;
215         JSObject* function = jsListener->jsFunction(document);
216         if (!function)
217             continue;
218         JSObject* listenerEntry = constructEmptyObject(exec);
219         listenerEntry->putDirect(exec->vm(), Identifier(exec, "listener"), function);
220         listenerEntry->putDirect(exec->vm(), Identifier(exec, "useCapture"), jsBoolean(listenerInfo.eventListenerVector[i].useCapture));
221         result->putDirectIndex(exec, outputIndex++, JSValue(listenerEntry));
222     }
223     return result;
224 }
225
226 JSValue JSInjectedScriptHost::getEventListeners(ExecState* exec)
227 {
228     if (exec->argumentCount() < 1)
229         return jsUndefined();
230     JSValue value = exec->argument(0);
231     if (!value.isObject() || value.isNull())
232         return jsUndefined();
233     Node* node = toNode(value);
234     if (!node)
235         return jsUndefined();
236     // This can only happen for orphan DocumentType nodes.
237     Document* document = node->document();
238     if (!node->document())
239         return jsUndefined();
240
241     Vector<EventListenerInfo> listenersArray;
242     impl()->getEventListenersImpl(node, listenersArray);
243
244     JSObject* result = constructEmptyObject(exec);
245     for (size_t i = 0; i < listenersArray.size(); ++i) {
246         JSArray* listeners = getJSListenerFunctions(exec, document, listenersArray[i]);
247         if (!listeners->length())
248             continue;
249         AtomicString eventType = listenersArray[i].eventType;
250         result->putDirect(exec->vm(), Identifier(exec, eventType.impl()), JSValue(listeners));
251     }
252
253     return result;
254 }
255
256 JSValue JSInjectedScriptHost::inspect(ExecState* exec)
257 {
258     if (exec->argumentCount() >= 2) {
259         ScriptValue object(exec->vm(), exec->argument(0));
260         ScriptValue hints(exec->vm(), exec->argument(1));
261         impl()->inspectImpl(object.toInspectorValue(exec), hints.toInspectorValue(exec));
262     }
263     return jsUndefined();
264 }
265
266 JSValue JSInjectedScriptHost::databaseId(ExecState* exec)
267 {
268     if (exec->argumentCount() < 1)
269         return jsUndefined();
270 #if ENABLE(SQL_DATABASE)
271     Database* database = toDatabase(exec->argument(0));
272     if (database)
273         return jsStringWithCache(exec, impl()->databaseIdImpl(database));
274 #endif
275     return jsUndefined();
276 }
277
278 JSValue JSInjectedScriptHost::storageId(ExecState* exec)
279 {
280     if (exec->argumentCount() < 1)
281         return jsUndefined();
282     Storage* storage = toStorage(exec->argument(0));
283     if (storage)
284         return jsStringWithCache(exec, impl()->storageIdImpl(storage));
285     return jsUndefined();
286 }
287
288 JSValue JSInjectedScriptHost::evaluate(ExecState* exec) const
289 {
290     JSGlobalObject* globalObject = exec->lexicalGlobalObject();
291     return globalObject->evalFunction();
292 }
293
294 JSValue JSInjectedScriptHost::setFunctionVariableValue(JSC::ExecState* exec)
295 {
296     // FIXME: implement this. https://bugs.webkit.org/show_bug.cgi?id=107830
297     throwError(exec, createTypeError(exec, "Variable value mutation is not supported"));
298     return jsUndefined();
299 }
300
301 } // namespace WebCore
302
303 #endif // ENABLE(INSPECTOR)