diff options
Diffstat (limited to 'WebCore/inspector')
29 files changed, 1866 insertions, 1342 deletions
diff --git a/WebCore/inspector/ConsoleMessage.cpp b/WebCore/inspector/ConsoleMessage.cpp new file mode 100644 index 0000000..b2bf390 --- /dev/null +++ b/WebCore/inspector/ConsoleMessage.cpp @@ -0,0 +1,138 @@ +/* + * 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "ConsoleMessage.h" + +#include "JSInspectedObjectWrapper.h" +#include "ScriptCallStack.h" +#include "ScriptCallFrame.h" +#include "ScriptFunctionCall.h" +#include "ScriptObjectQuarantine.h" +#include "ScriptString.h" + +namespace WebCore { + +ConsoleMessage::ConsoleMessage(MessageSource s, MessageLevel l, const String& m, unsigned li, const String& u, unsigned g) + : m_source(s) + , m_level(l) + , m_message(m) + , m_line(li) + , m_url(u) + , m_groupLevel(g) + , m_repeatCount(1) +{ +} + +ConsoleMessage::ConsoleMessage(MessageSource s, MessageLevel l, ScriptCallStack* callStack, unsigned g, bool storeTrace) + : m_source(s) + , m_level(l) + , m_wrappedArguments(callStack->at(0).argumentCount()) + , m_frames(storeTrace ? callStack->size() : 0) + , m_groupLevel(g) + , m_repeatCount(1) +{ + const ScriptCallFrame& lastCaller = callStack->at(0); + m_line = lastCaller.lineNumber(); + m_url = lastCaller.sourceURL().string(); + + // FIXME: For now, just store function names as strings. + // As ScriptCallStack start storing line number and source URL for all + // frames, refactor to use that, as well. + if (storeTrace) { + for (unsigned i = 0; i < callStack->size(); ++i) + m_frames[i] = callStack->at(i).functionName(); + } + + for (unsigned i = 0; i < lastCaller.argumentCount(); ++i) + m_wrappedArguments[i] = quarantineValue(callStack->state(), lastCaller.argumentAt(i)); +} + +void ConsoleMessage::addToConsole(ScriptState* scriptState, const ScriptObject& webInspector) +{ + ScriptFunctionCall messageConstructor(scriptState, webInspector, "ConsoleMessage"); + messageConstructor.appendArgument(static_cast<unsigned int>(m_source)); + messageConstructor.appendArgument(static_cast<unsigned int>(m_level)); + messageConstructor.appendArgument(m_line); + messageConstructor.appendArgument(m_url); + messageConstructor.appendArgument(m_groupLevel); + messageConstructor.appendArgument(m_repeatCount); + + if (!m_frames.isEmpty()) { + for (unsigned i = 0; i < m_frames.size(); ++i) + messageConstructor.appendArgument(m_frames[i]); + } else if (!m_wrappedArguments.isEmpty()) { + for (unsigned i = 0; i < m_wrappedArguments.size(); ++i) + messageConstructor.appendArgument(m_wrappedArguments[i]); + } else + messageConstructor.appendArgument(m_message); + + bool hadException = false; + ScriptObject message = messageConstructor.construct(hadException); + if (hadException) + return; + + ScriptFunctionCall addMessageToConsole(scriptState, webInspector, "addMessageToConsole"); + addMessageToConsole.appendArgument(message); + addMessageToConsole.call(hadException); +} + +bool ConsoleMessage::isEqual(ScriptState* state, ConsoleMessage* msg) const +{ + if (msg->m_wrappedArguments.size() != m_wrappedArguments.size()) + return false; + if (!state && msg->m_wrappedArguments.size()) + return false; + + ASSERT_ARG(state, state || msg->m_wrappedArguments.isEmpty()); + + for (size_t i = 0; i < msg->m_wrappedArguments.size(); ++i) { + if (!m_wrappedArguments[i].isEqual(state, msg->m_wrappedArguments[i])) + return false; + } + + size_t frameCount = msg->m_frames.size(); + if (frameCount != m_frames.size()) + return false; + + for (size_t i = 0; i < frameCount; ++i) { + if (m_frames[i] != msg->m_frames[i]) + return false; + } + + return msg->m_source == m_source + && msg->m_level == m_level + && msg->m_message == m_message + && msg->m_line == m_line + && msg->m_url == m_url + && msg->m_groupLevel == m_groupLevel; +} + +} // namespace WebCore diff --git a/WebCore/inspector/ConsoleMessage.h b/WebCore/inspector/ConsoleMessage.h new file mode 100644 index 0000000..d97cbb3 --- /dev/null +++ b/WebCore/inspector/ConsoleMessage.h @@ -0,0 +1,69 @@ +/* + * 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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. + */ + +#ifndef ConsoleMessage_h +#define ConsoleMessage_h + +#include "Console.h" +#include "ScriptObject.h" +#include "ScriptState.h" + +#include <runtime/Protect.h> +#include <wtf/Vector.h> + +namespace WebCore { + + class ScriptCallStack; + class ScriptString; + + class ConsoleMessage { + public: + ConsoleMessage(MessageSource, MessageLevel, const String& m, unsigned li, const String& u, unsigned g); + ConsoleMessage(MessageSource, MessageLevel, ScriptCallStack*, unsigned g, bool storeTrace = false); + + void addToConsole(ScriptState*, const ScriptObject& webInspector); + void incrementCount() { ++m_repeatCount; }; + bool isEqual(ScriptState*, ConsoleMessage* msg) const; + + private: + MessageSource m_source; + MessageLevel m_level; + String m_message; + Vector<ScriptValue> m_wrappedArguments; + Vector<ScriptString> m_frames; + unsigned m_line; + String m_url; + unsigned m_groupLevel; + unsigned m_repeatCount; + }; + +} // namespace WebCore + +#endif // ConsoleMessage_h diff --git a/WebCore/inspector/InspectorClient.h b/WebCore/inspector/InspectorClient.h index fcbf79d..2508536 100644 --- a/WebCore/inspector/InspectorClient.h +++ b/WebCore/inspector/InspectorClient.h @@ -44,6 +44,8 @@ public: virtual String localizedStringsURL() = 0; + virtual String hiddenPanels() = 0; + virtual void showWindow() = 0; virtual void closeWindow() = 0; diff --git a/WebCore/inspector/InspectorController.cpp b/WebCore/inspector/InspectorController.cpp index 5cdc368..ae50769 100644 --- a/WebCore/inspector/InspectorController.cpp +++ b/WebCore/inspector/InspectorController.cpp @@ -33,6 +33,7 @@ #include "CString.h" #include "CachedResource.h" #include "Console.h" +#include "ConsoleMessage.h" #include "DOMWindow.h" #include "DocLoader.h" #include "Document.h" @@ -46,34 +47,40 @@ #include "FrameTree.h" #include "FrameView.h" #include "GraphicsContext.h" -#include "HitTestResult.h" #include "HTMLFrameOwnerElement.h" +#include "HitTestResult.h" #include "InspectorClient.h" +#include "InspectorDatabaseResource.h" +#include "InspectorDOMStorageResource.h" +#include "InspectorResource.h" #include "JSDOMWindow.h" #include "JSInspectedObjectWrapper.h" #include "JSInspectorCallbackWrapper.h" +#include "JSInspectorController.h" #include "JSNode.h" #include "JSRange.h" #include "JavaScriptProfile.h" #include "Page.h" #include "Range.h" +#include "RenderInline.h" #include "ResourceRequest.h" #include "ResourceResponse.h" -#include "Settings.h" #include "ScriptCallStack.h" +#include "ScriptController.h" +#include "SecurityOrigin.h" +#include "Settings.h" #include "SharedBuffer.h" #include "TextEncoding.h" #include "TextIterator.h" -#include "ScriptController.h" #include <JavaScriptCore/APICast.h> #include <JavaScriptCore/JSRetainPtr.h> #include <JavaScriptCore/JSStringRef.h> #include <JavaScriptCore/OpaqueJSString.h> -#include <runtime/JSLock.h> -#include <runtime/UString.h> -#include <runtime/CollectorHeapIterator.h> #include <profiler/Profile.h> #include <profiler/Profiler.h> +#include <runtime/CollectorHeapIterator.h> +#include <runtime/JSLock.h> +#include <runtime/UString.h> #include <wtf/CurrentTime.h> #include <wtf/RefCounted.h> #include <wtf/StdLibExtras.h> @@ -83,6 +90,12 @@ #include "JSDatabase.h" #endif +#if ENABLE(DOM_STORAGE) +#include "Storage.h" +#include "StorageArea.h" +#include "JSStorage.h" +#endif + #if ENABLE(JAVASCRIPT_DEBUGGER) #include "JavaScriptCallFrame.h" #include "JavaScriptDebugServer.h" @@ -158,354 +171,7 @@ JSValueRef InspectorController::callFunction(JSContextRef context, JSObjectRef t return result; } -// ConsoleMessage Struct - -struct ConsoleMessage { - ConsoleMessage(MessageSource s, MessageLevel l, const String& m, unsigned li, const String& u, unsigned g) - : source(s) - , level(l) - , message(m) - , line(li) - , url(u) - , groupLevel(g) - , repeatCount(1) - { - } - - ConsoleMessage(MessageSource s, MessageLevel l, ScriptCallStack* callStack, unsigned g, bool storeTrace = false) - : source(s) - , level(l) - , wrappedArguments(callStack->at(0).argumentCount()) - , frames(storeTrace ? callStack->size() : 0) - , groupLevel(g) - , repeatCount(1) - { - const ScriptCallFrame& lastCaller = callStack->at(0); - line = lastCaller.lineNumber(); - url = lastCaller.sourceURL().string(); - - // FIXME: For now, just store function names as strings. - // As ScriptCallStack start storing line number and source URL for all - // frames, refactor to use that, as well. - if (storeTrace) { - unsigned stackSize = callStack->size(); - for (unsigned i = 0; i < stackSize; ++i) - frames[i] = callStack->at(i).functionName(); - } - - JSLock lock(false); - - for (unsigned i = 0; i < lastCaller.argumentCount(); ++i) - wrappedArguments[i] = JSInspectedObjectWrapper::wrap(callStack->state(), lastCaller.argumentAt(i).jsValue()); - } - - bool isEqual(ExecState* exec, ConsoleMessage* msg) const - { - if (msg->wrappedArguments.size() != this->wrappedArguments.size() || - (!exec && msg->wrappedArguments.size())) - return false; - - for (size_t i = 0; i < msg->wrappedArguments.size(); ++i) { - ASSERT_ARG(exec, exec); - if (!JSValueIsEqual(toRef(exec), toRef(msg->wrappedArguments[i].get()), toRef(this->wrappedArguments[i].get()), 0)) - return false; - } - - size_t frameCount = msg->frames.size(); - if (frameCount != this->frames.size()) - return false; - - for (size_t i = 0; i < frameCount; ++i) { - const ScriptString& myFrameFunctionName = this->frames[i]; - if (myFrameFunctionName != msg->frames[i]) - return false; - } - - return msg->source == this->source - && msg->level == this->level - && msg->message == this->message - && msg->line == this->line - && msg->url == this->url - && msg->groupLevel == this->groupLevel; - } - - MessageSource source; - MessageLevel level; - String message; - Vector<ProtectedJSValuePtr> wrappedArguments; - Vector<ScriptString> frames; - unsigned line; - String url; - unsigned groupLevel; - unsigned repeatCount; -}; - -// XMLHttpRequestResource Class - -struct XMLHttpRequestResource { - XMLHttpRequestResource(const JSC::UString& sourceString) - { - JSC::JSLock lock(false); - this->sourceString = sourceString.rep(); - } - - ~XMLHttpRequestResource() - { - JSC::JSLock lock(false); - sourceString.clear(); - } - - RefPtr<JSC::UString::Rep> sourceString; -}; - -// InspectorResource Struct - -struct InspectorResource : public RefCounted<InspectorResource> { - // Keep these in sync with WebInspector.Resource.Type - enum Type { - Doc, - Stylesheet, - Image, - Font, - Script, - XHR, - Media, - Other - }; - - static PassRefPtr<InspectorResource> create(long long identifier, DocumentLoader* documentLoader, Frame* frame) - { - return adoptRef(new InspectorResource(identifier, documentLoader, frame)); - } - - ~InspectorResource() - { - setScriptObject(0, 0); - } - - Type type() const - { - if (xmlHttpRequestResource) - return XHR; - - if (requestURL == loader->requestURL()) - return Doc; - - if (loader->frameLoader() && requestURL == loader->frameLoader()->iconURL()) - return Image; - - CachedResource* cachedResource = frame->document()->docLoader()->cachedResource(requestURL.string()); - if (!cachedResource) - return Other; - - switch (cachedResource->type()) { - case CachedResource::ImageResource: - return Image; - case CachedResource::FontResource: - return Font; - case CachedResource::CSSStyleSheet: -#if ENABLE(XSLT) - case CachedResource::XSLStyleSheet: -#endif - return Stylesheet; - case CachedResource::Script: - return Script; - default: - return Other; - } - } - - void setScriptObject(JSContextRef context, JSObjectRef newScriptObject) - { - if (scriptContext && scriptObject) - JSValueUnprotect(scriptContext, scriptObject); - - scriptObject = newScriptObject; - scriptContext = context; - - ASSERT((context && newScriptObject) || (!context && !newScriptObject)); - if (context && newScriptObject) - JSValueProtect(context, newScriptObject); - } - - void setXMLHttpRequestProperties(const JSC::UString& data) - { - xmlHttpRequestResource.set(new XMLHttpRequestResource(data)); - } - - String sourceString() const - { - if (xmlHttpRequestResource) - return JSC::UString(xmlHttpRequestResource->sourceString); - - RefPtr<SharedBuffer> buffer; - String textEncodingName; - - if (requestURL == loader->requestURL()) { - buffer = loader->mainResourceData(); - textEncodingName = frame->document()->inputEncoding(); - } else { - CachedResource* cachedResource = frame->document()->docLoader()->cachedResource(requestURL.string()); - if (!cachedResource) - return String(); - - if (cachedResource->isPurgeable()) { - // If the resource is purgeable then make it unpurgeable to get - // get its data. This might fail, in which case we return an - // empty String. - // FIXME: should we do something else in the case of a purged - // resource that informs the user why there is no data in the - // inspector? - if (!cachedResource->makePurgeable(false)) - return String(); - } - - buffer = cachedResource->data(); - textEncodingName = cachedResource->encoding(); - } - - if (!buffer) - return String(); - - TextEncoding encoding(textEncodingName); - if (!encoding.isValid()) - encoding = WindowsLatin1Encoding(); - return encoding.decode(buffer->data(), buffer->size()); - } - - long long identifier; - RefPtr<DocumentLoader> loader; - RefPtr<Frame> frame; - OwnPtr<XMLHttpRequestResource> xmlHttpRequestResource; - KURL requestURL; - HTTPHeaderMap requestHeaderFields; - HTTPHeaderMap responseHeaderFields; - String mimeType; - String suggestedFilename; - JSContextRef scriptContext; - JSObjectRef scriptObject; - long long expectedContentLength; - bool cached; - bool finished; - bool failed; - int length; - int responseStatusCode; - double startTime; - double responseReceivedTime; - double endTime; - -protected: - InspectorResource(long long identifier, DocumentLoader* documentLoader, Frame* frame) - : identifier(identifier) - , loader(documentLoader) - , frame(frame) - , xmlHttpRequestResource(0) - , scriptContext(0) - , scriptObject(0) - , expectedContentLength(0) - , cached(false) - , finished(false) - , failed(false) - , length(0) - , responseStatusCode(0) - , startTime(-1.0) - , responseReceivedTime(-1.0) - , endTime(-1.0) - { - } -}; - -// InspectorDatabaseResource Struct - -#if ENABLE(DATABASE) -struct InspectorDatabaseResource : public RefCounted<InspectorDatabaseResource> { - static PassRefPtr<InspectorDatabaseResource> create(Database* database, const String& domain, const String& name, const String& version) - { - return adoptRef(new InspectorDatabaseResource(database, domain, name, version)); - } - - void setScriptObject(JSContextRef context, JSObjectRef newScriptObject) - { - if (scriptContext && scriptObject) - JSValueUnprotect(scriptContext, scriptObject); - - scriptObject = newScriptObject; - scriptContext = context; - - ASSERT((context && newScriptObject) || (!context && !newScriptObject)); - if (context && newScriptObject) - JSValueProtect(context, newScriptObject); - } - - RefPtr<Database> database; - String domain; - String name; - String version; - JSContextRef scriptContext; - JSObjectRef scriptObject; - -private: - InspectorDatabaseResource(Database* database, const String& domain, const String& name, const String& version) - : database(database) - , domain(domain) - , name(name) - , version(version) - , scriptContext(0) - , scriptObject(0) - { - } -}; -#endif - -// JavaScript Callbacks - -#define SIMPLE_INSPECTOR_CALLBACK(jsFunction, inspectorControllerMethod) \ -static JSValueRef jsFunction(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*) \ -{ \ - if (InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject))) \ - controller->inspectorControllerMethod(); \ - return JSValueMakeUndefined(ctx); \ -} - -SIMPLE_INSPECTOR_CALLBACK(hideDOMNodeHighlight, hideHighlight); -SIMPLE_INSPECTOR_CALLBACK(loaded, scriptObjectReady); -SIMPLE_INSPECTOR_CALLBACK(unloading, close); -SIMPLE_INSPECTOR_CALLBACK(attach, attachWindow); -SIMPLE_INSPECTOR_CALLBACK(detach, detachWindow); -#if ENABLE(JAVASCRIPT_DEBUGGER) -SIMPLE_INSPECTOR_CALLBACK(enableDebugger, enableDebugger); -SIMPLE_INSPECTOR_CALLBACK(disableDebugger, disableDebugger); -SIMPLE_INSPECTOR_CALLBACK(pauseInDebugger, pauseInDebugger); -SIMPLE_INSPECTOR_CALLBACK(resumeDebugger, resumeDebugger); -SIMPLE_INSPECTOR_CALLBACK(stepOverStatementInDebugger, stepOverStatementInDebugger); -SIMPLE_INSPECTOR_CALLBACK(stepIntoStatementInDebugger, stepIntoStatementInDebugger); -SIMPLE_INSPECTOR_CALLBACK(stepOutOfFunctionInDebugger, stepOutOfFunctionInDebugger); -#endif -SIMPLE_INSPECTOR_CALLBACK(closeWindow, closeWindow); -SIMPLE_INSPECTOR_CALLBACK(clearMessages, clearConsoleMessages); -SIMPLE_INSPECTOR_CALLBACK(startProfiling, startUserInitiatedProfilingSoon); -SIMPLE_INSPECTOR_CALLBACK(stopProfiling, stopUserInitiatedProfiling); -SIMPLE_INSPECTOR_CALLBACK(enableProfiler, enableProfiler); -SIMPLE_INSPECTOR_CALLBACK(disableProfiler, disableProfiler); -SIMPLE_INSPECTOR_CALLBACK(toggleNodeSearch, toggleSearchForNodeInPage); - -#define BOOL_INSPECTOR_CALLBACK(jsFunction, inspectorControllerMethod) \ -static JSValueRef jsFunction(JSContextRef ctx, JSObjectRef, JSObjectRef thisObject, size_t, const JSValueRef[], JSValueRef*) \ -{ \ - if (InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject))) \ - return JSValueMakeBoolean(ctx, controller->inspectorControllerMethod()); \ - return JSValueMakeUndefined(ctx); \ -} - -#if ENABLE(JAVASCRIPT_DEBUGGER) -BOOL_INSPECTOR_CALLBACK(debuggerEnabled, debuggerEnabled); -BOOL_INSPECTOR_CALLBACK(pauseOnExceptions, pauseOnExceptions); -#endif -BOOL_INSPECTOR_CALLBACK(profilerEnabled, profilerEnabled); -BOOL_INSPECTOR_CALLBACK(isWindowVisible, windowVisible); -BOOL_INSPECTOR_CALLBACK(searchingForNode, searchingForNodeInPage); - -static bool addSourceToFrame(const String& mimeType, const String& source, Node* frameNode) +bool InspectorController::addSourceToFrame(const String& mimeType, const String& source, Node* frameNode) { ASSERT_ARG(frameNode, frameNode); @@ -541,362 +207,7 @@ static bool addSourceToFrame(const String& mimeType, const String& source, Node* return true; } -static JSValueRef addResourceSourceToFrame(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - JSValueRef undefined = JSValueMakeUndefined(ctx); - - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (argumentCount < 2 || !controller) - return undefined; - - JSValueRef identifierValue = arguments[0]; - if (!JSValueIsNumber(ctx, identifierValue)) - return undefined; - - long long identifier = static_cast<long long>(JSValueToNumber(ctx, identifierValue, exception)); - if (exception && *exception) - return undefined; - - RefPtr<InspectorResource> resource = controller->resources().get(identifier); - ASSERT(resource); - if (!resource) - return undefined; - - String sourceString = resource->sourceString(); - if (sourceString.isEmpty()) - return undefined; - - bool successfullyAddedSource = addSourceToFrame(resource->mimeType, sourceString, toNode(toJS(arguments[1]))); - return JSValueMakeBoolean(ctx, successfullyAddedSource); -} - -static JSValueRef addSourceToFrame(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - JSValueRef undefined = JSValueMakeUndefined(ctx); - - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (argumentCount < 3 || !controller) - return undefined; - - JSValueRef mimeTypeValue = arguments[0]; - if (!JSValueIsString(ctx, mimeTypeValue)) - return undefined; - - JSValueRef sourceValue = arguments[1]; - if (!JSValueIsString(ctx, sourceValue)) - return undefined; - - String mimeType = toString(ctx, mimeTypeValue, exception); - if (mimeType.isEmpty()) - return undefined; - - String source = toString(ctx, sourceValue, exception); - if (source.isEmpty()) - return undefined; - - bool successfullyAddedSource = addSourceToFrame(mimeType, source, toNode(toJS(arguments[2]))); - return JSValueMakeBoolean(ctx, successfullyAddedSource); -} - -static JSValueRef getResourceDocumentNode(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - JSValueRef undefined = JSValueMakeUndefined(ctx); - - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!argumentCount || argumentCount > 1 || !controller) - return undefined; - - JSValueRef identifierValue = arguments[0]; - if (!JSValueIsNumber(ctx, identifierValue)) - return undefined; - - long long identifier = static_cast<long long>(JSValueToNumber(ctx, identifierValue, exception)); - if (exception && *exception) - return undefined; - - RefPtr<InspectorResource> resource = controller->resources().get(identifier); - ASSERT(resource); - if (!resource) - return undefined; - - Frame* frame = resource->frame.get(); - - Document* document = frame->document(); - if (!document) - return undefined; - - if (document->isPluginDocument() || document->isImageDocument() || document->isMediaDocument()) - return undefined; - - ExecState* exec = toJSDOMWindowShell(resource->frame.get())->window()->globalExec(); - - JSC::JSLock lock(false); - JSValueRef documentValue = toRef(JSInspectedObjectWrapper::wrap(exec, toJS(exec, document))); - return documentValue; -} - -static JSValueRef highlightDOMNode(JSContextRef context, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/) -{ - JSValueRef undefined = JSValueMakeUndefined(context); - - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (argumentCount < 1 || !controller) - return undefined; - - JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(toJS(arguments[0])); - if (!wrapper) - return undefined; - Node* node = toNode(wrapper->unwrappedObject()); - if (!node) - return undefined; - - controller->highlight(node); - - return undefined; -} - -static JSValueRef search(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!controller) - return JSValueMakeUndefined(ctx); - - if (argumentCount < 2 || !JSValueIsString(ctx, arguments[1])) - return JSValueMakeUndefined(ctx); - - Node* node = toNode(toJS(arguments[0])); - if (!node) - return JSValueMakeUndefined(ctx); - - String target = toString(ctx, arguments[1], exception); - - JSObjectRef global = JSContextGetGlobalObject(ctx); - - JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, jsStringRef("Array").get(), exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSValueRef pushProperty = JSObjectGetProperty(ctx, result, jsStringRef("push").get(), exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - 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; - - JSC::JSLock lock(false); - JSValueRef arg0 = toRef(toJS(toJS(ctx), resultRange.get())); - JSObjectCallAsFunction(ctx, pushFunction, result, 1, &arg0, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - setStart(searchRange.get(), newStart); - } while (true); - - return result; -} - -#if ENABLE(DATABASE) -static JSValueRef databaseTableNames(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!controller) - return JSValueMakeUndefined(ctx); - - if (argumentCount < 1) - return JSValueMakeUndefined(ctx); - - JSQuarantinedObjectWrapper* wrapper = JSQuarantinedObjectWrapper::asWrapper(toJS(arguments[0])); - if (!wrapper) - return JSValueMakeUndefined(ctx); - - Database* database = toDatabase(wrapper->unwrappedObject()); - if (!database) - return JSValueMakeUndefined(ctx); - - JSObjectRef global = JSContextGetGlobalObject(ctx); - - JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, jsStringRef("Array").get(), exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSValueRef pushProperty = JSObjectGetProperty(ctx, result, jsStringRef("push").get(), exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - Vector<String> tableNames = database->tableNames(); - unsigned length = tableNames.size(); - for (unsigned i = 0; i < length; ++i) { - String tableName = tableNames[i]; - JSValueRef tableNameValue = JSValueMakeString(ctx, jsStringRef(tableName).get()); - - JSValueRef pushArguments[] = { tableNameValue }; - JSObjectCallAsFunction(ctx, pushFunction, result, 1, pushArguments, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - } - - return result; -} -#endif - -static JSValueRef inspectedWindow(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/) -{ - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!controller) - return JSValueMakeUndefined(ctx); - - JSDOMWindow* inspectedWindow = toJSDOMWindow(controller->inspectedPage()->mainFrame()); - JSLock lock(false); - return toRef(JSInspectedObjectWrapper::wrap(inspectedWindow->globalExec(), inspectedWindow)); -} - -static JSValueRef setting(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef arguments[], JSValueRef* exception) -{ - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!controller) - return JSValueMakeUndefined(ctx); - - JSValueRef keyValue = arguments[0]; - if (!JSValueIsString(ctx, keyValue)) - return JSValueMakeUndefined(ctx); - - const InspectorController::Setting& setting = controller->setting(toString(ctx, keyValue, exception)); - - switch (setting.type()) { - default: - case InspectorController::Setting::NoType: - return JSValueMakeUndefined(ctx); - case InspectorController::Setting::StringType: - return JSValueMakeString(ctx, jsStringRef(setting.string()).get()); - case InspectorController::Setting::DoubleType: - return JSValueMakeNumber(ctx, setting.doubleValue()); - case InspectorController::Setting::IntegerType: - return JSValueMakeNumber(ctx, setting.integerValue()); - case InspectorController::Setting::BooleanType: - return JSValueMakeBoolean(ctx, setting.booleanValue()); - case InspectorController::Setting::StringVectorType: { - Vector<JSValueRef> stringValues; - const Vector<String>& strings = setting.stringVector(); - const unsigned length = strings.size(); - for (unsigned i = 0; i < length; ++i) - stringValues.append(JSValueMakeString(ctx, jsStringRef(strings[i]).get())); - - JSObjectRef stringsArray = JSObjectMakeArray(ctx, stringValues.size(), stringValues.data(), exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - return stringsArray; - } - } -} - -static JSValueRef setSetting(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef arguments[], JSValueRef* exception) -{ - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!controller) - return JSValueMakeUndefined(ctx); - - JSValueRef keyValue = arguments[0]; - if (!JSValueIsString(ctx, keyValue)) - return JSValueMakeUndefined(ctx); - - InspectorController::Setting setting; - - JSValueRef value = arguments[1]; - switch (JSValueGetType(ctx, value)) { - default: - case kJSTypeUndefined: - case kJSTypeNull: - // Do nothing. The setting is already NoType. - ASSERT(setting.type() == InspectorController::Setting::NoType); - break; - case kJSTypeString: - setting.set(toString(ctx, value, exception)); - break; - case kJSTypeNumber: - setting.set(JSValueToNumber(ctx, value, exception)); - break; - case kJSTypeBoolean: - setting.set(JSValueToBoolean(ctx, value)); - break; - case kJSTypeObject: { - JSObjectRef object = JSValueToObject(ctx, value, 0); - JSValueRef lengthValue = JSObjectGetProperty(ctx, object, jsStringRef("length").get(), exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - Vector<String> strings; - const unsigned length = static_cast<unsigned>(JSValueToNumber(ctx, lengthValue, 0)); - for (unsigned i = 0; i < length; ++i) { - JSValueRef itemValue = JSObjectGetPropertyAtIndex(ctx, object, i, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - strings.append(toString(ctx, itemValue, exception)); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - } - - setting.set(strings); - break; - } - } - - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - controller->setSetting(toString(ctx, keyValue, exception), setting); - - return JSValueMakeUndefined(ctx); -} - -static JSValueRef localizedStrings(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/) -{ - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!controller) - return JSValueMakeUndefined(ctx); - - String url = controller->localizedStringsURL(); - if (url.isNull()) - return JSValueMakeNull(ctx); - - return JSValueMakeString(ctx, jsStringRef(url).get()); -} - -static JSValueRef platform(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef /*thisObject*/, size_t /*argumentCount*/, const JSValueRef[] /*arguments[]*/, JSValueRef* /*exception*/) +const String& InspectorController::platform() const { #if PLATFORM(MAC) #ifdef BUILDING_ON_TIGER @@ -916,184 +227,9 @@ static JSValueRef platform(JSContextRef ctx, JSObjectRef /*function*/, JSObjectR DEFINE_STATIC_LOCAL(const String, platform, ("unknown")); #endif - JSValueRef platformValue = JSValueMakeString(ctx, jsStringRef(platform).get()); - - return platformValue; -} - -static JSValueRef moveByUnrestricted(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!controller) - return JSValueMakeUndefined(ctx); - - if (argumentCount < 2) - return JSValueMakeUndefined(ctx); - - double x = JSValueToNumber(ctx, arguments[0], exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - double y = JSValueToNumber(ctx, arguments[1], exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - controller->moveWindowBy(narrowPrecisionToFloat(x), narrowPrecisionToFloat(y)); - - return JSValueMakeUndefined(ctx); + return platform; } -static JSValueRef setAttachedWindowHeight(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!controller) - return JSValueMakeUndefined(ctx); - - if (argumentCount < 1) - return JSValueMakeUndefined(ctx); - - unsigned height = static_cast<unsigned>(JSValueToNumber(ctx, arguments[0], exception)); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - controller->setAttachedWindowHeight(height); - - return JSValueMakeUndefined(ctx); -} - -static JSValueRef wrapCallback(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/) -{ - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!controller) - return JSValueMakeUndefined(ctx); - - if (argumentCount < 1) - return JSValueMakeUndefined(ctx); - - JSLock lock(false); - return toRef(JSInspectorCallbackWrapper::wrap(toJS(ctx), toJS(arguments[0]))); -} - -#if ENABLE(JAVASCRIPT_DEBUGGER) -static JSValueRef currentCallFrame(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* /*exception*/) -{ - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!controller) - return JSValueMakeUndefined(ctx); - - JavaScriptCallFrame* callFrame = controller->currentCallFrame(); - if (!callFrame || !callFrame->isValid()) - return JSValueMakeNull(ctx); - - ExecState* globalExec = callFrame->scopeChain()->globalObject()->globalExec(); - - JSLock lock(false); - return toRef(JSInspectedObjectWrapper::wrap(globalExec, toJS(toJS(ctx), callFrame))); -} - -static JSValueRef setPauseOnExceptions(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* /*exception*/) -{ - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!controller) - return JSValueMakeUndefined(ctx); - - if (argumentCount < 1) - return JSValueMakeUndefined(ctx); - - controller->setPauseOnExceptions(JSValueToBoolean(ctx, arguments[0])); - - return JSValueMakeUndefined(ctx); -} - -static JSValueRef addBreakpoint(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!controller) - return JSValueMakeUndefined(ctx); - - if (argumentCount < 2) - return JSValueMakeUndefined(ctx); - - double sourceID = JSValueToNumber(ctx, arguments[0], exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - double lineNumber = JSValueToNumber(ctx, arguments[1], exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - controller->addBreakpoint(static_cast<int>(sourceID), static_cast<unsigned>(lineNumber)); - - return JSValueMakeUndefined(ctx); -} - -static JSValueRef removeBreakpoint(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) -{ - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!controller) - return JSValueMakeUndefined(ctx); - - if (argumentCount < 2) - return JSValueMakeUndefined(ctx); - - double sourceID = JSValueToNumber(ctx, arguments[0], exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - double lineNumber = JSValueToNumber(ctx, arguments[1], exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - controller->removeBreakpoint(static_cast<int>(sourceID), static_cast<unsigned>(lineNumber)); - - return JSValueMakeUndefined(ctx); -} -#endif - -static JSValueRef profiles(JSContextRef ctx, JSObjectRef /*function*/, JSObjectRef thisObject, size_t /*argumentCount*/, const JSValueRef[] /*arguments*/, JSValueRef* exception) -{ - InspectorController* controller = reinterpret_cast<InspectorController*>(JSObjectGetPrivate(thisObject)); - if (!controller) - return JSValueMakeUndefined(ctx); - - JSLock lock(false); - - const Vector<RefPtr<Profile> >& profiles = controller->profiles(); - - JSObjectRef global = JSContextGetGlobalObject(ctx); - - JSValueRef arrayProperty = JSObjectGetProperty(ctx, global, jsStringRef("Array").get(), exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSObjectRef arrayConstructor = JSValueToObject(ctx, arrayProperty, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSObjectRef result = JSObjectCallAsConstructor(ctx, arrayConstructor, 0, 0, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSValueRef pushProperty = JSObjectGetProperty(ctx, result, jsStringRef("push").get(), exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - JSObjectRef pushFunction = JSValueToObject(ctx, pushProperty, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - - for (size_t i = 0; i < profiles.size(); ++i) { - JSValueRef arg0 = toRef(toJS(toJS(ctx), profiles[i].get())); - JSObjectCallAsFunction(ctx, pushFunction, result, 1, &arg0, exception); - if (exception && *exception) - return JSValueMakeUndefined(ctx); - } - - return result; -} - -// InspectorController Class - static unsigned s_inspectorControllerCount; static HashMap<String, InspectorController::Setting*>* s_settingCache; @@ -1225,6 +361,13 @@ String InspectorController::localizedStringsURL() return m_client->localizedStringsURL(); } +String InspectorController::hiddenPanels() +{ + if (!enabled()) + return String(); + return m_client->hiddenPanels(); +} + // Trying to inspect something in a frame with JavaScript disabled would later lead to // crashes trying to create JavaScript wrappers. Some day we could fix this issue, but // for now prevent crashes here by never targeting a node in such a frame. @@ -1297,6 +440,7 @@ void InspectorController::hideHighlight() { if (!enabled()) return; + m_highlightedNode = 0; m_client->hideHighlight(); } @@ -1358,7 +502,7 @@ void InspectorController::addConsoleMessage(ExecState* exec, ConsoleMessage* con ASSERT_ARG(consoleMessage, consoleMessage); if (m_previousMessage && m_previousMessage->isEqual(exec, consoleMessage)) { - ++m_previousMessage->repeatCount; + m_previousMessage->incrementCount(); delete consoleMessage; } else { m_previousMessage = consoleMessage; @@ -1366,7 +510,7 @@ void InspectorController::addConsoleMessage(ExecState* exec, ConsoleMessage* con } if (windowVisible()) - addScriptConsoleMessage(m_previousMessage); + m_previousMessage->addToConsole(toJS(m_scriptContext), ScriptObject(toJS(m_scriptObject))); } void InspectorController::clearConsoleMessages() @@ -1520,83 +664,16 @@ void InspectorController::windowScriptObjectAvailable() if (!m_page || !enabled()) return; - m_scriptContext = toRef(m_page->mainFrame()->script()->globalObject()->globalExec()); + // Grant the inspector the ability to script the inspected page. + m_page->mainFrame()->document()->securityOrigin()->grantUniversalAccess(); - JSObjectRef global = JSContextGetGlobalObject(m_scriptContext); - ASSERT(global); - - static JSStaticFunction staticFunctions[] = { - // SIMPLE_INSPECTOR_CALLBACK - { "hideDOMNodeHighlight", WebCore::hideDOMNodeHighlight, kJSPropertyAttributeNone }, - { "loaded", WebCore::loaded, kJSPropertyAttributeNone }, - { "windowUnloading", WebCore::unloading, kJSPropertyAttributeNone }, - { "attach", WebCore::attach, kJSPropertyAttributeNone }, - { "detach", WebCore::detach, kJSPropertyAttributeNone }, -#if ENABLE(JAVASCRIPT_DEBUGGER) - { "enableDebugger", WebCore::enableDebugger, kJSPropertyAttributeNone }, - { "disableDebugger", WebCore::disableDebugger, kJSPropertyAttributeNone }, - { "pauseInDebugger", WebCore::pauseInDebugger, kJSPropertyAttributeNone }, - { "resumeDebugger", WebCore::resumeDebugger, kJSPropertyAttributeNone }, - { "stepOverStatementInDebugger", WebCore::stepOverStatementInDebugger, kJSPropertyAttributeNone }, - { "stepIntoStatementInDebugger", WebCore::stepIntoStatementInDebugger, kJSPropertyAttributeNone }, - { "stepOutOfFunctionInDebugger", WebCore::stepOutOfFunctionInDebugger, kJSPropertyAttributeNone }, -#endif - { "closeWindow", WebCore::closeWindow, kJSPropertyAttributeNone }, - { "clearMessages", WebCore::clearMessages, kJSPropertyAttributeNone }, - { "startProfiling", WebCore::startProfiling, kJSPropertyAttributeNone }, - { "stopProfiling", WebCore::stopProfiling, kJSPropertyAttributeNone }, - { "enableProfiler", WebCore::enableProfiler, kJSPropertyAttributeNone }, - { "disableProfiler", WebCore::disableProfiler, kJSPropertyAttributeNone }, - { "toggleNodeSearch", WebCore::toggleNodeSearch, kJSPropertyAttributeNone }, - - // BOOL_INSPECTOR_CALLBACK -#if ENABLE(JAVASCRIPT_DEBUGGER) - { "debuggerEnabled", WebCore::debuggerEnabled, kJSPropertyAttributeNone }, - { "pauseOnExceptions", WebCore::pauseOnExceptions, kJSPropertyAttributeNone }, -#endif - { "profilerEnabled", WebCore::profilerEnabled, kJSPropertyAttributeNone }, - { "isWindowVisible", WebCore::isWindowVisible, kJSPropertyAttributeNone }, - { "searchingForNode", WebCore::searchingForNode, kJSPropertyAttributeNone }, - - // Custom callbacks - { "addResourceSourceToFrame", WebCore::addResourceSourceToFrame, kJSPropertyAttributeNone }, - { "addSourceToFrame", WebCore::addSourceToFrame, kJSPropertyAttributeNone }, - { "getResourceDocumentNode", WebCore::getResourceDocumentNode, kJSPropertyAttributeNone }, - { "highlightDOMNode", WebCore::highlightDOMNode, kJSPropertyAttributeNone }, - { "search", WebCore::search, kJSPropertyAttributeNone }, -#if ENABLE(DATABASE) - { "databaseTableNames", WebCore::databaseTableNames, kJSPropertyAttributeNone }, -#endif - { "setting", WebCore::setting, kJSPropertyAttributeNone }, - { "setSetting", WebCore::setSetting, kJSPropertyAttributeNone }, - { "inspectedWindow", WebCore::inspectedWindow, kJSPropertyAttributeNone }, - { "localizedStringsURL", WebCore::localizedStrings, kJSPropertyAttributeNone }, - { "platform", WebCore::platform, kJSPropertyAttributeNone }, - { "moveByUnrestricted", WebCore::moveByUnrestricted, kJSPropertyAttributeNone }, - { "setAttachedWindowHeight", WebCore::setAttachedWindowHeight, kJSPropertyAttributeNone }, - { "wrapCallback", WebCore::wrapCallback, kJSPropertyAttributeNone }, -#if ENABLE(JAVASCRIPT_DEBUGGER) - { "currentCallFrame", WebCore::currentCallFrame, kJSPropertyAttributeNone }, - { "setPauseOnExceptions", WebCore::setPauseOnExceptions, kJSPropertyAttributeNone }, - { "addBreakpoint", WebCore::addBreakpoint, kJSPropertyAttributeNone }, - { "removeBreakpoint", WebCore::removeBreakpoint, kJSPropertyAttributeNone }, -#endif - { "profiles", WebCore::profiles, kJSPropertyAttributeNone }, - { 0, 0, 0 } - }; - - JSClassDefinition inspectorControllerDefinition = { - 0, kJSClassAttributeNone, "InspectorController", 0, 0, staticFunctions, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 - }; - - JSClassRef controllerClass = JSClassCreate(&inspectorControllerDefinition); - ASSERT(controllerClass); - - m_controllerScriptObject = JSObjectMake(m_scriptContext, controllerClass, reinterpret_cast<void*>(this)); - ASSERT(m_controllerScriptObject); - - JSObjectSetProperty(m_scriptContext, global, jsStringRef("InspectorController").get(), m_controllerScriptObject, kJSPropertyAttributeNone, 0); + // FIXME: This should be cleaned up. API Mix-up. + JSGlobalObject* globalObject = m_page->mainFrame()->script()->globalObject(); + ExecState* exec = globalObject->globalExec(); + m_scriptContext = toRef(exec); + JSValuePtr jsInspector = toJS(exec, this); + m_controllerScriptObject = toRef(asObject(jsInspector)); + globalObject->putDirect(Identifier(exec, "InspectorController"), jsInspector); } void InspectorController::scriptObjectReady() @@ -2103,145 +1180,20 @@ void InspectorController::populateScriptObjects() unsigned messageCount = m_consoleMessages.size(); for (unsigned i = 0; i < messageCount; ++i) - addScriptConsoleMessage(m_consoleMessages[i]); + m_consoleMessages[i]->addToConsole(toJS(m_scriptContext), ScriptObject(toJS(m_scriptObject))); #if ENABLE(DATABASE) DatabaseResourcesSet::iterator databasesEnd = m_databaseResources.end(); for (DatabaseResourcesSet::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it) - addDatabaseScriptResource((*it).get()); + (*it)->bind(toJS(m_scriptContext), ScriptObject(toJS(m_scriptObject))); #endif - - callSimpleFunction(m_scriptContext, m_scriptObject, "populateInterface"); -} - -#if ENABLE(DATABASE) -JSObjectRef InspectorController::addDatabaseScriptResource(InspectorDatabaseResource* resource) -{ - ASSERT_ARG(resource, resource); - - if (resource->scriptObject) - return resource->scriptObject; - - ASSERT(m_scriptContext); - ASSERT(m_scriptObject); - if (!m_scriptContext || !m_scriptObject) - return 0; - - Frame* frame = resource->database->document()->frame(); - if (!frame) - return 0; - - JSValueRef exception = 0; - - JSValueRef databaseProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("Database").get(), &exception); - if (HANDLE_EXCEPTION(m_scriptContext, exception)) - return 0; - - JSObjectRef databaseConstructor = JSValueToObject(m_scriptContext, databaseProperty, &exception); - if (HANDLE_EXCEPTION(m_scriptContext, exception)) - return 0; - - ExecState* exec = toJSDOMWindow(frame)->globalExec(); - - JSValueRef database; - - { - JSC::JSLock lock(false); - database = toRef(JSInspectedObjectWrapper::wrap(exec, toJS(exec, resource->database.get()))); - } - - JSValueRef domainValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->domain).get()); - JSValueRef nameValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->name).get()); - JSValueRef versionValue = JSValueMakeString(m_scriptContext, jsStringRef(resource->version).get()); - - JSValueRef arguments[] = { database, domainValue, nameValue, versionValue }; - JSObjectRef result = JSObjectCallAsConstructor(m_scriptContext, databaseConstructor, 4, arguments, &exception); - if (HANDLE_EXCEPTION(m_scriptContext, exception)) - return 0; - - ASSERT(result); - - callFunction(m_scriptContext, m_scriptObject, "addDatabase", 1, &result, exception); - - if (exception) - return 0; - - resource->setScriptObject(m_scriptContext, result); - - return result; -} - -void InspectorController::removeDatabaseScriptResource(InspectorDatabaseResource* resource) -{ - ASSERT(m_scriptContext); - ASSERT(m_scriptObject); - if (!m_scriptContext || !m_scriptObject) - return; - - ASSERT(resource); - ASSERT(resource->scriptObject); - if (!resource || !resource->scriptObject) - return; - - JSObjectRef scriptObject = resource->scriptObject; - resource->setScriptObject(0, 0); - - JSValueRef exception = 0; - callFunction(m_scriptContext, m_scriptObject, "removeDatabase", 1, &scriptObject, exception); -} +#if ENABLE(DOM_STORAGE) + DOMStorageResourcesSet::iterator domStorageEnd = m_domStorageResources.end(); + for (DOMStorageResourcesSet::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it) + (*it)->bind(toJS(m_scriptContext), ScriptObject(toJS(m_scriptObject))); #endif -void InspectorController::addScriptConsoleMessage(const ConsoleMessage* message) -{ - ASSERT_ARG(message, message); - - JSValueRef exception = 0; - - JSValueRef messageConstructorProperty = JSObjectGetProperty(m_scriptContext, m_scriptObject, jsStringRef("ConsoleMessage").get(), &exception); - if (HANDLE_EXCEPTION(m_scriptContext, exception)) - return; - - JSObjectRef messageConstructor = JSValueToObject(m_scriptContext, messageConstructorProperty, &exception); - if (HANDLE_EXCEPTION(m_scriptContext, exception)) - return; - - JSValueRef sourceValue = JSValueMakeNumber(m_scriptContext, message->source); - JSValueRef levelValue = JSValueMakeNumber(m_scriptContext, message->level); - JSValueRef lineValue = JSValueMakeNumber(m_scriptContext, message->line); - JSValueRef urlValue = JSValueMakeString(m_scriptContext, jsStringRef(message->url).get()); - JSValueRef groupLevelValue = JSValueMakeNumber(m_scriptContext, message->groupLevel); - JSValueRef repeatCountValue = JSValueMakeNumber(m_scriptContext, message->repeatCount); - - static const unsigned maximumMessageArguments = 256; - JSValueRef arguments[maximumMessageArguments]; - unsigned argumentCount = 0; - arguments[argumentCount++] = sourceValue; - arguments[argumentCount++] = levelValue; - arguments[argumentCount++] = lineValue; - arguments[argumentCount++] = urlValue; - arguments[argumentCount++] = groupLevelValue; - arguments[argumentCount++] = repeatCountValue; - - if (!message->frames.isEmpty()) { - unsigned remainingSpaceInArguments = maximumMessageArguments - argumentCount; - unsigned argumentsToAdd = min(remainingSpaceInArguments, static_cast<unsigned>(message->frames.size())); - for (unsigned i = 0; i < argumentsToAdd; ++i) - arguments[argumentCount++] = JSValueMakeString(m_scriptContext, jsStringRef(message->frames[i]).get()); - } else if (!message->wrappedArguments.isEmpty()) { - unsigned remainingSpaceInArguments = maximumMessageArguments - argumentCount; - unsigned argumentsToAdd = min(remainingSpaceInArguments, static_cast<unsigned>(message->wrappedArguments.size())); - for (unsigned i = 0; i < argumentsToAdd; ++i) - arguments[argumentCount++] = toRef(message->wrappedArguments[i]); - } else { - JSValueRef messageValue = JSValueMakeString(m_scriptContext, jsStringRef(message->message).get()); - arguments[argumentCount++] = messageValue; - } - - JSObjectRef messageObject = JSObjectCallAsConstructor(m_scriptContext, messageConstructor, argumentCount, arguments, &exception); - if (HANDLE_EXCEPTION(m_scriptContext, exception)) - return; - - callFunction(m_scriptContext, m_scriptObject, "addMessageToConsole", 1, &messageObject, exception); + callSimpleFunction(m_scriptContext, m_scriptObject, "populateInterface"); } void InspectorController::addScriptProfile(Profile* profile) @@ -2265,10 +1217,13 @@ void InspectorController::resetScriptObjects() #if ENABLE(DATABASE) DatabaseResourcesSet::iterator databasesEnd = m_databaseResources.end(); - for (DatabaseResourcesSet::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it) { - InspectorDatabaseResource* resource = (*it).get(); - resource->setScriptObject(0, 0); - } + for (DatabaseResourcesSet::iterator it = m_databaseResources.begin(); it != databasesEnd; ++it) + (*it)->unbind(); +#endif +#if ENABLE(DOM_STORAGE) + DOMStorageResourcesSet::iterator domStorageEnd = m_domStorageResources.end(); + for (DOMStorageResourcesSet::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it) + (*it)->unbind(); #endif callSimpleFunction(m_scriptContext, m_scriptObject, "reset"); @@ -2312,6 +1267,9 @@ void InspectorController::didCommitLoad(DocumentLoader* loader) #if ENABLE(DATABASE) m_databaseResources.clear(); #endif +#if ENABLE(DOM_STORAGE) + m_domStorageResources.clear(); +#endif if (windowVisible()) { resetScriptObjects(); @@ -2555,6 +1513,21 @@ void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identi updateScriptResourceType(resource); } +void InspectorController::scriptImported(unsigned long identifier, const JSC::UString& sourceString) +{ + if (!enabled()) + return; + + InspectorResource* resource = m_resources.get(identifier).get(); + if (!resource) + return; + + resource->setXMLHttpRequestProperties(sourceString); + + if (windowVisible() && resource->scriptObject) + updateScriptResourceType(resource); +} + #if ENABLE(DATABASE) void InspectorController::didOpenDatabase(Database* database, const String& domain, const String& name, const String& version) @@ -2567,7 +1540,27 @@ void InspectorController::didOpenDatabase(Database* database, const String& doma m_databaseResources.add(resource); if (windowVisible()) - addDatabaseScriptResource(resource.get()); + resource->bind(toJS(m_scriptContext), ScriptObject(toJS(m_scriptObject))); +} +#endif + +#if ENABLE(DOM_STORAGE) +void InspectorController::didUseDOMStorage(StorageArea* storageArea, bool isLocalStorage, Frame* frame) +{ + if (!enabled()) + return; + + DOMStorageResourcesSet::iterator domStorageEnd = m_domStorageResources.end(); + for (DOMStorageResourcesSet::iterator it = m_domStorageResources.begin(); it != domStorageEnd; ++it) + if ((*it)->isSameHostAndType(frame, isLocalStorage)) + return; + + RefPtr<Storage> domStorage = Storage::create(frame, storageArea); + RefPtr<InspectorDOMStorageResource> resource = InspectorDOMStorageResource::create(domStorage.get(), isLocalStorage, frame); + + m_domStorageResources.add(resource); + if (windowVisible()) + resource->bind(toJS(m_scriptContext), ScriptObject(toJS(m_scriptObject))); } #endif @@ -2680,26 +1673,23 @@ void InspectorController::removeBreakpoint(intptr_t sourceID, unsigned lineNumbe } #endif -static void drawOutlinedQuad(GraphicsContext& context, const FloatQuad& quad, const Color& fillColor) +static Path quadToPath(const FloatQuad& quad) { - static const int outlineThickness = 2; - static const Color outlineColor(62, 86, 180, 228); - Path quadPath; quadPath.moveTo(quad.p1()); quadPath.addLineTo(quad.p2()); quadPath.addLineTo(quad.p3()); quadPath.addLineTo(quad.p4()); quadPath.closeSubpath(); - - // Clear the quad - { - context.save(); - context.setCompositeOperation(CompositeClear); - context.addPath(quadPath); - context.fillPath(); - context.restore(); - } + return quadPath; +} + +static void drawOutlinedQuad(GraphicsContext& context, const FloatQuad& quad, const Color& fillColor) +{ + static const int outlineThickness = 2; + static const Color outlineColor(62, 86, 180, 228); + + Path quadPath = quadToPath(quad); // Clip out the quad, then draw with a 2px stroke to get a pixel // of outline (because inflating a quad is hard) @@ -2722,29 +1712,40 @@ static void drawOutlinedQuad(GraphicsContext& context, const FloatQuad& quad, co context.fillPath(); } -static void drawHighlightForBoxes(GraphicsContext& context, const Vector<FloatQuad>& lineBoxQuads, const FloatQuad& contentQuad, const FloatQuad& paddingQuad, const FloatQuad& borderQuad, const FloatQuad& marginQuad) +static void drawOutlinedQuadWithClip(GraphicsContext& context, const FloatQuad& quad, const FloatQuad& clipQuad, const Color& fillColor) +{ + context.save(); + Path clipQuadPath = quadToPath(clipQuad); + context.clipOut(clipQuadPath); + drawOutlinedQuad(context, quad, fillColor); + context.restore(); +} + +static void drawHighlightForBox(GraphicsContext& context, const FloatQuad& contentQuad, const FloatQuad& paddingQuad, const FloatQuad& borderQuad, const FloatQuad& marginQuad) { static const Color contentBoxColor(125, 173, 217, 128); static const Color paddingBoxColor(125, 173, 217, 160); static const Color borderBoxColor(125, 173, 217, 192); static const Color marginBoxColor(125, 173, 217, 228); - if (!lineBoxQuads.isEmpty()) { - for (size_t i = 0; i < lineBoxQuads.size(); ++i) - drawOutlinedQuad(context, lineBoxQuads[i], contentBoxColor); - return; - } - if (marginQuad != borderQuad) - drawOutlinedQuad(context, marginQuad, marginBoxColor); + drawOutlinedQuadWithClip(context, marginQuad, borderQuad, marginBoxColor); if (borderQuad != paddingQuad) - drawOutlinedQuad(context, borderQuad, borderBoxColor); + drawOutlinedQuadWithClip(context, borderQuad, paddingQuad, borderBoxColor); if (paddingQuad != contentQuad) - drawOutlinedQuad(context, paddingQuad, paddingBoxColor); + drawOutlinedQuadWithClip(context, paddingQuad, contentQuad, paddingBoxColor); drawOutlinedQuad(context, contentQuad, contentBoxColor); } +static void drawHighlightForLineBoxes(GraphicsContext& context, const Vector<FloatQuad>& lineBoxQuads) +{ + static const Color lineBoxColor(125, 173, 217, 128); + + for (size_t i = 0; i < lineBoxQuads.size(); ++i) + drawOutlinedQuad(context, lineBoxQuads[i], lineBoxColor); +} + static inline void convertFromFrameToMainFrame(Frame* frame, IntRect& rect) { rect = frame->page()->mainFrame()->view()->windowToContents(frame->view()->contentsToWindow(rect)); @@ -2761,71 +1762,57 @@ void InspectorController::drawNodeHighlight(GraphicsContext& context) const if (!m_highlightedNode) return; - RenderBox* renderer = m_highlightedNode->renderBox(); + RenderObject* renderer = m_highlightedNode->renderer(); Frame* containingFrame = m_highlightedNode->document()->frame(); if (!renderer || !containingFrame) return; - IntRect contentBox = renderer->contentBoxRect(); - - // FIXME: Should we add methods to RenderObject to obtain these rects? - IntRect paddingBox(contentBox.x() - renderer->paddingLeft(), contentBox.y() - renderer->paddingTop(), - contentBox.width() + renderer->paddingLeft() + renderer->paddingRight(), contentBox.height() + renderer->paddingTop() + renderer->paddingBottom()); - IntRect borderBox(paddingBox.x() - renderer->borderLeft(), paddingBox.y() - renderer->borderTop(), - paddingBox.width() + renderer->borderLeft() + renderer->borderRight(), paddingBox.height() + renderer->borderTop() + renderer->borderBottom()); - IntRect marginBox(borderBox.x() - renderer->marginLeft(), borderBox.y() - renderer->marginTop(), - borderBox.width() + renderer->marginLeft() + renderer->marginRight(), borderBox.height() + renderer->marginTop() + renderer->marginBottom()); - - IntSize mainFrameOffset = frameToMainFrameOffset(containingFrame); - - FloatQuad absContentQuad = renderer->localToAbsoluteQuad(FloatRect(contentBox)); - FloatQuad absPaddingQuad = renderer->localToAbsoluteQuad(FloatRect(paddingBox)); - FloatQuad absBorderQuad = renderer->localToAbsoluteQuad(FloatRect(borderBox)); - FloatQuad absMarginQuad = renderer->localToAbsoluteQuad(FloatRect(marginBox)); - - absContentQuad.move(mainFrameOffset); - absPaddingQuad.move(mainFrameOffset); - absBorderQuad.move(mainFrameOffset); - absMarginQuad.move(mainFrameOffset); - IntRect boundingBox = renderer->absoluteBoundingBoxRect(true); boundingBox.move(mainFrameOffset); - Vector<FloatQuad> lineBoxQuads; - if (renderer->isInline() || (renderer->isText() && !m_highlightedNode->isSVGElement())) { - // FIXME: We should show margins/padding/border for inlines. - renderer->collectAbsoluteLineBoxQuads(lineBoxQuads); - } - - for (unsigned i = 0; i < lineBoxQuads.size(); ++i) - lineBoxQuads[i] += mainFrameOffset; - - if (lineBoxQuads.isEmpty() && contentBox.isEmpty()) { - // If we have no line boxes and our content box is empty, we'll just draw our bounding box. - // This can happen, e.g., with an <a> enclosing an <img style="float:right">. - // FIXME: Can we make this better/more accurate? The <a> in the above case has no - // width/height but the highlight makes it appear to be the size of the <img>. - lineBoxQuads.append(FloatRect(boundingBox)); - } - ASSERT(m_inspectedPage); FrameView* view = m_inspectedPage->mainFrame()->view(); FloatRect overlayRect = view->visibleContentRect(); - - if (!overlayRect.contains(boundingBox) && !boundingBox.contains(enclosingIntRect(overlayRect))) { - Element* element; - if (m_highlightedNode->isElementNode()) - element = static_cast<Element*>(m_highlightedNode.get()); - else - element = static_cast<Element*>(m_highlightedNode->parent()); + if (!overlayRect.contains(boundingBox) && !boundingBox.contains(enclosingIntRect(overlayRect))) overlayRect = view->visibleContentRect(); - } - context.translate(-overlayRect.x(), -overlayRect.y()); - drawHighlightForBoxes(context, lineBoxQuads, absContentQuad, absPaddingQuad, absBorderQuad, absMarginQuad); + if (renderer->isBox()) { + RenderBox* renderBox = toRenderBox(renderer); + + IntRect contentBox = renderBox->contentBoxRect(); + + IntRect paddingBox(contentBox.x() - renderBox->paddingLeft(), contentBox.y() - renderBox->paddingTop(), + contentBox.width() + renderBox->paddingLeft() + renderBox->paddingRight(), contentBox.height() + renderBox->paddingTop() + renderBox->paddingBottom()); + IntRect borderBox(paddingBox.x() - renderBox->borderLeft(), paddingBox.y() - renderBox->borderTop(), + paddingBox.width() + renderBox->borderLeft() + renderBox->borderRight(), paddingBox.height() + renderBox->borderTop() + renderBox->borderBottom()); + IntRect marginBox(borderBox.x() - renderBox->marginLeft(), borderBox.y() - renderBox->marginTop(), + borderBox.width() + renderBox->marginLeft() + renderBox->marginRight(), borderBox.height() + renderBox->marginTop() + renderBox->marginBottom()); + + FloatQuad absContentQuad = renderBox->localToAbsoluteQuad(FloatRect(contentBox)); + FloatQuad absPaddingQuad = renderBox->localToAbsoluteQuad(FloatRect(paddingBox)); + FloatQuad absBorderQuad = renderBox->localToAbsoluteQuad(FloatRect(borderBox)); + FloatQuad absMarginQuad = renderBox->localToAbsoluteQuad(FloatRect(marginBox)); + + absContentQuad.move(mainFrameOffset); + absPaddingQuad.move(mainFrameOffset); + absBorderQuad.move(mainFrameOffset); + absMarginQuad.move(mainFrameOffset); + + drawHighlightForBox(context, absContentQuad, absPaddingQuad, absBorderQuad, absMarginQuad); + } else if (renderer->isRenderInline()) { + RenderInline* renderInline = toRenderInline(renderer); + + // FIXME: We should show margins/padding/border for inlines. + Vector<FloatQuad> lineBoxQuads; + renderInline->absoluteQuadsForRange(lineBoxQuads); + for (unsigned i = 0; i < lineBoxQuads.size(); ++i) + lineBoxQuads[i] += mainFrameOffset; + + drawHighlightForLineBoxes(context, lineBoxQuads); + } } void InspectorController::count(const String& title, unsigned lineNumber, const String& sourceID) diff --git a/WebCore/inspector/InspectorController.h b/WebCore/inspector/InspectorController.h index e52bee9..96b5e6f 100644 --- a/WebCore/inspector/InspectorController.h +++ b/WebCore/inspector/InspectorController.h @@ -36,6 +36,7 @@ #include <JavaScriptCore/JSContextRef.h> #include <wtf/HashMap.h> #include <wtf/HashSet.h> +#include <wtf/RefCounted.h> #include <wtf/Vector.h> #if ENABLE(JAVASCRIPT_DEBUGGER) @@ -57,27 +58,30 @@ class GraphicsContext; class HitTestResult; class InspectorClient; class JavaScriptCallFrame; +class StorageArea; class Node; class Page; -class ResourceRequest; +struct ResourceRequest; class ResourceResponse; class ResourceError; class ScriptCallStack; class SharedBuffer; -struct ConsoleMessage; -struct InspectorDatabaseResource; -struct InspectorResource; +class ConsoleMessage; +class InspectorDatabaseResource; +class InspectorDOMStorageResource; +class InspectorResource; -class InspectorController +class InspectorController : public RefCounted<InspectorController> #if ENABLE(JAVASCRIPT_DEBUGGER) - : JavaScriptDebugListener + , JavaScriptDebugListener #endif { public: typedef HashMap<long long, RefPtr<InspectorResource> > ResourcesMap; typedef HashMap<RefPtr<Frame>, ResourcesMap*> FrameResourcesMap; typedef HashSet<RefPtr<InspectorDatabaseResource> > DatabaseResourcesSet; + typedef HashSet<RefPtr<InspectorDOMStorageResource> > DOMStorageResourcesSet; typedef enum { CurrentPanel, @@ -126,7 +130,11 @@ public: } m_simpleContent; }; - InspectorController(Page*, InspectorClient*); + static PassRefPtr<InspectorController> create(Page* page, InspectorClient* inspectorClient) + { + return adoptRef(new InspectorController(page, inspectorClient)); + } + ~InspectorController(); void inspectedPageDestroyed(); @@ -140,6 +148,7 @@ public: void setSetting(const String& key, const Setting&); String localizedStringsURL(); + String hiddenPanels(); void inspect(Node*); void highlight(Node*); @@ -161,6 +170,7 @@ public: bool windowVisible(); void setWindowVisible(bool visible = true, bool attached = false); + bool addSourceToFrame(const String& mimeType, const String& source, Node*); void addMessageToConsole(MessageSource, MessageLevel, ScriptCallStack*); void addMessageToConsole(MessageSource, MessageLevel, const String& message, unsigned lineNumber, const String& sourceID); void clearConsoleMessages(); @@ -205,10 +215,14 @@ public: void didFinishLoading(DocumentLoader*, unsigned long identifier); void didFailLoading(DocumentLoader*, unsigned long identifier, const ResourceError&); void resourceRetrievedByXMLHttpRequest(unsigned long identifier, const JSC::UString& sourceString); + void scriptImported(unsigned long identifier, const JSC::UString& sourceString); #if ENABLE(DATABASE) void didOpenDatabase(Database*, const String& domain, const String& name, const String& version); #endif +#if ENABLE(DOM_STORAGE) + void didUseDOMStorage(StorageArea* storageArea, bool isLocalStorage, Frame* frame); +#endif const ResourcesMap& resources() const { return m_resources; } @@ -246,11 +260,13 @@ public: void startGroup(MessageSource source, ScriptCallStack* callFrame); void endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL); + const String& platform() const; + private: + InspectorController(Page*, InspectorClient*); void focusNode(); void addConsoleMessage(JSC::ExecState*, ConsoleMessage*); - void addScriptConsoleMessage(const ConsoleMessage*); void addResource(InspectorResource*); void removeResource(InspectorResource*); @@ -269,11 +285,6 @@ private: void pruneResources(ResourcesMap*, DocumentLoader* loaderToKeep = 0); void removeAllResources(ResourcesMap* map) { pruneResources(map); } -#if ENABLE(DATABASE) - JSObjectRef addDatabaseScriptResource(InspectorDatabaseResource*); - void removeDatabaseScriptResource(InspectorDatabaseResource*); -#endif - JSValueRef callSimpleFunction(JSContextRef, JSObjectRef thisObject, const char* functionName) const; JSValueRef callFunction(JSContextRef, JSObjectRef thisObject, const char* functionName, size_t argumentCount, const JSValueRef arguments[], JSValueRef& exception) const; @@ -302,6 +313,9 @@ private: #if ENABLE(DATABASE) DatabaseResourcesSet m_databaseResources; #endif +#if ENABLE(DOM_STORAGE) + DOMStorageResourcesSet m_domStorageResources; +#endif JSObjectRef m_scriptObject; JSObjectRef m_controllerScriptObject; JSContextRef m_scriptContext; diff --git a/WebCore/inspector/InspectorController.idl b/WebCore/inspector/InspectorController.idl new file mode 100644 index 0000000..0cb8041 --- /dev/null +++ b/WebCore/inspector/InspectorController.idl @@ -0,0 +1,91 @@ +/* + * 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. + */ + +module core { + interface [ + GenerateConstructor + ] InspectorController { + [ImplementationFunction=hideHighlight] void hideDOMNodeHighlight(); + [Custom] void highlightDOMNode(in Node node); + [ImplementationFunction=scriptObjectReady] void loaded(); + [ImplementationFunction=close] void windowUnloading(); + [ImplementationFunction=attachWindow] void attach(); + [ImplementationFunction=detachWindow] void detach(); + + void enableDebugger(); + void disableDebugger(); + void pauseInDebugger(); + void resumeDebugger(); + void stepOverStatementInDebugger(); + void stepIntoStatementInDebugger(); + void stepOutOfFunctionInDebugger(); + + void closeWindow(); + [ImplementationFunction=clearConsoleMessages] void clearMessages(); + [ImplementationFunction=startUserInitiatedProfiling] void startProfiling(); + [ImplementationFunction=stopUserInitiatedProfiling] void stopProfiling(); + void enableProfiler(); + void disableProfiler(); + [ImplementationFunction=toggleSearchForNodeInPage] void toggleNodeSearch(); + + boolean debuggerEnabled(); + boolean pauseOnExceptions(); + + boolean profilerEnabled(); + [ImplementationFunction=windowVisible] boolean isWindowVisible(); + [ImplementationFunction=searchingForNodeInPage] boolean searchingForNode(); + + [Custom] void addResourceSourceToFrame(in unsigned long identifier, in Node frame); + [Custom] void addSourceToFrame(in DOMString mimeType, in DOMString sourceValue, in Node frame); + [Custom] Node getResourceDocumentNode(in unsigned long identifier); + [Custom] void search(in Node node, in DOMString query); +#if ENABLE_DATABASE + [Custom] DOMObject databaseTableNames(in Database database); +#endif + [Custom] DOMObject setting(in DOMString key); + [Custom] void setSetting(in DOMString key, in DOMObject value); + [Custom] DOMWindow inspectedWindow(); + DOMString localizedStringsURL(); + DOMString hiddenPanels(); + DOMString platform(); + [ImplementationFunction=moveWindowBy] void moveByUnrestricted(in float x, in float y); + void setAttachedWindowHeight(in unsigned long height); + [Custom] DOMObject wrapCallback(in DOMObject callback); + + [Custom] DOMObject currentCallFrame(); + void setPauseOnExceptions(in boolean pauseOnExceptions); + void addBreakpoint(in unsigned long sourceID, in unsigned long lineNumber); + void removeBreakpoint(in unsigned long sourceID, in unsigned long lineNumber); + + [Custom] Array profiles(); + }; + } diff --git a/WebCore/inspector/InspectorDOMStorageResource.cpp b/WebCore/inspector/InspectorDOMStorageResource.cpp new file mode 100644 index 0000000..33d036e --- /dev/null +++ b/WebCore/inspector/InspectorDOMStorageResource.cpp @@ -0,0 +1,95 @@ +/* + * 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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" +#if ENABLE(DOM_STORAGE) + +#include "InspectorDOMStorageResource.h" + +#include "Document.h" +#include "Frame.h" +#include "ScriptFunctionCall.h" +#include "ScriptObjectQuarantine.h" +#include "ScriptValue.h" +#include "Storage.h" + +using namespace JSC; + +namespace WebCore { + +InspectorDOMStorageResource::InspectorDOMStorageResource(Storage* domStorage, bool isLocalStorage, Frame* frame) + : m_domStorage(domStorage) + , m_isLocalStorage(isLocalStorage) + , m_frame(frame) +{ +} + +bool InspectorDOMStorageResource::isSameHostAndType(Frame* frame, bool isLocalStorage) const +{ + return equalIgnoringCase(m_frame->document()->securityOrigin()->host(), frame->document()->securityOrigin()->host()) && m_isLocalStorage == isLocalStorage; +} + +void InspectorDOMStorageResource::bind(ScriptState* scriptState, const ScriptObject& webInspector) +{ + if (!m_scriptObject.hasNoValue()) + return; + + ASSERT(scriptState); + ASSERT(!webInspector.hasNoValue()); + if (!scriptState || webInspector.hasNoValue()) + return; + + ScriptFunctionCall resourceConstructor(scriptState, webInspector, "DOMStorage"); + ScriptObject domStorage; + if (!getQuarantinedScriptObject(m_frame.get(), m_domStorage.get(), domStorage)) + return; + + resourceConstructor.appendArgument(domStorage); + resourceConstructor.appendArgument(m_frame->document()->securityOrigin()->host()); + resourceConstructor.appendArgument(m_isLocalStorage); + + bool hadException = false; + m_scriptObject = resourceConstructor.construct(hadException); + if (hadException) + return; + + ScriptFunctionCall addDOMStorage(scriptState, webInspector, "addDOMStorage"); + addDOMStorage.appendArgument(m_scriptObject); + addDOMStorage.call(hadException); +} + +void InspectorDOMStorageResource::unbind() +{ + m_scriptObject = ScriptObject(); +} + +} // namespace WebCore + +#endif diff --git a/WebCore/inspector/InspectorDOMStorageResource.h b/WebCore/inspector/InspectorDOMStorageResource.h new file mode 100644 index 0000000..ad3e196 --- /dev/null +++ b/WebCore/inspector/InspectorDOMStorageResource.h @@ -0,0 +1,76 @@ +/* + * 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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. + */ + +#ifndef InspectorDOMStorageResource_h +#define InspectorDOMStorageResource_h + +#if ENABLE(DOM_STORAGE) + +#include "ScriptObject.h" +#include "ScriptState.h" + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + + class Storage; + class Frame; + + class InspectorDOMStorageResource : public RefCounted<InspectorDOMStorageResource> { + public: + static PassRefPtr<InspectorDOMStorageResource> create(Storage* domStorage, bool isLocalStorage, Frame* frame) + { + return adoptRef(new InspectorDOMStorageResource(domStorage, isLocalStorage, frame)); + } + + void bind(ScriptState*, const ScriptObject& webInspector); + void unbind(); + + bool isSameHostAndType(Frame*, bool isLocalStorage) const; + + private: + + InspectorDOMStorageResource(Storage*, bool isLocalStorage, Frame*); + + ScriptObject m_scriptObject; + RefPtr<Storage> m_domStorage; + bool m_isLocalStorage; + RefPtr<Frame> m_frame; + + private: + }; + +} // namespace WebCore + +#endif + +#endif // InspectorDOMStorageResource_h diff --git a/WebCore/inspector/InspectorDatabaseResource.cpp b/WebCore/inspector/InspectorDatabaseResource.cpp new file mode 100644 index 0000000..43cd8ef --- /dev/null +++ b/WebCore/inspector/InspectorDatabaseResource.cpp @@ -0,0 +1,89 @@ +/* + * 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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" +#if ENABLE(DATABASE) +#include "InspectorDatabaseResource.h" + +#include "Database.h" +#include "Document.h" +#include "Frame.h" +#include "ScriptFunctionCall.h" +#include "ScriptObjectQuarantine.h" +#include "ScriptValue.h" + +namespace WebCore { + +InspectorDatabaseResource::InspectorDatabaseResource(Database* database, const String& domain, const String& name, const String& version) + : m_database(database) + , m_domain(domain) + , m_name(name) + , m_version(version) +{ +} + +void InspectorDatabaseResource::bind(ScriptState* scriptState, const ScriptObject& webInspector) +{ + if (!m_scriptObject.hasNoValue()) + return; + + ASSERT(scriptState); + ASSERT(!webInspector.hasNoValue()); + if (!scriptState || webInspector.hasNoValue()) + return; + + ScriptFunctionCall resourceConstructor(scriptState, webInspector, "Database"); + ScriptObject database; + if (!getQuarantinedScriptObject(m_database.get(), database)) + return; + + resourceConstructor.appendArgument(database); + resourceConstructor.appendArgument(m_domain); + resourceConstructor.appendArgument(m_name); + resourceConstructor.appendArgument(m_version); + + bool hadException = false; + m_scriptObject = resourceConstructor.construct(hadException); + if (hadException) + return; + + ScriptFunctionCall addDatabase(scriptState, webInspector, "addDatabase"); + addDatabase.appendArgument(m_scriptObject); + addDatabase.call(hadException); +} + +void InspectorDatabaseResource::unbind() +{ + m_scriptObject = ScriptObject(); +} + +} // namespace WebCore + +#endif // ENABLE(DATABASE) diff --git a/WebCore/inspector/InspectorDatabaseResource.h b/WebCore/inspector/InspectorDatabaseResource.h new file mode 100644 index 0000000..1be2334 --- /dev/null +++ b/WebCore/inspector/InspectorDatabaseResource.h @@ -0,0 +1,70 @@ +/* + * 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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. + */ + +#ifndef InspectorDatabaseResource_h +#define InspectorDatabaseResource_h + +#if ENABLE(DATABASE) + +#include "Database.h" +#include "ScriptObject.h" +#include "ScriptState.h" + +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace WebCore { + + class InspectorDatabaseResource : public RefCounted<InspectorDatabaseResource> { + public: + static PassRefPtr<InspectorDatabaseResource> create(Database* database, const String& domain, const String& name, const String& version) + { + return adoptRef(new InspectorDatabaseResource(database, domain, name, version)); + } + + void bind(ScriptState*, const ScriptObject& webInspector); + void unbind(); + + private: + InspectorDatabaseResource(Database*, const String& domain, const String& name, const String& version); + ScriptObject m_scriptObject; + + RefPtr<Database> m_database; + String m_domain; + String m_name; + String m_version; + }; + +} // namespace WebCore + +#endif // ENABLE(DATABASE) + +#endif // InspectorDatabaseResource_h diff --git a/WebCore/inspector/InspectorResource.cpp b/WebCore/inspector/InspectorResource.cpp new file mode 100644 index 0000000..7db6cd1 --- /dev/null +++ b/WebCore/inspector/InspectorResource.cpp @@ -0,0 +1,181 @@ +/* + * 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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 "InspectorResource.h" + +#include "CachedResource.h" +#include "DocLoader.h" +#include "DocumentLoader.h" +#include "Frame.h" +#include "TextEncoding.h" + +#include <runtime/JSLock.h> + +namespace WebCore { + +// XMLHttpRequestResource Class + +struct XMLHttpRequestResource { + XMLHttpRequestResource(const JSC::UString& sourceString) + { + JSC::JSLock lock(false); + this->sourceString = sourceString.rep(); + } + + ~XMLHttpRequestResource() + { + JSC::JSLock lock(false); + sourceString.clear(); + } + + RefPtr<JSC::UString::Rep> sourceString; +}; + + InspectorResource::InspectorResource(long long identifier, DocumentLoader* documentLoader, Frame* frame) + : identifier(identifier) + , loader(documentLoader) + , frame(frame) + , scriptContext(0) + , scriptObject(0) + , expectedContentLength(0) + , cached(false) + , finished(false) + , failed(false) + , length(0) + , responseStatusCode(0) + , startTime(-1.0) + , responseReceivedTime(-1.0) + , endTime(-1.0) + , xmlHttpRequestResource(0) + { + } + +InspectorResource::~InspectorResource() +{ + setScriptObject(0, 0); +} + +InspectorResource::Type InspectorResource::type() const +{ + if (xmlHttpRequestResource) + return XHR; + + if (requestURL == loader->requestURL()) + return Doc; + + if (loader->frameLoader() && requestURL == loader->frameLoader()->iconURL()) + return Image; + + CachedResource* cachedResource = frame->document()->docLoader()->cachedResource(requestURL.string()); + if (!cachedResource) + return Other; + + switch (cachedResource->type()) { + case CachedResource::ImageResource: + return Image; + case CachedResource::FontResource: + return Font; + case CachedResource::CSSStyleSheet: +#if ENABLE(XSLT) + case CachedResource::XSLStyleSheet: +#endif + return Stylesheet; + case CachedResource::Script: + return Script; + default: + return Other; + } +} + +void InspectorResource::setScriptObject(JSContextRef context, JSObjectRef newScriptObject) +{ + if (scriptContext && scriptObject) + JSValueUnprotect(scriptContext, scriptObject); + + scriptObject = newScriptObject; + scriptContext = context; + + ASSERT((context && newScriptObject) || (!context && !newScriptObject)); + if (context && newScriptObject) + JSValueProtect(context, newScriptObject); +} + +void InspectorResource::setXMLHttpRequestProperties(const JSC::UString& data) +{ + xmlHttpRequestResource.set(new XMLHttpRequestResource(data)); +} + +void InspectorResource::setScriptProperties(const JSC::UString& data) +{ + xmlHttpRequestResource.set(new XMLHttpRequestResource(data)); +} + +String InspectorResource::sourceString() const +{ + if (xmlHttpRequestResource) + return JSC::UString(xmlHttpRequestResource->sourceString); + + RefPtr<SharedBuffer> buffer; + String textEncodingName; + + if (requestURL == loader->requestURL()) { + buffer = loader->mainResourceData(); + textEncodingName = frame->document()->inputEncoding(); + } else { + CachedResource* cachedResource = frame->document()->docLoader()->cachedResource(requestURL.string()); + if (!cachedResource) + return String(); + + if (cachedResource->isPurgeable()) { + // If the resource is purgeable then make it unpurgeable to get + // get its data. This might fail, in which case we return an + // empty String. + // FIXME: should we do something else in the case of a purged + // resource that informs the user why there is no data in the + // inspector? + if (!cachedResource->makePurgeable(false)) + return String(); + } + + buffer = cachedResource->data(); + textEncodingName = cachedResource->encoding(); + } + + if (!buffer) + return String(); + + TextEncoding encoding(textEncodingName); + if (!encoding.isValid()) + encoding = WindowsLatin1Encoding(); + return encoding.decode(buffer->data(), buffer->size()); +} + +} // namespace WebCore diff --git a/WebCore/inspector/InspectorResource.h b/WebCore/inspector/InspectorResource.h new file mode 100644 index 0000000..46d7fed --- /dev/null +++ b/WebCore/inspector/InspectorResource.h @@ -0,0 +1,109 @@ +/* + * 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 APPLE AND ITS 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 APPLE OR ITS 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. + */ + +#ifndef InspectorResource_h +#define InspectorResource_h + +#include <JavaScriptCore/JSContextRef.h> + +#include "HTTPHeaderMap.h" +#include "KURL.h" + +#include <wtf/OwnPtr.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> +#include <wtf/RefPtr.h> + +namespace JSC { + class UString; +} + +namespace WebCore { + class DocumentLoader; + class Frame; + struct XMLHttpRequestResource; + + class InspectorResource : public RefCounted<InspectorResource> { + public: + + // Keep these in sync with WebInspector.Resource.Type + enum Type { + Doc, + Stylesheet, + Image, + Font, + Script, + XHR, + Media, + Other + }; + + static PassRefPtr<InspectorResource> create(long long identifier, DocumentLoader* documentLoader, Frame* frame) + { + return adoptRef(new InspectorResource(identifier, documentLoader, frame)); + } + + ~InspectorResource(); + Type type() const; + void setScriptObject(JSContextRef, JSObjectRef); + void setXMLHttpRequestProperties(const JSC::UString& data); + void setScriptProperties(const JSC::UString& data); + + String sourceString() const; + + long long identifier; + RefPtr<DocumentLoader> loader; + RefPtr<Frame> frame; + KURL requestURL; + HTTPHeaderMap requestHeaderFields; + HTTPHeaderMap responseHeaderFields; + String mimeType; + String suggestedFilename; + JSContextRef scriptContext; + JSObjectRef scriptObject; + long long expectedContentLength; + bool cached; + bool finished; + bool failed; + int length; + int responseStatusCode; + double startTime; + double responseReceivedTime; + double endTime; + + private: + InspectorResource(long long identifier, DocumentLoader*, Frame*); + + OwnPtr<XMLHttpRequestResource> xmlHttpRequestResource; + }; + +} // namespace WebCore + +#endif // InspectorResource_h diff --git a/WebCore/inspector/JavaScriptDebugServer.cpp b/WebCore/inspector/JavaScriptDebugServer.cpp index 05dca70..62ccad4 100644 --- a/WebCore/inspector/JavaScriptDebugServer.cpp +++ b/WebCore/inspector/JavaScriptDebugServer.cpp @@ -363,12 +363,11 @@ void JavaScriptDebugServer::setJavaScriptPaused(Frame* frame, bool paused) frame->script()->setPaused(paused); - if (Document* document = frame->document()) { - if (paused) - document->suspendActiveDOMObjects(); - else - document->resumeActiveDOMObjects(); - } + Document* document = frame->document(); + if (paused) + document->suspendActiveDOMObjects(); + else + document->resumeActiveDOMObjects(); setJavaScriptPaused(frame->view(), paused); } diff --git a/WebCore/inspector/front-end/Console.js b/WebCore/inspector/front-end/Console.js index 31e466c..ba879a0 100644 --- a/WebCore/inspector/front-end/Console.js +++ b/WebCore/inspector/front-end/Console.js @@ -141,7 +141,7 @@ WebInspector.Console.prototype = { addMessage: function(msg) { - if (msg instanceof WebInspector.ConsoleMessage) { + if (msg instanceof WebInspector.ConsoleMessage && !(msg instanceof WebInspector.ConsoleCommandResult)) { msg.totalRepeatCount = msg.repeatCount; msg.repeatDelta = msg.repeatCount; @@ -446,6 +446,9 @@ WebInspector.Console.prototype = { if (!str.length) return; + var commandMessage = new WebInspector.ConsoleCommand(str); + this.addMessage(commandMessage); + var result; var exception = false; try { @@ -459,31 +462,12 @@ WebInspector.Console.prototype = { this.prompt.historyOffset = 0; this.prompt.text = ""; - var level = exception ? WebInspector.ConsoleMessage.MessageLevel.Error : WebInspector.ConsoleMessage.MessageLevel.Log; - this.addMessage(new WebInspector.ConsoleCommand(str, result, this._format(result), level)); - }, - - _mouseOverNode: function(event) - { - var anchorElement = event.target.enclosingNodeOrSelfWithNodeName("a"); - WebInspector.hoveredDOMNode = (anchorElement ? anchorElement.representedNode : null); - }, - - _mouseOutOfNode: function(event) - { - var nodeUnderMouse = document.elementFromPoint(event.pageX, event.pageY); - var anchorElement = nodeUnderMouse.enclosingNodeOrSelfWithNodeName("a"); - if (!anchorElement || !anchorElement.representedNode) - WebInspector.hoveredDOMNode = null; + this.addMessage(new WebInspector.ConsoleCommandResult(result, exception, commandMessage)); }, - _format: function(output, inline) + _format: function(output, forceObjectFormat) { - var type = Object.type(output, InspectorController.inspectedWindow()); - if (type === "object") { - if (output instanceof InspectorController.inspectedWindow().Node) - type = "node"; - } + var type = (forceObjectFormat ? "object" : Object.type(output, InspectorController.inspectedWindow())); // We don't perform any special formatting on these types, so we just // pass them through the simple _formatvalue function. @@ -497,7 +481,9 @@ WebInspector.Console.prototype = { }; var formatter; - if (type in undecoratedTypes) + if (forceObjectFormat) + formatter = "_formatobject"; + else if (type in undecoratedTypes) formatter = "_formatvalue"; else { formatter = "_format" + type; @@ -509,77 +495,74 @@ WebInspector.Console.prototype = { var span = document.createElement("span"); span.addStyleClass("console-formatted-" + type); - this[formatter](output, span, inline); + this[formatter](output, span); return span; }, - _formatvalue: function(val, elem, inline) + _formatvalue: function(val, elem) { elem.appendChild(document.createTextNode(val)); }, - _formatstring: function(str, elem, inline) + _formatstring: function(str, elem) { elem.appendChild(document.createTextNode("\"" + str + "\"")); }, - _formatregexp: function(re, elem, inline) + _formatregexp: function(re, elem) { var formatted = String(re).replace(/([\\\/])/g, "\\$1").replace(/\\(\/[gim]*)$/, "$1").substring(1); elem.appendChild(document.createTextNode(formatted)); }, - _formatarray: function(arr, elem, inline) + _formatarray: function(arr, elem) { elem.appendChild(document.createTextNode("[")); for (var i = 0; i < arr.length; ++i) { - elem.appendChild(this._format(arr[i], true)); + elem.appendChild(this._format(arr[i])); if (i < arr.length - 1) elem.appendChild(document.createTextNode(", ")); } elem.appendChild(document.createTextNode("]")); }, - _formatnode: function(node, elem, inline) + _formatnode: function(node, elem) { - var anchor = document.createElement("a"); - anchor.className = "inspectible-node"; - anchor.innerHTML = nodeTitleInfo.call(node).title; - anchor.representedNode = node; - anchor.addEventListener("mouseover", this._mouseOverNode.bind(this), false); - anchor.addEventListener("mouseout", this._mouseOutOfNode.bind(this), false); - - if (inline) - elem.appendChild(anchor); - else - elem.appendChild(new WebInspector.ObjectPropertiesSection(node, anchor, null, null, true).element); + var treeOutline = new WebInspector.ElementsTreeOutline(); + treeOutline.rootDOMNode = node; + treeOutline.element.addStyleClass("outline-disclosure"); + if (!treeOutline.children[0].hasChildren) + treeOutline.element.addStyleClass("single-node"); + elem.appendChild(treeOutline.element); }, - _formatobject: function(obj, elem, inline) + _formatobject: function(obj, elem) { - if (inline) - elem.appendChild(document.createTextNode(Object.describe(obj))); - else - elem.appendChild(new WebInspector.ObjectPropertiesSection(obj, null, null, null, true).element); + elem.appendChild(new WebInspector.ObjectPropertiesSection(obj, null, null, null, true).element); }, - _formaterror: function(obj, elem, inline) + _formaterror: function(obj, elem) { - elem.appendChild(document.createTextNode(obj.name + ": " + obj.message + " ")); + var messageElement = document.createElement("span"); + messageElement.className = "error-message"; + messageElement.textContent = obj.name + ": " + obj.message; + elem.appendChild(messageElement); if (obj.sourceURL) { var urlElement = document.createElement("a"); - urlElement.className = "console-message-url webkit-html-resource-link"; + urlElement.className = "webkit-html-resource-link"; urlElement.href = obj.sourceURL; urlElement.lineNumber = obj.line; urlElement.preferredPanel = "scripts"; if (obj.line > 0) - urlElement.textContent = WebInspector.UIString("%s (line %d)", obj.sourceURL, obj.line); + urlElement.textContent = WebInspector.displayNameForURL(obj.sourceURL) + ":" + obj.line; else - urlElement.textContent = obj.sourceURL; + urlElement.textContent = WebInspector.displayNameForURL(obj.sourceURL); + elem.appendChild(document.createTextNode(" (")); elem.appendChild(urlElement); + elem.appendChild(document.createTextNode(")")); } }, } @@ -596,18 +579,6 @@ WebInspector.ConsoleMessage = function(source, level, line, url, groupLevel, rep this.repeatCount = repeatCount; switch (this.level) { - case WebInspector.ConsoleMessage.MessageLevel.Object: - var propertiesSection = new WebInspector.ObjectPropertiesSection(arguments[6], null, null, null, true); - propertiesSection.element.addStyleClass("console-message"); - this.propertiesSection = propertiesSection; - break; - case WebInspector.ConsoleMessage.MessageLevel.Node: - var node = arguments[6]; - if (!(node instanceof InspectorController.inspectedWindow().Node)) - return; - this.elementsTreeOutline = new WebInspector.ElementsTreeOutline(); - this.elementsTreeOutline.rootDOMNode = node; - break; case WebInspector.ConsoleMessage.MessageLevel.Trace: var span = document.createElement("span"); span.addStyleClass("console-formatted-trace"); @@ -618,14 +589,16 @@ WebInspector.ConsoleMessage = function(source, level, line, url, groupLevel, rep span.appendChild(document.createTextNode(funcNames.join("\n"))); this.formattedMessage = span; break; + case WebInspector.ConsoleMessage.MessageLevel.Object: + this.formattedMessage = this._format(["%O", arguments[6]]); + break; default: - // The formatedMessage property is used for the rich and interactive console. this.formattedMessage = this._format(Array.prototype.slice.call(arguments, 6)); - - // This is used for inline message bubbles in SourceFrames, or other plain-text representations. - this.message = this.formattedMessage.textContent; break; } + + // This is used for inline message bubbles in SourceFrames, or other plain-text representations. + this.message = this.formattedMessage.textContent; } WebInspector.ConsoleMessage.prototype = { @@ -643,6 +616,11 @@ WebInspector.ConsoleMessage.prototype = { function formatForConsole(obj) { + return WebInspector.console._format(obj); + } + + function formatAsObjectForConsole(obj) + { return WebInspector.console._format(obj, true); } @@ -655,6 +633,8 @@ WebInspector.ConsoleMessage.prototype = { formatters.o = formatForConsole; // Firebug allows both %i and %d for formatting integers. formatters.i = formatters.d; + // Support %O to force object formating, instead of the type-based %o formatting. + formatters.O = formatAsObjectForConsole; function append(a, b) { @@ -675,10 +655,9 @@ WebInspector.ConsoleMessage.prototype = { for (var i = 0; i < parameters.length; ++i) { if (typeof parameters[i] === "string") formattedResult.appendChild(WebInspector.linkifyStringAsFragment(parameters[i])); - else if (parameters.length === 1) - formattedResult.appendChild(WebInspector.console._format(parameters[0])); else formattedResult.appendChild(formatForConsole(parameters[i])); + if (i < parameters.length - 1) formattedResult.appendChild(document.createTextNode(" ")); } @@ -758,7 +737,7 @@ WebInspector.ConsoleMessage.prototype = { urlElement.preferredPanel = "scripts"; if (this.line > 0) - urlElement.textContent = WebInspector.UIString("%s (line %d)", WebInspector.displayNameForURL(this.url), this.line); + urlElement.textContent = WebInspector.displayNameForURL(this.url) + ":" + this.line; else urlElement.textContent = WebInspector.displayNameForURL(this.url); @@ -814,14 +793,20 @@ WebInspector.ConsoleMessage.prototype = { case WebInspector.ConsoleMessage.MessageLevel.Object: levelString = "Object"; break; - case WebInspector.ConsoleMessage.MessageLevel.GroupTitle: - levelString = "GroupTitle"; + case WebInspector.ConsoleMessage.MessageLevel.Trace: + levelString = "Trace"; + break; + case WebInspector.ConsoleMessage.MessageLevel.StartGroup: + levelString = "Start Group"; + break; + case WebInspector.ConsoleMessage.MessageLevel.EndGroup: + levelString = "End Group"; break; } return sourceString + " " + levelString + ": " + this.formattedMessage.textContent + "\n" + this.url + " line " + this.line; }, - + isEqual: function(msg, disreguardGroup) { if (!msg) @@ -853,17 +838,14 @@ WebInspector.ConsoleMessage.MessageLevel = { Warning: 2, Error: 3, Object: 4, - Node: 5, - Trace: 6, - StartGroup: 7, - EndGroup: 8 + Trace: 5, + StartGroup: 6, + EndGroup: 7 } -WebInspector.ConsoleCommand = function(command, result, formattedResultElement, level) +WebInspector.ConsoleCommand = function(command) { this.command = command; - this.formattedResultElement = formattedResultElement; - this.level = level; } WebInspector.ConsoleCommand.prototype = { @@ -878,30 +860,33 @@ WebInspector.ConsoleCommand.prototype = { commandTextElement.textContent = this.command; element.appendChild(commandTextElement); - var resultElement = document.createElement("div"); - resultElement.className = "console-message"; - element.appendChild(resultElement); + return element; + } +} - switch (this.level) { - case WebInspector.ConsoleMessage.MessageLevel.Log: - resultElement.addStyleClass("console-log-level"); - break; - case WebInspector.ConsoleMessage.MessageLevel.Warning: - resultElement.addStyleClass("console-warning-level"); - break; - case WebInspector.ConsoleMessage.MessageLevel.Error: - resultElement.addStyleClass("console-error-level"); - } +WebInspector.ConsoleCommandResult = function(result, exception, originatingCommand) +{ + var level = (exception ? WebInspector.ConsoleMessage.MessageLevel.Error : WebInspector.ConsoleMessage.MessageLevel.Log); + var message = (exception ? String(result) : result); + var line = (exception ? result.line : -1); + var url = (exception ? result.sourceURL : null); + + WebInspector.ConsoleMessage.call(this, WebInspector.ConsoleMessage.MessageSource.JS, level, line, url, null, 1, message); - var resultTextElement = document.createElement("span"); - resultTextElement.className = "console-message-text"; - resultTextElement.appendChild(this.formattedResultElement); - resultElement.appendChild(resultTextElement); + this.originatingCommand = originatingCommand; +} +WebInspector.ConsoleCommandResult.prototype = { + toMessageElement: function() + { + var element = WebInspector.ConsoleMessage.prototype.toMessageElement.call(this); + element.addStyleClass("console-user-command-result"); return element; } } +WebInspector.ConsoleCommandResult.prototype.__proto__ = WebInspector.ConsoleMessage.prototype; + WebInspector.ConsoleGroup = function(parentGroup, level) { this.parentGroup = parentGroup; @@ -928,8 +913,11 @@ WebInspector.ConsoleGroup.prototype = { element.addEventListener("click", this._titleClicked.bind(this), true); } else this.messagesElement.appendChild(element); + + if (element.previousSibling && msg.originatingCommand && element.previousSibling.command === msg.originatingCommand) + element.previousSibling.addStyleClass("console-adjacent-user-command-result"); }, - + _titleClicked: function(event) { var groupTitleElement = event.target.enclosingNodeOrSelfWithClass("console-group-title-level"); diff --git a/WebCore/inspector/front-end/DOMStorage.js b/WebCore/inspector/front-end/DOMStorage.js new file mode 100644 index 0000000..5207b69 --- /dev/null +++ b/WebCore/inspector/front-end/DOMStorage.js @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2008 Nokia 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * 3. Neither the name of Apple Computer, Inc. ("Apple") 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 "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 APPLE OR ITS 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. + */ + +WebInspector.DOMStorage = function(domStorage, domain, isLocalStorage) +{ + this.domStorage = domStorage; + this.domain = domain; + this.isLocalStorage = isLocalStorage; +} + +WebInspector.DOMStorage.prototype = { + get domStorage() + { + return this._domStorage; + }, + + set domStorage(x) + { + if (this._domStorage === x) + return; + this._domStorage = x; + }, + + get domain() + { + return this._domain; + }, + + set domain(x) + { + if (this._domain === x) + return; + this._domain = x; + }, + + get isLocalStorage() + { + return this._isLocalStorage; + }, + + set isLocalStorage(x) + { + if (this._isLocalStorage === x) + return; + this._isLocalStorage = x; + } +} diff --git a/WebCore/inspector/front-end/DOMStorageDataGrid.js b/WebCore/inspector/front-end/DOMStorageDataGrid.js new file mode 100644 index 0000000..9946415 --- /dev/null +++ b/WebCore/inspector/front-end/DOMStorageDataGrid.js @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2009 Nokia 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``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 APPLE INC. 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. + */ + +WebInspector.DOMStorageDataGrid = function(columns) +{ + WebInspector.DataGrid.call(this, columns); + this.dataTableBody.addEventListener("dblclick", this._ondblclick.bind(this), false); +} + +WebInspector.DOMStorageDataGrid.prototype = { + _ondblclick: function(event) + { + if (this._editing) + return; + if (this._editingNode) + return; + this._startEditing(event); + }, + + _startEditing: function(event) + { + var element = event.target.enclosingNodeOrSelfWithNodeName("td"); + if (!element) + return; + this._editingNode = this.dataGridNodeFromEvent(event); + if (!this._editingNode) + return; + this._editing = true; + + WebInspector.startEditing(element, this._editingCommitted.bind(this), this._editingCancelled.bind(this), element.textContent); + window.getSelection().setBaseAndExtent(element, 0, element, 1); + }, + + _editingCommitted: function(element, newText) + { + if (element.hasStyleClass("0-column")) + columnIdentifier = 0; + else + columnIdentifier = 1; + textBeforeEditing = this._editingNode.data[columnIdentifier]; + if (textBeforeEditing == newText) { + this._editingCancelled(element); + return; + } + + var domStorage = WebInspector.panels.databases.visibleView.domStorage.domStorage; + if (domStorage) { + if (columnIdentifier == 0) { + if (domStorage.getItem(newText) != null) { + element.textContent = this._editingNode.data[0]; + this._editingCancelled(element); + return; + } + domStorage.removeItem(this._editingNode.data[0]); + domStorage.setItem(newText, this._editingNode.data[1]); + this._editingNode.data[0] = newText; + } else { + domStorage.setItem(this._editingNode.data[0], newText); + this._editingNode.data[1] = newText; + } + } + + this._editingCancelled(element); + }, + + _editingCancelled: function(element, context) + { + delete this._editing; + this._editingNode = null; + }, + + deleteSelectedRow: function() + { + var node = this.selectedNode; + var domStorage = WebInspector.panels.databases.visibleView.domStorage.domStorage; + if (node && domStorage) + domStorage.removeItem(node.data[0]); + } +} + +WebInspector.DOMStorageDataGrid.prototype.__proto__ = WebInspector.DataGrid.prototype; diff --git a/WebCore/inspector/front-end/DOMStorageItemsView.js b/WebCore/inspector/front-end/DOMStorageItemsView.js new file mode 100644 index 0000000..912573e --- /dev/null +++ b/WebCore/inspector/front-end/DOMStorageItemsView.js @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2008 Nokia 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: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. 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. + * + * THIS SOFTWARE IS PROVIDED ``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 APPLE INC. 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. + */ + +WebInspector.DOMStorageItemsView = function(domStorage) +{ + WebInspector.View.call(this); + + this.domStorage = domStorage; + + this.element.addStyleClass("storage-view"); + this.element.addStyleClass("table"); + + this.deleteButton = document.createElement("button"); + this.deleteButton.title = WebInspector.UIString("Delete"); + this.deleteButton.className = "delete-storage-status-bar-item status-bar-item hidden"; + this.deleteButton.addEventListener("click", this._deleteButtonClicked.bind(this), false); + + this.refreshButton = document.createElement("button"); + this.refreshButton.title = WebInspector.UIString("Refresh"); + this.refreshButton.className = "refresh-storage-status-bar-item status-bar-item"; + this.refreshButton.addEventListener("click", this._refreshButtonClicked.bind(this), false); +} + +WebInspector.DOMStorageItemsView.prototype = { + get statusBarItems() + { + return [this.refreshButton, this.deleteButton]; + }, + + show: function(parentElement) + { + WebInspector.View.prototype.show.call(this, parentElement); + this.update(); + }, + + hide: function() + { + WebInspector.View.prototype.hide.call(this); + this.deleteButton.addStyleClass("hidden"); + }, + + update: function() + { + this.element.removeChildren(); + var hasDOMStorage = this.domStorage; + if (hasDOMStorage) + hasDOMStorage = this.domStorage.domStorage; + + if (hasDOMStorage) { + var dataGrid = WebInspector.panels.databases.dataGridForDOMStorage(this.domStorage.domStorage); + if (!dataGrid) + hasDOMStorage = 0; + else { + this._dataGrid = dataGrid; + this.element.appendChild(dataGrid.element); + this.deleteButton.removeStyleClass("hidden"); + } + } + + if (!hasDOMStorage) { + var emptyMsgElement = document.createElement("div"); + emptyMsgElement.className = "storage-table-empty"; + if (this.domStorage) + emptyMsgElement.textContent = WebInspector.UIString("This storage is empty."); + this.element.appendChild(emptyMsgElement); + this._dataGrid = null; + this.deleteButton.addStyleClass("hidden"); + } + }, + + _deleteButtonClicked: function(event) + { + if (this._dataGrid) { + this._dataGrid.deleteSelectedRow(); + + this.show(); + } + }, + + _refreshButtonClicked: function(event) + { + this.update(); + } +} + +WebInspector.DOMStorageItemsView.prototype.__proto__ = WebInspector.View.prototype; diff --git a/WebCore/inspector/front-end/DatabaseQueryView.js b/WebCore/inspector/front-end/DatabaseQueryView.js index 6a91625..122707f 100644 --- a/WebCore/inspector/front-end/DatabaseQueryView.js +++ b/WebCore/inspector/front-end/DatabaseQueryView.js @@ -29,7 +29,7 @@ WebInspector.DatabaseQueryView = function(database) this.database = database; - this.element.addStyleClass("database-view"); + this.element.addStyleClass("storage-view"); this.element.addStyleClass("query"); this.element.tabIndex = 0; diff --git a/WebCore/inspector/front-end/DatabaseTableView.js b/WebCore/inspector/front-end/DatabaseTableView.js index 2e72240..bbca9d0 100644 --- a/WebCore/inspector/front-end/DatabaseTableView.js +++ b/WebCore/inspector/front-end/DatabaseTableView.js @@ -30,8 +30,13 @@ WebInspector.DatabaseTableView = function(database, tableName) this.database = database; this.tableName = tableName; - this.element.addStyleClass("database-view"); + this.element.addStyleClass("storage-view"); this.element.addStyleClass("table"); + + this.refreshButton = document.createElement("button"); + this.refreshButton.title = WebInspector.UIString("Refresh"); + this.refreshButton.className = "refresh-storage-status-bar-item status-bar-item"; + this.refreshButton.addEventListener("click", this._refreshButtonClicked.bind(this), false); } WebInspector.DatabaseTableView.prototype = { @@ -41,6 +46,11 @@ WebInspector.DatabaseTableView.prototype = { this.update(); }, + get statusBarItems() + { + return [this.refreshButton]; + }, + update: function() { function queryTransaction(tx) @@ -58,7 +68,7 @@ WebInspector.DatabaseTableView.prototype = { var dataGrid = WebInspector.panels.databases.dataGridForResult(result); if (!dataGrid) { var emptyMsgElement = document.createElement("div"); - emptyMsgElement.className = "database-table-empty"; + emptyMsgElement.className = "storage-table-empty"; emptyMsgElement.textContent = WebInspector.UIString("The ā%sā\ntable is empty.", this.tableName); this.element.appendChild(emptyMsgElement); return; @@ -72,11 +82,15 @@ WebInspector.DatabaseTableView.prototype = { this.element.removeChildren(); var errorMsgElement = document.createElement("div"); - errorMsgElement.className = "database-table-error"; + errorMsgElement.className = "storage-table-error"; errorMsgElement.textContent = WebInspector.UIString("An error occurred trying to\nread the ā%sā table.", this.tableName); this.element.appendChild(errorMsgElement); }, + _refreshButtonClicked: function(event) + { + this.update(); + } } WebInspector.DatabaseTableView.prototype.__proto__ = WebInspector.View.prototype; diff --git a/WebCore/inspector/front-end/DatabasesPanel.js b/WebCore/inspector/front-end/DatabasesPanel.js index df5bbb3..4644b3b 100644 --- a/WebCore/inspector/front-end/DatabasesPanel.js +++ b/WebCore/inspector/front-end/DatabasesPanel.js @@ -46,9 +46,24 @@ WebInspector.DatabasesPanel = function(database) this.sidebarTree = new TreeOutline(this.sidebarTreeElement); - this.databaseViews = document.createElement("div"); - this.databaseViews.id = "database-views"; - this.element.appendChild(this.databaseViews); + this.databasesListTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("DATABASES"), {}, true); + this.sidebarTree.appendChild(this.databasesListTreeElement); + this.databasesListTreeElement.expand(); + + this.localStorageListTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("LOCAL STORAGE"), {}, true); + this.sidebarTree.appendChild(this.localStorageListTreeElement); + this.localStorageListTreeElement.expand(); + + this.sessionStorageListTreeElement = new WebInspector.SidebarSectionTreeElement(WebInspector.UIString("SESSION STORAGE"), {}, true); + this.sidebarTree.appendChild(this.sessionStorageListTreeElement); + this.sessionStorageListTreeElement.expand(); + + this.storageViews = document.createElement("div"); + this.storageViews.id = "storage-views"; + this.element.appendChild(this.storageViews); + + this.storageViewStatusBarItemsContainer = document.createElement("div"); + this.storageViewStatusBarItemsContainer.id = "storage-view-status-bar-items"; this.reset(); } @@ -61,6 +76,11 @@ WebInspector.DatabasesPanel.prototype = { return WebInspector.UIString("Databases"); }, + get statusBarItems() + { + return [this.storageViewStatusBarItemsContainer]; + }, + show: function() { WebInspector.Panel.prototype.show.call(this); @@ -81,8 +101,23 @@ WebInspector.DatabasesPanel.prototype = { this._databases = []; - this.sidebarTree.removeChildren(); - this.databaseViews.removeChildren(); + if (this._domStorage) { + var domStorageLength = this._domStorage.length; + for (var i = 0; i < domStorageLength; ++i) { + var domStorage = this._domStorage[i]; + + delete domStorage._domStorageView; + } + } + + this._domStorage = []; + + this.databasesListTreeElement.removeChildren(); + this.localStorageListTreeElement.removeChildren(); + this.sessionStorageListTreeElement.removeChildren(); + this.storageViews.removeChildren(); + + this.storageViewStatusBarItemsContainer.removeChildren(); }, handleKeyEvent: function(event) @@ -96,8 +131,18 @@ WebInspector.DatabasesPanel.prototype = { var databaseTreeElement = new WebInspector.DatabaseSidebarTreeElement(database); database._databasesTreeElement = databaseTreeElement; + this.databasesListTreeElement.appendChild(databaseTreeElement); + }, - this.sidebarTree.appendChild(databaseTreeElement); + addDOMStorage: function(domStorage) + { + this._domStorage.push(domStorage); + var domStorageTreeElement = new WebInspector.DOMStorageSidebarTreeElement(domStorage); + domStorage._domStorageTreeElement = domStorageTreeElement; + if (domStorage.isLocalStorage) + this.localStorageListTreeElement.appendChild(domStorageTreeElement); + else + this.sessionStorageListTreeElement.appendChild(domStorageTreeElement); }, showDatabase: function(database, tableName) @@ -105,8 +150,8 @@ WebInspector.DatabasesPanel.prototype = { if (!database) return; - if (this.visibleDatabaseView) - this.visibleDatabaseView.hide(); + if (this.visibleView) + this.visibleView.hide(); var view; if (tableName) { @@ -125,16 +170,46 @@ WebInspector.DatabasesPanel.prototype = { } } - view.show(this.databaseViews); + view.show(this.storageViews); + + this.visibleView = view; - this.visibleDatabaseView = view; + this.storageViewStatusBarItemsContainer.removeChildren(); + var statusBarItems = view.statusBarItems; + for (var i = 0; i < statusBarItems.length; ++i) + this.storageViewStatusBarItemsContainer.appendChild(statusBarItems[i]); + }, + + showDOMStorage: function(domStorage) + { + if (!domStorage) + return; + + if (this.visibleView) + this.visibleView.hide(); + + var view; + view = domStorage._domStorageView; + if (!view) { + view = new WebInspector.DOMStorageItemsView(domStorage); + domStorage._domStorageView = view; + } + + view.show(this.storageViews); + + this.visibleView = view; + + this.storageViewStatusBarItemsContainer.removeChildren(); + var statusBarItems = view.statusBarItems; + for (var i = 0; i < statusBarItems.length; ++i) + this.storageViewStatusBarItemsContainer.appendChild(statusBarItems[i]); }, closeVisibleView: function() { - if (this.visibleDatabaseView) - this.visibleDatabaseView.hide(); - delete this.visibleDatabaseView; + if (this.visibleView) + this.visibleView.hide(); + delete this.visibleView; }, updateDatabaseTables: function(database) @@ -155,7 +230,7 @@ WebInspector.DatabasesPanel.prototype = { for (var tableName in database._tableViews) { if (!(tableName in tableNamesHash)) { - if (this.visibleDatabaseView === database._tableViews[tableName]) + if (this.visibleView === database._tableViews[tableName]) this.closeVisibleView(); delete database._tableViews[tableName]; } @@ -241,6 +316,60 @@ WebInspector.DatabasesPanel.prototype = { return dataGrid; }, + dataGridForDOMStorage: function(domStorage) + { + if (!domStorage.length) + return null; + + var columns = {}; + columns[0] = {}; + columns[1] = {}; + columns[0].title = WebInspector.UIString("Key"); + columns[0].width = columns[0].title.length; + columns[1].title = WebInspector.UIString("Value"); + columns[1].width = columns[0].title.length; + + var nodes = []; + + var length = domStorage.length; + for (index = 0; index < domStorage.length; index++) { + var data = {}; + + var key = String(domStorage.key(index)); + data[0] = key; + if (key.length > columns[0].width) + columns[0].width = key.length; + + var value = String(domStorage.getItem(key)); + data[1] = value; + if (value.length > columns[1].width) + columns[1].width = value.length; + var node = new WebInspector.DataGridNode(data, false); + node.selectable = true; + nodes.push(node); + } + + var totalColumnWidths = columns[0].width + columns[1].width; + width = Math.round((columns[0].width * 100) / totalColumnWidths); + const minimumPrecent = 10; + if (width < minimumPrecent) + width = minimumPrecent; + if (width > 100 - minimumPrecent) + width = 100 - minimumPrecent; + columns[0].width = width; + columns[1].width = 100 - width; + columns[0].width += "%"; + columns[1].width += "%"; + + var dataGrid = new WebInspector.DOMStorageDataGrid(columns); + var length = nodes.length; + for (var i = 0; i < length; ++i) + dataGrid.appendChild(nodes[i]); + if (length > 0) + nodes[0].selected = true; + return dataGrid; + }, + _startSidebarDragging: function(event) { WebInspector.elementDragStart(this.sidebarResizeElement, this._sidebarDragging.bind(this), this._endSidebarDragging.bind(this), event, "col-resize"); @@ -277,7 +406,8 @@ WebInspector.DatabasesPanel.prototype = { this._currentSidebarWidth = width; this.sidebarElement.style.width = width + "px"; - this.databaseViews.style.left = width + "px"; + this.storageViews.style.left = width + "px"; + this.storageViewStatusBarItemsContainer.style.left = width + "px"; this.sidebarResizeElement.style.left = (width - 3) + "px"; } } @@ -355,3 +485,42 @@ WebInspector.SidebarDatabaseTableTreeElement.prototype = { } WebInspector.SidebarDatabaseTableTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype; + +WebInspector.DOMStorageSidebarTreeElement = function(domStorage) +{ + + this.domStorage = domStorage; + + WebInspector.SidebarTreeElement.call(this, "domstorage-sidebar-tree-item", domStorage, "", null, false); + + this.refreshTitles(); +} + +WebInspector.DOMStorageSidebarTreeElement.prototype = { + onselect: function() + { + WebInspector.panels.databases.showDOMStorage(this.domStorage); + }, + + get mainTitle() + { + return this.domStorage.domain; + }, + + set mainTitle(x) + { + // Do nothing. + }, + + get subtitle() + { + return ""; //this.database.displayDomain; + }, + + set subtitle(x) + { + // Do nothing. + } +} + +WebInspector.DOMStorageSidebarTreeElement.prototype.__proto__ = WebInspector.SidebarTreeElement.prototype; diff --git a/WebCore/inspector/front-end/Images/domStorage.png b/WebCore/inspector/front-end/Images/domStorage.png Binary files differnew file mode 100644 index 0000000..028550c --- /dev/null +++ b/WebCore/inspector/front-end/Images/domStorage.png diff --git a/WebCore/inspector/front-end/Images/userInputResultIcon.png b/WebCore/inspector/front-end/Images/userInputResultIcon.png Binary files differnew file mode 100644 index 0000000..794a5ca --- /dev/null +++ b/WebCore/inspector/front-end/Images/userInputResultIcon.png diff --git a/WebCore/inspector/front-end/ScriptsPanel.js b/WebCore/inspector/front-end/ScriptsPanel.js index 38a6a96..2792834 100644 --- a/WebCore/inspector/front-end/ScriptsPanel.js +++ b/WebCore/inspector/front-end/ScriptsPanel.js @@ -569,11 +569,29 @@ WebInspector.ScriptsPanel.prototype = { var select = this.filesSelectElement; - // FIXME: Append in some meaningful order. var option = document.createElement("option"); option.representedObject = (script.resource || script); option.text = (script.sourceURL ? WebInspector.displayNameForURL(script.sourceURL) : WebInspector.UIString("(program)")); - select.appendChild(option); + + var insertionIndex = -1; + if (select.childNodes) { + insertionIndex = insertionIndexForObjectInListSortedByFunction(option, select.childNodes, function(a, b) { + a = a.text.toLowerCase(); + b = b.text.toLowerCase(); + + if (a < b) + return -1; + else if (a > b) + return 1; + + return 0; + }); + } + + if (insertionIndex < 0) + select.appendChild(option); + else + select.insertBefore(option, select.childNodes.item(insertionIndex)); script.filesSelectOption = option; diff --git a/WebCore/inspector/front-end/SourceFrame.js b/WebCore/inspector/front-end/SourceFrame.js index 8d6d6d3..26c0626 100644 --- a/WebCore/inspector/front-end/SourceFrame.js +++ b/WebCore/inspector/front-end/SourceFrame.js @@ -225,8 +225,10 @@ WebInspector.SourceFrame.prototype = { this.element.contentWindow.Element.prototype.addStyleClass = Element.prototype.addStyleClass; this.element.contentWindow.Element.prototype.removeStyleClass = Element.prototype.removeStyleClass; + this.element.contentWindow.Element.prototype.removeMatchingStyleClasses = Element.prototype.removeMatchingStyleClasses; this.element.contentWindow.Element.prototype.hasStyleClass = Element.prototype.hasStyleClass; this.element.contentWindow.Node.prototype.enclosingNodeOrSelfWithNodeName = Node.prototype.enclosingNodeOrSelfWithNodeName; + this.element.contentWindow.Node.prototype.enclosingNodeOrSelfWithNodeNameInArray = Node.prototype.enclosingNodeOrSelfWithNodeNameInArray; this._addExistingMessagesToSource(); this._addExistingBreakpointsToSource(); diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc index 52a8578..997d4a7 100644 --- a/WebCore/inspector/front-end/WebKit.qrc +++ b/WebCore/inspector/front-end/WebKit.qrc @@ -10,6 +10,9 @@ <file>DatabasesPanel.js</file> <file>DatabaseTableView.js</file> <file>DataGrid.js</file> + <file>DOMStorage.js</file> + <file>DOMStorageDataGrid.js</file> + <file>DOMStorageItemsView.js</file> <file>ElementsPanel.js</file> <file>ElementsTreeOutline.js</file> <file>FontView.js</file> @@ -66,6 +69,7 @@ <file>Images/disclosureTriangleSmallRightDownWhite.png</file> <file>Images/disclosureTriangleSmallRightWhite.png</file> <file>Images/dockButtons.png</file> + <file>Images/domStorage.png</file> <file>Images/elementsIcon.png</file> <file>Images/enableButtons.png</file> <file>Images/errorIcon.png</file> diff --git a/WebCore/inspector/front-end/inspector.css b/WebCore/inspector/front-end/inspector.css index 7e3c224..082955e 100644 --- a/WebCore/inspector/front-end/inspector.css +++ b/WebCore/inspector/front-end/inspector.css @@ -439,6 +439,7 @@ body.console-visible #console { #console-messages { position: absolute; + z-index: 0; top: 0; left: 0; right: 0; @@ -463,6 +464,10 @@ body.console-visible #console { background-image: url(Images/userInputIcon.png); } +.console-user-command-result.console-log-level::before { + background-image: url(Images/userInputResultIcon.png); +} + .console-message, .console-user-command { position: relative; border-bottom: 1px solid rgb(240, 240, 240); @@ -470,6 +475,14 @@ body.console-visible #console { min-height: 16px; } +.console-adjacent-user-command-result { + border-bottom: none; +} + +.console-adjacent-user-command-result + .console-user-command-result.console-log-level::before { + background-image: none; +} + .console-message::before, .console-user-command::before, #console-prompt::before, .console-group-title-level::before { position: absolute; display: block; @@ -561,35 +574,34 @@ body.console-visible #console { color: rgb(0, 128, 255); } -.console-message-url { - color: rgb(33%, 33%, 33%) !important; +#console-messages a { + color: rgb(33%, 33%, 33%); cursor: pointer; - float: right; } -.console-message-url:hover { +#console-messages a:hover { color: rgb(15%, 15%, 15%); } -.console-message-url:hover::after { - opacity: 1; +.console-message-url { + float: right; } .console-group-messages .section { - margin: 0; + margin: 0 0 0 12px !important; } .console-group-messages .section .header { padding: 0 8px 0 0; background-image: none; border: none; - min-height: 16px; + min-height: 0; } .console-group-messages .section .header::before { position: absolute; top: 1px; - left: 12px; + left: 1px; width: 8px; height: 8px; content: url(Images/treeRightTriangleBlack.png); @@ -601,6 +613,21 @@ body.console-visible #console { .console-group-messages .section .header .title { color: black; + font-weight: normal; +} + +.console-group-messages .section .properties li .info { + padding-top: 0; + padding-bottom: 0; + color: rgb(60%, 60%, 60%); +} + +.console-group-messages .outline-disclosure { + padding-left: 0; +} + +.console-group-messages .outline-disclosure > ol { + padding: 0 0 0 12px !important; } .console-group-messages .outline-disclosure, .console-group-messages .outline-disclosure ol { @@ -608,33 +635,39 @@ body.console-visible #console { line-height: 1em; } -.console-group-messages .outline-disclosure li { - padding-top: 2px; - padding-bottom: 2px; +.console-group-messages .outline-disclosure.single-node li { + padding-left: 2px; } .console-group-messages .outline-disclosure li .selection { - z-index: 0; - margin-top: -1px; + margin-left: -6px; + margin-right: -6px; +} + +.console-formatted-object, .console-formatted-node { + position: relative; + display: inline-block; + vertical-align: top; } .console-formatted-object .section, .console-formatted-node .section { position: static; } +.console-formatted-object .properties, .console-formatted-node .properties { + padding-left: 0 !important; +} + +.error-message { + color: red; +} + .auto-complete-text { color: rgb(128, 128, 128); -webkit-user-select: none; -webkit-user-modify: read-only; } -.inspectible-node:hover { - background-color: rgba(56, 121, 217, 0.1); - -webkit-border-radius: 5px; - padding: 0 5px 1px; - margin: 0 -5px -1px; -} - .panel { display: none; overflow: hidden; @@ -1532,7 +1565,11 @@ body.inactive .sidebar { content: url(Images/databaseTable.png); } -#database-views { +.domstorage-sidebar-tree-item .icon { + content: url(Images/domStorage.png); +} + +#storage-views { position: absolute; top: 0; right: 0; @@ -1540,7 +1577,7 @@ body.inactive .sidebar { bottom: 0; } -.database-view { +.storage-view { display: none; overflow: hidden; position: absolute; @@ -1550,20 +1587,20 @@ body.inactive .sidebar { bottom: 0; } -.database-view.visible { +.storage-view.visible { display: block; } -.database-view.table { +.storage-view.table { overflow: hidden; } -.database-view.table .data-grid { +.storage-view.table .data-grid { border: none; height: 100%; } -.database-view.table .database-table-empty, .database-view.table .database-table-error { +.storage-view.table .storage-table-empty, .storage-view.table .storage-table-error { position: absolute; top: 0; bottom: 25%; @@ -1581,7 +1618,7 @@ body.inactive .sidebar { white-space: pre-wrap; } -.database-view.table .database-table-error { +.storage-view.table .storage-table-error { color: rgb(66%, 33%, 33%); } @@ -1773,7 +1810,7 @@ body.inactive .data-grid th.sort-ascending, body.inactive .data-grid th.sort-des text-indent: 10px; } -.database-view.query { +.storage-view.query { font-size: 10px; font-family: Monaco, Lucida Console, monospace; padding: 2px 0; @@ -2498,6 +2535,10 @@ button.enable-toggle-status-bar-item.toggled-on:active { padding-left: 37px; } +.sidebar-tree > .children > .children > .sidebar-tree-item { + padding-left: 37px; +} + .sidebar-tree.hide-disclosure-buttons > .children { display: none; } @@ -2994,3 +3035,39 @@ body.inactive .sidebar-tree-item.selected .bubble.search-matches { .reset-profile-status-bar-item:active { background-position: 32px 0; } + +.delete-storage-status-bar-item { + background-image: url(Images/excludeButtons.png) !important; +} + +.delete-storage-status-bar-item:active { + background-position: 32px 0; +} + +#storage-view-status-bar-items { + position: absolute; + top: 0; + bottom: 0; + left: 200px; + overflow: hidden; + border-left: 1px solid rgb(184, 184, 184); + margin-left: -1px; +} + +.refresh-storage-status-bar-item { + background-image: url(Images/reloadButtons.png) !important; +} + +.refresh-storage-status-bar-item:active { + background-position: 32px 0; +} + +#storage-view-status-bar-items { + position: absolute; + top: 0; + bottom: 0; + left: 200px; + overflow: hidden; + border-left: 1px solid rgb(184, 184, 184); + margin-left: -1px; +} diff --git a/WebCore/inspector/front-end/inspector.html b/WebCore/inspector/front-end/inspector.html index cb38886..77d720b 100644 --- a/WebCore/inspector/front-end/inspector.html +++ b/WebCore/inspector/front-end/inspector.html @@ -41,7 +41,10 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="Resource.js"></script> <script type="text/javascript" src="ResourceCategory.js"></script> <script type="text/javascript" src="Database.js"></script> + <script type="text/javascript" src="DOMStorage.js"></script> + <script type="text/javascript" src="DOMStorageItemsView.js"></script> <script type="text/javascript" src="DataGrid.js"></script> + <script type="text/javascript" src="DOMStorageDataGrid.js"></script> <script type="text/javascript" src="Script.js"></script> <script type="text/javascript" src="Breakpoint.js"></script> <script type="text/javascript" src="SidebarPane.js"></script> diff --git a/WebCore/inspector/front-end/inspector.js b/WebCore/inspector/front-end/inspector.js index 07ae7db..90ffa2b 100644 --- a/WebCore/inspector/front-end/inspector.js +++ b/WebCore/inspector/front-end/inspector.js @@ -287,10 +287,14 @@ WebInspector.loaded = function() databases: new WebInspector.DatabasesPanel() }; + var hiddenPanels = (InspectorController.hiddenPanels() || "").split(','); + var toolbarElement = document.getElementById("toolbar"); var previousToolbarItem = toolbarElement.children[0]; for (var panelName in this.panels) { + if (hiddenPanels.indexOf(panelName) !== -1) + continue; var panel = this.panels[panelName]; var panelToolbarItem = panel.toolbarItem; panelToolbarItem.addEventListener("click", this._toolbarItemClicked.bind(this)); @@ -795,6 +799,11 @@ WebInspector.addDatabase = function(database) this.panels.databases.addDatabase(database); } +WebInspector.addDOMStorage = function(domStorage) +{ + this.panels.databases.addDOMStorage(domStorage); +} + WebInspector.debuggerWasEnabled = function() { this.panels.scripts.debuggerWasEnabled(); diff --git a/WebCore/inspector/front-end/utilities.js b/WebCore/inspector/front-end/utilities.js index 8f86504..7b0a20b 100644 --- a/WebCore/inspector/front-end/utilities.js +++ b/WebCore/inspector/front-end/utilities.js @@ -37,6 +37,8 @@ Object.type = function(obj, win) win = win || window; + if (obj instanceof win.Node) + return "node"; if (obj instanceof win.String) return "string"; if (obj instanceof win.Array) @@ -70,6 +72,7 @@ Object.describe = function(obj, abbreviated) switch (type1) { case "object": + case "node": return type2; case "array": return "[" + obj.toString() + "]"; @@ -937,6 +940,40 @@ Array.prototype.remove = function(value, onlyFirst) } } +function insertionIndexForObjectInListSortedByFunction(anObject, aList, aFunction) +{ + // indexOf returns (-lowerBound - 1). Taking (-result - 1) works out to lowerBound. + return (-indexOfObjectInListSortedByFunction(anObject, aList, aFunction) - 1); +} + +function indexOfObjectInListSortedByFunction(anObject, aList, aFunction) +{ + var first = 0; + var last = aList.length - 1; + var floor = Math.floor; + var mid, c; + + while (first <= last) { + mid = floor((first + last) / 2); + c = aFunction(anObject, aList[mid]); + + if (c > 0) + first = mid + 1; + else if (c < 0) + last = mid - 1; + else { + //we return the first occurance of an item in the list. + while (mid > 0 && aFunction(anObject, aList[mid - 1]) === 0) + mid--; + return mid; + } + } + + // By returning 1 less than the negative lower search bound, we can reuse this function + // for both indexOf and insertionIndexFor, with some simple arithmetic. + return (-first - 1); +} + String.sprintf = function(format) { return String.vsprintf(format, Array.prototype.slice.call(arguments, 1)); |