Upstream version 5.34.104.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / 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 #include "V8InjectedScriptHost.h"
33
34 #include "V8Database.h"
35 #include "V8EventTarget.h"
36 #include "V8HTMLAllCollection.h"
37 #include "V8HTMLCollection.h"
38 #include "V8Node.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"
64
65 namespace WebCore {
66
67 Node* InjectedScriptHost::scriptValueAsNode(ScriptValue value)
68 {
69     v8::HandleScope scope(value.isolate());
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* state, Node* node)
76 {
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);
81
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);
86 }
87
88 void V8InjectedScriptHost::inspectedObjectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
89 {
90     if (info.Length() < 1)
91         return;
92
93     if (!info[0]->IsInt32()) {
94         throwTypeError("argument has to be an integer", info.GetIsolate());
95         return;
96     }
97
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());
101 }
102
103 void V8InjectedScriptHost::internalConstructorNameMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
104 {
105     if (info.Length() < 1)
106         return;
107
108     if (!info[0]->IsObject())
109         return;
110
111     v8SetReturnValue(info, info[0]->ToObject()->GetConstructorName());
112 }
113
114 void V8InjectedScriptHost::isHTMLAllCollectionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
115 {
116     if (info.Length() < 1)
117         return;
118
119     if (!info[0]->IsObject()) {
120         v8SetReturnValue(info, false);
121         return;
122     }
123
124     v8SetReturnValue(info, V8HTMLAllCollection::hasInstance(info[0], info.GetIsolate()));
125 }
126
127 void V8InjectedScriptHost::typeMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
128 {
129     if (info.Length() < 1)
130         return;
131     v8::Isolate* isolate = info.GetIsolate();
132
133     v8::Handle<v8::Value> value = info[0];
134     if (value->IsString()) {
135         v8SetReturnValue(info, v8AtomicString(isolate, "string"));
136         return;
137     }
138     if (value->IsArray()) {
139         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
140         return;
141     }
142     if (value->IsBoolean()) {
143         v8SetReturnValue(info, v8AtomicString(isolate, "boolean"));
144         return;
145     }
146     if (value->IsNumber()) {
147         v8SetReturnValue(info, v8AtomicString(isolate, "number"));
148         return;
149     }
150     if (value->IsDate()) {
151         v8SetReturnValue(info, v8AtomicString(isolate, "date"));
152         return;
153     }
154     if (value->IsRegExp()) {
155         v8SetReturnValue(info, v8AtomicString(isolate, "regexp"));
156         return;
157     }
158     if (V8Node::hasInstance(value, isolate)) {
159         v8SetReturnValue(info, v8AtomicString(isolate, "node"));
160         return;
161     }
162     if (V8NodeList::hasInstance(value, isolate)) {
163         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
164         return;
165     }
166     if (V8HTMLCollection::hasInstance(value, isolate)) {
167         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
168         return;
169     }
170     if (V8Int8Array::hasInstance(value, isolate) || V8Int16Array::hasInstance(value, isolate) || V8Int32Array::hasInstance(value, isolate)) {
171         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
172         return;
173     }
174     if (V8Uint8Array::hasInstance(value, isolate) || V8Uint16Array::hasInstance(value, isolate) || V8Uint32Array::hasInstance(value, isolate)) {
175         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
176         return;
177     }
178     if (V8Float32Array::hasInstance(value, isolate) || V8Float64Array::hasInstance(value, isolate)) {
179         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
180         return;
181     }
182     if (V8Uint8ClampedArray::hasInstance(value, isolate)) {
183         v8SetReturnValue(info, v8AtomicString(isolate, "array"));
184         return;
185     }
186 }
187
188 static bool setFunctionName(v8::Handle<v8::Object>& result, const v8::Handle<v8::Value>& value, v8::Isolate* isolate)
189 {
190     if (value->IsString() && v8::Handle<v8::String>::Cast(value)->Length()) {
191         result->Set(v8AtomicString(isolate, "functionName"), value);
192         return true;
193     }
194     return false;
195 }
196
197 void V8InjectedScriptHost::functionDetailsMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
198 {
199     if (info.Length() < 1)
200         return;
201
202     v8::Isolate* isolate = info.GetIsolate();
203
204     v8::Handle<v8::Value> value = info[0];
205     if (!value->IsFunction())
206         return;
207     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
208     int lineNumber = function->GetScriptLineNumber();
209     int columnNumber = function->GetScriptColumnNumber();
210
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());
215
216     v8::Local<v8::Object> result = v8::Object::New(isolate);
217     result->Set(v8AtomicString(isolate, "location"), location);
218
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, ""));
223
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);
229
230     v8SetReturnValue(info, result);
231 }
232
233 void V8InjectedScriptHost::getInternalPropertiesMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
234 {
235     if (info.Length() < 1)
236         return;
237
238     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(info[0]);
239
240     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
241     ScriptDebugServer& debugServer = host->scriptDebugServer();
242     v8SetReturnValue(info, debugServer.getInternalProperties(object));
243 }
244
245 static v8::Handle<v8::Array> getJSListenerFunctions(ExecutionContext* executionContext, const EventListenerInfo& listenerInfo, v8::Isolate* isolate)
246 {
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();
253             continue;
254         }
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())
259             continue;
260         v8::Local<v8::Object> function;
261         {
262             // getListenerObject() may cause JS in the event attribute to get compiled, potentially unsuccessfully.
263             v8::TryCatch block;
264             function = v8Listener->getListenerObject(executionContext);
265             if (block.HasCaught())
266                 continue;
267         }
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);
273     }
274     return result;
275 }
276
277 void V8InjectedScriptHost::getEventListenersMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
278 {
279     if (info.Length() < 1)
280         return;
281
282     EventTarget* target = 0;
283     v8::Local<v8::Value> value = info[0];
284
285     if (V8EventTarget::hasInstance(value, info.GetIsolate()))
286         target = V8EventTarget::toNative(value->ToObject());
287
288     // We need to handle a DOMWindow specially, because a DOMWindow 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     ScriptValue object(info[0], info.GetIsolate());
318     ScriptValue hints(info[1], info.GetIsolate());
319     host->inspectImpl(object.toJSONValue(ScriptState::current()), hints.toJSONValue(ScriptState::current()));
320 }
321
322 void V8InjectedScriptHost::evaluateMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
323 {
324     v8::Isolate* isolate = info.GetIsolate();
325     if (info.Length() < 1) {
326         isolate->ThrowException(v8::Exception::Error(v8::String::NewFromUtf8(isolate, "One argument expected.")));
327         return;
328     }
329
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.")));
333         return;
334     }
335
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());
341         return;
342     }
343     v8SetReturnValue(info, result);
344 }
345
346 void V8InjectedScriptHost::setFunctionVariableValueMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
347 {
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];
352
353     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
354     ScriptDebugServer& debugServer = host->scriptDebugServer();
355     v8SetReturnValue(info, debugServer.setFunctionVariableValue(functionValue, scopeIndex, variableName, newValue));
356 }
357
358 static bool getFunctionLocation(const v8::FunctionCallbackInfo<v8::Value>& info, String* scriptId, int* lineNumber, int* columnNumber)
359 {
360     if (info.Length() < 1)
361         return false;
362     v8::Handle<v8::Value> fn = info[0];
363     if (!fn->IsFunction())
364         return false;
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)
369         return false;
370     *scriptId = String::number(function->ScriptId());
371     return true;
372 }
373
374 void V8InjectedScriptHost::debugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
375 {
376     String scriptId;
377     int lineNumber;
378     int columnNumber;
379     if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
380         return;
381
382     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
383     host->debugFunction(scriptId, lineNumber, columnNumber);
384 }
385
386 void V8InjectedScriptHost::undebugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
387 {
388     String scriptId;
389     int lineNumber;
390     int columnNumber;
391     if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
392         return;
393
394     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
395     host->undebugFunction(scriptId, lineNumber, columnNumber);
396 }
397
398 void V8InjectedScriptHost::monitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
399 {
400     String scriptId;
401     int lineNumber;
402     int columnNumber;
403     if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
404         return;
405
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();
412     }
413
414     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
415     host->monitorFunction(scriptId, lineNumber, columnNumber, toCoreStringWithUndefinedOrNullCheck(name));
416 }
417
418 void V8InjectedScriptHost::unmonitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& info)
419 {
420     String scriptId;
421     int lineNumber;
422     int columnNumber;
423     if (!getFunctionLocation(info, &scriptId, &lineNumber, &columnNumber))
424         return;
425
426     InjectedScriptHost* host = V8InjectedScriptHost::toNative(info.Holder());
427     host->unmonitorFunction(scriptId, lineNumber, columnNumber);
428 }
429
430 } // namespace WebCore