blob: 307b7bd65d6f1e2804f03a2cbde05f92f2a21db4 [file] [log] [blame]
/*
* Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2008 Matt Lilek <webkit@mattlilek.com>
* Copyright (C) 2009 Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "config.h"
#include "JSInspectorBackend.h"
#include "Console.h"
#include "Cookie.h"
#include "CookieJar.h"
#if ENABLE(DATABASE)
#include "Database.h"
#include "JSDatabase.h"
#endif
#include "ExceptionCode.h"
#include "Frame.h"
#include "FrameLoader.h"
#include "InspectorBackend.h"
#include "InspectorController.h"
#include "InspectorResource.h"
#include "JSDOMWindow.h"
#include "JSInspectedObjectWrapper.h"
#include "JSInspectorCallbackWrapper.h"
#include "JSNode.h"
#include "JSRange.h"
#include "Node.h"
#include "Page.h"
#if ENABLE(DOM_STORAGE)
#include "Storage.h"
#include "JSStorage.h"
#endif
#include "TextIterator.h"
#include "VisiblePosition.h"
#include <runtime/JSArray.h>
#include <runtime/JSLock.h>
#include <wtf/Vector.h>
#if ENABLE(JAVASCRIPT_DEBUGGER)
#include "JavaScriptCallFrame.h"
#include "JavaScriptDebugServer.h"
#include "JavaScriptProfile.h"
#include "JSJavaScriptCallFrame.h"
#include <profiler/Profile.h>
#include <profiler/Profiler.h>
#endif
using namespace JSC;
namespace WebCore {
JSValue JSInspectorBackend::highlightDOMNode(JSC::ExecState* exec, const JSC::ArgList& args)
{
if (args.size() < 1)
return jsUndefined();
impl()->highlight(args.at(0).toInt32(exec));
return jsUndefined();
}
JSValue JSInspectorBackend::search(ExecState* exec, const ArgList& args)
{
if (args.size() < 2)
return jsUndefined();
Node* node = toNode(args.at(0));
if (!node)
return jsUndefined();
String target = args.at(1).toString(exec);
if (exec->hadException())
return jsUndefined();
MarkedArgumentBuffer result;
RefPtr<Range> searchRange(rangeOfContents(node));
ExceptionCode ec = 0;
do {
RefPtr<Range> resultRange(findPlainText(searchRange.get(), target, true, false));
if (resultRange->collapsed(ec))
break;
// A non-collapsed result range can in some funky whitespace cases still not
// advance the range's start position (4509328). Break to avoid infinite loop.
VisiblePosition newStart = endVisiblePosition(resultRange.get(), DOWNSTREAM);
if (newStart == startVisiblePosition(searchRange.get(), DOWNSTREAM))
break;
result.append(toJS(exec, resultRange.get()));
setStart(searchRange.get(), newStart);
} while (true);
return constructArray(exec, result);
}
#if ENABLE(DATABASE)
JSValue JSInspectorBackend::databaseTableNames(ExecState* exec, const ArgList& args)
{
if (args.size() < 1)
return jsUndefined();
JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(args.at(0));
if (!wrapper)
return jsUndefined();
Database* database = toDatabase(wrapper->unwrappedObject());
if (!database)
return jsUndefined();
MarkedArgumentBuffer result;
Vector<String> tableNames = database->tableNames();
unsigned length = tableNames.size();
for (unsigned i = 0; i < length; ++i)
result.append(jsString(exec, tableNames[i]));
return constructArray(exec, result);
}
#endif
JSValue JSInspectorBackend::inspectedWindow(ExecState*, const ArgList&)
{
InspectorController* ic = impl()->inspectorController();
if (!ic)
return jsUndefined();
JSDOMWindow* inspectedWindow = toJSDOMWindow(ic->inspectedPage()->mainFrame());
return JSInspectedObjectWrapper::wrap(inspectedWindow->globalExec(), inspectedWindow);
}
JSValue JSInspectorBackend::cookies(ExecState* exec, const ArgList&)
{
InspectorController* ic = impl()->inspectorController();
if (!ic)
return jsUndefined();
Document* document = ic->inspectedPage()->mainFrame()->document();
Vector<Cookie> cookies;
getRawCookies(document, document->cookieURL(), cookies);
MarkedArgumentBuffer result;
Identifier nameIdentifier(exec, "name");
Identifier valueIdentifier(exec, "value");
Identifier domainIdentifier(exec, "domain");
Identifier pathIdentifier(exec, "path");
Identifier expiresIdentifier(exec, "expires");
Identifier sizeIdentifier(exec, "size");
Identifier httpOnlyIdentifier(exec, "httpOnly");
Identifier secureIdentifier(exec, "secure");
Identifier sessionIdentifier(exec, "session");
unsigned length = cookies.size();
for (unsigned i = 0; i < length; ++i) {
const Cookie& cookie = cookies[i];
JSObject* cookieObject = constructEmptyObject(exec);
cookieObject->putDirect(nameIdentifier, jsString(exec, cookie.name));
cookieObject->putDirect(valueIdentifier, jsString(exec, cookie.value));
cookieObject->putDirect(domainIdentifier, jsString(exec, cookie.domain));
cookieObject->putDirect(pathIdentifier, jsString(exec, cookie.path));
cookieObject->putDirect(expiresIdentifier, jsNumber(exec, cookie.expires));
cookieObject->putDirect(sizeIdentifier, jsNumber(exec, cookie.name.length() + cookie.value.length()));
cookieObject->putDirect(httpOnlyIdentifier, jsBoolean(cookie.httpOnly));
cookieObject->putDirect(secureIdentifier, jsBoolean(cookie.secure));
cookieObject->putDirect(sessionIdentifier, jsBoolean(cookie.session));
result.append(cookieObject);
}
return constructArray(exec, result);
}
JSValue JSInspectorBackend::setting(ExecState* exec, const ArgList& args)
{
if (args.size() < 1)
return jsUndefined();
String key = args.at(0).toString(exec);
if (exec->hadException())
return jsUndefined();
InspectorController* ic = impl()->inspectorController();
if (!ic)
return jsUndefined();
const InspectorController::Setting& setting = ic->setting(key);
switch (setting.type()) {
default:
case InspectorController::Setting::NoType:
return jsUndefined();
case InspectorController::Setting::StringType:
return jsString(exec, setting.string());
case InspectorController::Setting::DoubleType:
return jsNumber(exec, setting.doubleValue());
case InspectorController::Setting::IntegerType:
return jsNumber(exec, setting.integerValue());
case InspectorController::Setting::BooleanType:
return jsBoolean(setting.booleanValue());
case InspectorController::Setting::StringVectorType: {
MarkedArgumentBuffer stringsArray;
const Vector<String>& strings = setting.stringVector();
const unsigned length = strings.size();
for (unsigned i = 0; i < length; ++i)
stringsArray.append(jsString(exec, strings[i]));
return constructArray(exec, stringsArray);
}
}
}
JSValue JSInspectorBackend::setSetting(ExecState* exec, const ArgList& args)
{
if (args.size() < 2)
return jsUndefined();
String key = args.at(0).toString(exec);
if (exec->hadException())
return jsUndefined();
InspectorController::Setting setting;
JSValue value = args.at(1);
if (value.isUndefined() || value.isNull()) {
// Do nothing. The setting is already NoType.
ASSERT(setting.type() == InspectorController::Setting::NoType);
} else if (value.isString())
setting.set(value.toString(exec));
else if (value.isNumber())
setting.set(value.toNumber(exec));
else if (value.isBoolean())
setting.set(value.toBoolean(exec));
else {
JSArray* jsArray = asArray(value);
if (!jsArray)
return jsUndefined();
Vector<String> strings;
for (unsigned i = 0; i < jsArray->length(); ++i) {
String item = jsArray->get(exec, i).toString(exec);
if (exec->hadException())
return jsUndefined();
strings.append(item);
}
setting.set(strings);
}
if (exec->hadException())
return jsUndefined();
InspectorController* ic = impl()->inspectorController();
if (ic)
ic->setSetting(key, setting);
return jsUndefined();
}
JSValue JSInspectorBackend::wrapCallback(ExecState* exec, const ArgList& args)
{
if (args.size() < 1)
return jsUndefined();
return JSInspectorCallbackWrapper::wrap(exec, args.at(0));
}
#if ENABLE(JAVASCRIPT_DEBUGGER)
JSValue JSInspectorBackend::currentCallFrame(ExecState* exec, const ArgList&)
{
JavaScriptCallFrame* callFrame = impl()->currentCallFrame();
if (!callFrame || !callFrame->isValid())
return jsUndefined();
// FIXME: I am not sure if this is actually needed. Can we just use exec?
ExecState* globalExec = callFrame->scopeChain()->globalObject()->globalExec();
JSLock lock(SilenceAssertionsOnly);
return JSInspectedObjectWrapper::wrap(globalExec, toJS(exec, callFrame));
}
JSValue JSInspectorBackend::profiles(JSC::ExecState* exec, const JSC::ArgList&)
{
JSLock lock(SilenceAssertionsOnly);
MarkedArgumentBuffer result;
InspectorController* ic = impl()->inspectorController();
if (!ic)
return jsUndefined();
const Vector<RefPtr<Profile> >& profiles = ic->profiles();
for (size_t i = 0; i < profiles.size(); ++i)
result.append(toJS(exec, profiles[i].get()));
return constructArray(exec, result);
}
#endif
JSValue JSInspectorBackend::nodeForId(ExecState* exec, const ArgList& args)
{
if (args.size() < 1)
return jsUndefined();
Node* node = impl()->nodeForId(args.at(0).toInt32(exec));
if (!node)
return jsUndefined();
InspectorController* ic = impl()->inspectorController();
if (!ic)
return jsUndefined();
JSLock lock(SilenceAssertionsOnly);
JSDOMWindow* inspectedWindow = toJSDOMWindow(ic->inspectedPage()->mainFrame());
return JSInspectedObjectWrapper::wrap(inspectedWindow->globalExec(), toJS(exec, deprecatedGlobalObjectForPrototype(inspectedWindow->globalExec()), node));
}
JSValue JSInspectorBackend::idForNode(ExecState* exec, const ArgList& args)
{
if (args.size() < 1)
return jsUndefined();
JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(args.at(0));
if (!wrapper)
return jsUndefined();
Node* node = toNode(wrapper->unwrappedObject());
if (node)
return jsNumber(exec, impl()->idForNode(node));
return jsUndefined();
}
JSValue JSInspectorBackend::wrapObject(ExecState*, const ArgList& args)
{
if (args.size() < 1)
return jsUndefined();
return impl()->wrapObject(ScriptValue(args.at(0))).jsValue();
}
JSValue JSInspectorBackend::unwrapObject(ExecState* exec, const ArgList& args)
{
if (args.size() < 1)
return jsUndefined();
return impl()->unwrapObject(args.at(0).toString(exec)).jsValue();
}
JSValue JSInspectorBackend::pushNodePathToFrontend(ExecState* exec, const ArgList& args)
{
if (args.size() < 2)
return jsUndefined();
JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(args.at(0));
if (!wrapper)
return jsUndefined();
Node* node = toNode(wrapper->unwrappedObject());
if (!node)
return jsUndefined();
bool selectInUI = args.at(1).toBoolean(exec);
return jsNumber(exec, impl()->pushNodePathToFrontend(node, selectInUI));
}
#if ENABLE(DATABASE)
JSValue JSInspectorBackend::selectDatabase(ExecState*, const ArgList& args)
{
if (args.size() < 1)
return jsUndefined();
JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(args.at(0));
if (!wrapper)
return jsUndefined();
Database* database = toDatabase(wrapper->unwrappedObject());
if (database)
impl()->selectDatabase(database);
return jsUndefined();
}
#endif
#if ENABLE(DOM_STORAGE)
JSValue JSInspectorBackend::selectDOMStorage(ExecState*, const ArgList& args)
{
if (args.size() < 1)
return jsUndefined();
InspectorController* ic = impl()->inspectorController();
if (!ic)
return jsUndefined();
JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(args.at(0));
if (!wrapper)
return jsUndefined();
Storage* storage = toStorage(wrapper->unwrappedObject());
if (storage)
impl()->selectDOMStorage(storage);
return jsUndefined();
}
#endif
} // namespace WebCore