| /* |
| * 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 |