Home | History | Annotate | Download | only in custom
      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 "V8HTMLAllCollection.h"
     36 #include "V8HTMLCollection.h"
     37 #include "V8Node.h"
     38 #include "V8NodeList.h"
     39 #include "V8Storage.h"
     40 #include "bindings/v8/BindingSecurity.h"
     41 #include "bindings/v8/ScriptDebugServer.h"
     42 #include "bindings/v8/ScriptValue.h"
     43 #include "bindings/v8/V8AbstractEventListener.h"
     44 #include "bindings/v8/V8Binding.h"
     45 #include "bindings/v8/V8HiddenPropertyName.h"
     46 #include "bindings/v8/V8ScriptRunner.h"
     47 #include "bindings/v8/custom/V8Float32ArrayCustom.h"
     48 #include "bindings/v8/custom/V8Float64ArrayCustom.h"
     49 #include "bindings/v8/custom/V8Int16ArrayCustom.h"
     50 #include "bindings/v8/custom/V8Int32ArrayCustom.h"
     51 #include "bindings/v8/custom/V8Int8ArrayCustom.h"
     52 #include "bindings/v8/custom/V8Uint16ArrayCustom.h"
     53 #include "bindings/v8/custom/V8Uint32ArrayCustom.h"
     54 #include "bindings/v8/custom/V8Uint8ArrayCustom.h"
     55 #include "bindings/v8/custom/V8Uint8ClampedArrayCustom.h"
     56 #include "core/inspector/InjectedScript.h"
     57 #include "core/inspector/InjectedScriptHost.h"
     58 #include "core/inspector/InspectorDOMAgent.h"
     59 #include "core/platform/JSONValues.h"
     60 #include "modules/webdatabase/Database.h"
     61 
     62 namespace WebCore {
     63 
     64 Node* InjectedScriptHost::scriptValueAsNode(ScriptValue value)
     65 {
     66     v8::HandleScope scope(v8::Isolate::GetCurrent());
     67     if (!value.isObject() || value.isNull())
     68         return 0;
     69     return V8Node::toNative(v8::Handle<v8::Object>::Cast(value.v8Value()));
     70 }
     71 
     72 ScriptValue InjectedScriptHost::nodeAsScriptValue(ScriptState* state, Node* node)
     73 {
     74     v8::HandleScope scope;
     75     v8::Local<v8::Context> context = state->context();
     76     v8::Context::Scope contextScope(context);
     77 
     78     if (!BindingSecurity::shouldAllowAccessToNode(node))
     79         return ScriptValue(v8::Null());
     80     return ScriptValue(toV8(node, v8::Handle<v8::Object>(), context->GetIsolate()));
     81 }
     82 
     83 void V8InjectedScriptHost::inspectedObjectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
     84 {
     85     if (args.Length() < 1)
     86         return;
     87 
     88     if (!args[0]->IsInt32()) {
     89         throwTypeError("argument has to be an integer", args.GetIsolate());
     90         return;
     91     }
     92 
     93     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
     94     InjectedScriptHost::InspectableObject* object = host->inspectedObject(args[0]->ToInt32()->Value());
     95     v8SetReturnValue(args, object->get(ScriptState::current()).v8Value());
     96 }
     97 
     98 void V8InjectedScriptHost::internalConstructorNameMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
     99 {
    100     if (args.Length() < 1)
    101         return;
    102 
    103     if (!args[0]->IsObject())
    104         return;
    105 
    106     v8SetReturnValue(args, args[0]->ToObject()->GetConstructorName());
    107 }
    108 
    109 void V8InjectedScriptHost::isHTMLAllCollectionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
    110 {
    111     if (args.Length() < 1)
    112         return;
    113 
    114     if (!args[0]->IsObject()) {
    115         v8SetReturnValue(args, false);
    116         return;
    117     }
    118 
    119     v8SetReturnValue(args, V8HTMLAllCollection::HasInstance(args[0], args.GetIsolate(), worldType(args.GetIsolate())));
    120 }
    121 
    122 void V8InjectedScriptHost::typeMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
    123 {
    124     if (args.Length() < 1)
    125         return;
    126 
    127     v8::Handle<v8::Value> value = args[0];
    128     if (value->IsString()) {
    129         v8SetReturnValue(args, v8::String::NewSymbol("string"));
    130         return;
    131     }
    132     if (value->IsArray()) {
    133         v8SetReturnValue(args, v8::String::NewSymbol("array"));
    134         return;
    135     }
    136     if (value->IsBoolean()) {
    137         v8SetReturnValue(args, v8::String::NewSymbol("boolean"));
    138         return;
    139     }
    140     if (value->IsNumber()) {
    141         v8SetReturnValue(args, v8::String::NewSymbol("number"));
    142         return;
    143     }
    144     if (value->IsDate()) {
    145         v8SetReturnValue(args, v8::String::NewSymbol("date"));
    146         return;
    147     }
    148     if (value->IsRegExp()) {
    149         v8SetReturnValue(args, v8::String::NewSymbol("regexp"));
    150         return;
    151     }
    152     WrapperWorldType currentWorldType = worldType(args.GetIsolate());
    153     if (V8Node::HasInstance(value, args.GetIsolate(), currentWorldType)) {
    154         v8SetReturnValue(args, v8::String::NewSymbol("node"));
    155         return;
    156     }
    157     if (V8NodeList::HasInstance(value, args.GetIsolate(), currentWorldType)) {
    158         v8SetReturnValue(args, v8::String::NewSymbol("array"));
    159         return;
    160     }
    161     if (V8HTMLCollection::HasInstance(value, args.GetIsolate(), currentWorldType)) {
    162         v8SetReturnValue(args, v8::String::NewSymbol("array"));
    163         return;
    164     }
    165     if (V8Int8Array::HasInstance(value, args.GetIsolate(), currentWorldType) || V8Int16Array::HasInstance(value, args.GetIsolate(), currentWorldType) || V8Int32Array::HasInstance(value, args.GetIsolate(), currentWorldType)) {
    166         v8SetReturnValue(args, v8::String::NewSymbol("array"));
    167         return;
    168     }
    169     if (V8Uint8Array::HasInstance(value, args.GetIsolate(), currentWorldType) || V8Uint16Array::HasInstance(value, args.GetIsolate(), currentWorldType) || V8Uint32Array::HasInstance(value, args.GetIsolate(), currentWorldType)) {
    170         v8SetReturnValue(args, v8::String::NewSymbol("array"));
    171         return;
    172     }
    173     if (V8Float32Array::HasInstance(value, args.GetIsolate(), currentWorldType) || V8Float64Array::HasInstance(value, args.GetIsolate(), currentWorldType)) {
    174         v8SetReturnValue(args, v8::String::NewSymbol("array"));
    175         return;
    176     }
    177     if (V8Uint8ClampedArray::HasInstance(value, args.GetIsolate(), currentWorldType)) {
    178         v8SetReturnValue(args, v8::String::NewSymbol("array"));
    179         return;
    180     }
    181 }
    182 
    183 void V8InjectedScriptHost::functionDetailsMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
    184 {
    185     if (args.Length() < 1)
    186         return;
    187 
    188     v8::Handle<v8::Value> value = args[0];
    189     if (!value->IsFunction())
    190         return;
    191     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(value);
    192     int lineNumber = function->GetScriptLineNumber();
    193     int columnNumber = function->GetScriptColumnNumber();
    194 
    195     v8::Local<v8::Object> location = v8::Object::New();
    196     location->Set(v8::String::NewSymbol("lineNumber"), v8::Integer::New(lineNumber, args.GetIsolate()));
    197     location->Set(v8::String::NewSymbol("columnNumber"), v8::Integer::New(columnNumber, args.GetIsolate()));
    198     location->Set(v8::String::NewSymbol("scriptId"), function->GetScriptId()->ToString());
    199 
    200     v8::Local<v8::Object> result = v8::Object::New();
    201     result->Set(v8::String::NewSymbol("location"), location);
    202 
    203     v8::Handle<v8::Value> name = function->GetName();
    204     if (name->IsString() && v8::Handle<v8::String>::Cast(name)->Length())
    205         result->Set(v8::String::NewSymbol("name"), name);
    206 
    207     v8::Handle<v8::Value> inferredName = function->GetInferredName();
    208     if (inferredName->IsString() && v8::Handle<v8::String>::Cast(inferredName)->Length())
    209         result->Set(v8::String::NewSymbol("inferredName"), inferredName);
    210 
    211     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
    212     ScriptDebugServer& debugServer = host->scriptDebugServer();
    213     v8::Handle<v8::Value> scopes = debugServer.functionScopes(function);
    214     if (!scopes.IsEmpty() && scopes->IsArray())
    215         result->Set(v8::String::NewSymbol("rawScopes"), scopes);
    216 
    217     v8SetReturnValue(args, result);
    218 }
    219 
    220 void V8InjectedScriptHost::getInternalPropertiesMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
    221 {
    222     if (args.Length() < 1)
    223         return;
    224 
    225     v8::Handle<v8::Object> object = v8::Handle<v8::Object>::Cast(args[0]);
    226 
    227     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
    228     ScriptDebugServer& debugServer = host->scriptDebugServer();
    229     v8SetReturnValue(args, debugServer.getInternalProperties(object));
    230 }
    231 
    232 static v8::Handle<v8::Array> getJSListenerFunctions(Document* document, const EventListenerInfo& listenerInfo)
    233 {
    234     v8::Local<v8::Array> result = v8::Array::New();
    235     size_t handlersCount = listenerInfo.eventListenerVector.size();
    236     for (size_t i = 0, outputIndex = 0; i < handlersCount; ++i) {
    237         RefPtr<EventListener> listener = listenerInfo.eventListenerVector[i].listener;
    238         if (listener->type() != EventListener::JSEventListenerType) {
    239             ASSERT_NOT_REACHED();
    240             continue;
    241         }
    242         V8AbstractEventListener* v8Listener = static_cast<V8AbstractEventListener*>(listener.get());
    243         v8::Local<v8::Context> context = toV8Context(document, v8Listener->world());
    244         // Hide listeners from other contexts.
    245         if (context != v8::Context::GetCurrent())
    246             continue;
    247         v8::Local<v8::Object> function;
    248         {
    249             // getListenerObject() may cause JS in the event attribute to get compiled, potentially unsuccessfully.
    250             v8::TryCatch block;
    251             function = v8Listener->getListenerObject(document);
    252             if (block.HasCaught())
    253                 continue;
    254         }
    255         ASSERT(!function.IsEmpty());
    256         v8::Local<v8::Object> listenerEntry = v8::Object::New();
    257         listenerEntry->Set(v8::String::NewSymbol("listener"), function);
    258         listenerEntry->Set(v8::String::NewSymbol("useCapture"), v8::Boolean::New(listenerInfo.eventListenerVector[i].useCapture));
    259         result->Set(v8::Number::New(outputIndex++), listenerEntry);
    260     }
    261     return result;
    262 }
    263 
    264 void V8InjectedScriptHost::getEventListenersMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
    265 {
    266     if (args.Length() < 1)
    267         return;
    268 
    269     v8::Local<v8::Value> value = args[0];
    270     if (!V8Node::HasInstance(value, args.GetIsolate(), worldType(args.GetIsolate())))
    271         return;
    272     Node* node = V8Node::toNative(value->ToObject());
    273     if (!node)
    274         return;
    275     // This can only happen for orphan DocumentType nodes.
    276     Document* document = node->document();
    277     if (!node->document())
    278         return;
    279 
    280     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
    281     Vector<EventListenerInfo> listenersArray;
    282     host->getEventListenersImpl(node, listenersArray);
    283 
    284     v8::Local<v8::Object> result = v8::Object::New();
    285     for (size_t i = 0; i < listenersArray.size(); ++i) {
    286         v8::Handle<v8::Array> listeners = getJSListenerFunctions(document, listenersArray[i]);
    287         if (!listeners->Length())
    288             continue;
    289         AtomicString eventType = listenersArray[i].eventType;
    290         result->Set(v8String(eventType, args.GetIsolate()), listeners);
    291     }
    292 
    293     v8SetReturnValue(args, result);
    294 }
    295 
    296 void V8InjectedScriptHost::inspectMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
    297 {
    298     if (args.Length() < 2)
    299         return;
    300 
    301     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
    302     ScriptValue object(args[0]);
    303     ScriptValue hints(args[1]);
    304     host->inspectImpl(object.toJSONValue(ScriptState::current()), hints.toJSONValue(ScriptState::current()));
    305 }
    306 
    307 void V8InjectedScriptHost::databaseIdMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
    308 {
    309     if (args.Length() > 0 && V8Database::HasInstance(args[0], args.GetIsolate(), worldType(args.GetIsolate()))) {
    310         Database* database = V8Database::toNative(v8::Handle<v8::Object>::Cast(args[0]));
    311         if (database) {
    312             InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder()); {
    313                 v8SetReturnValueStringOrUndefined(args, host->databaseIdImpl(database), args.GetIsolate());
    314                 return;
    315             }
    316         }
    317     }
    318 }
    319 
    320 void V8InjectedScriptHost::storageIdMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
    321 {
    322     if (args.Length() > 0 && V8Storage::HasInstance(args[0], args.GetIsolate(), worldType(args.GetIsolate()))) {
    323         Storage* storage = V8Storage::toNative(v8::Handle<v8::Object>::Cast(args[0]));
    324         if (storage) {
    325             InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
    326             v8SetReturnValueStringOrUndefined(args, host->storageIdImpl(storage), args.GetIsolate());
    327             return;
    328         }
    329     }
    330 }
    331 
    332 void V8InjectedScriptHost::evaluateMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
    333 {
    334     if (args.Length() < 1) {
    335         v8::ThrowException(v8::Exception::Error(v8::String::New("One argument expected.")));
    336         return;
    337     }
    338 
    339     v8::Handle<v8::String> expression = args[0]->ToString();
    340     if (expression.IsEmpty()) {
    341         v8::ThrowException(v8::Exception::Error(v8::String::New("The argument must be a string.")));
    342         return;
    343     }
    344 
    345     ASSERT(!v8::Context::GetCurrent().IsEmpty());
    346     v8::TryCatch tryCatch;
    347     v8::Handle<v8::Value> result = V8ScriptRunner::compileAndRunInternalScript(expression, args.GetIsolate());
    348     if (tryCatch.HasCaught()) {
    349         v8SetReturnValue(args, tryCatch.ReThrow());
    350         return;
    351     }
    352     v8SetReturnValue(args, result);
    353 }
    354 
    355 void V8InjectedScriptHost::setFunctionVariableValueMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
    356 {
    357     v8::Handle<v8::Value> functionValue = args[0];
    358     int scopeIndex = args[1]->Int32Value();
    359     String variableName = toWebCoreStringWithUndefinedOrNullCheck(args[2]);
    360     v8::Handle<v8::Value> newValue = args[3];
    361 
    362     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
    363     ScriptDebugServer& debugServer = host->scriptDebugServer();
    364     v8SetReturnValue(args, debugServer.setFunctionVariableValue(functionValue, scopeIndex, variableName, newValue));
    365 }
    366 
    367 static bool getFunctionLocation(const v8::FunctionCallbackInfo<v8::Value>& args, String* scriptId, int* lineNumber, int* columnNumber)
    368 {
    369     if (args.Length() < 1)
    370         return false;
    371     v8::Handle<v8::Value> fn = args[0];
    372     if (!fn->IsFunction())
    373         return false;
    374     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(fn);
    375     *lineNumber = function->GetScriptLineNumber();
    376     *columnNumber = function->GetScriptColumnNumber();
    377     if (*lineNumber == v8::Function::kLineOffsetNotFound || *columnNumber == v8::Function::kLineOffsetNotFound)
    378         return false;
    379     *scriptId = toWebCoreStringWithUndefinedOrNullCheck(function->GetScriptId());
    380     return true;
    381 }
    382 
    383 void V8InjectedScriptHost::debugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
    384 {
    385     String scriptId;
    386     int lineNumber;
    387     int columnNumber;
    388     if (!getFunctionLocation(args, &scriptId, &lineNumber, &columnNumber))
    389         return;
    390 
    391     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
    392     host->debugFunction(scriptId, lineNumber, columnNumber);
    393 }
    394 
    395 void V8InjectedScriptHost::undebugFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
    396 {
    397     String scriptId;
    398     int lineNumber;
    399     int columnNumber;
    400     if (!getFunctionLocation(args, &scriptId, &lineNumber, &columnNumber))
    401         return;
    402 
    403     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
    404     host->undebugFunction(scriptId, lineNumber, columnNumber);
    405 }
    406 
    407 void V8InjectedScriptHost::monitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
    408 {
    409     String scriptId;
    410     int lineNumber;
    411     int columnNumber;
    412     if (!getFunctionLocation(args, &scriptId, &lineNumber, &columnNumber))
    413         return;
    414 
    415     v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(args[0]);
    416     v8::Handle<v8::Value> name;
    417     if (args.Length() > 0 && args[0]->IsFunction()) {
    418         v8::Handle<v8::Function> function = v8::Handle<v8::Function>::Cast(args[0]);
    419         name = function->GetName();
    420         if (!name->IsString() || !v8::Handle<v8::String>::Cast(name)->Length())
    421             name = function->GetInferredName();
    422     }
    423 
    424     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
    425     host->monitorFunction(scriptId, lineNumber, columnNumber, toWebCoreStringWithUndefinedOrNullCheck(name));
    426 }
    427 
    428 void V8InjectedScriptHost::unmonitorFunctionMethodCustom(const v8::FunctionCallbackInfo<v8::Value>& args)
    429 {
    430     String scriptId;
    431     int lineNumber;
    432     int columnNumber;
    433     if (!getFunctionLocation(args, &scriptId, &lineNumber, &columnNumber))
    434         return;
    435 
    436     InjectedScriptHost* host = V8InjectedScriptHost::toNative(args.Holder());
    437     host->unmonitorFunction(scriptId, lineNumber, columnNumber);
    438 }
    439 
    440 } // namespace WebCore
    441