diff options
Diffstat (limited to 'Source/WebCore/inspector')
74 files changed, 5246 insertions, 1235 deletions
diff --git a/Source/WebCore/inspector/CodeGeneratorInspector.pm b/Source/WebCore/inspector/CodeGeneratorInspector.pm index b7be15e..e215a91 100644 --- a/Source/WebCore/inspector/CodeGeneratorInspector.pm +++ b/Source/WebCore/inspector/CodeGeneratorInspector.pm @@ -13,61 +13,70 @@ my %typeTransform; $typeTransform{"ApplicationCache"} = { "forward" => "InspectorApplicationCacheAgent", "header" => "InspectorApplicationCacheAgent.h", - "domainAccessor" => "m_inspectorController->m_applicationCacheAgent", + "domainAccessor" => "m_inspectorAgent->applicationCacheAgent()", }; $typeTransform{"CSS"} = { "forward" => "InspectorCSSAgent", "header" => "InspectorCSSAgent.h", - "domainAccessor" => "m_inspectorController->m_cssAgent", + "domainAccessor" => "m_inspectorAgent->cssAgent()", }; $typeTransform{"Console"} = { "forward" => "InspectorConsoleAgent", "header" => "InspectorConsoleAgent.h", - "domainAccessor" => "m_inspectorController->m_consoleAgent", + "domainAccessor" => "m_inspectorAgent->consoleAgent()", }; $typeTransform{"Debugger"} = { "forward" => "InspectorDebuggerAgent", "header" => "InspectorDebuggerAgent.h", - "domainAccessor" => "m_inspectorController->m_debuggerAgent", + "domainAccessor" => "m_inspectorAgent->debuggerAgent()", }; $typeTransform{"BrowserDebugger"} = { "forward" => "InspectorBrowserDebuggerAgent", "header" => "InspectorBrowserDebuggerAgent.h", - "domainAccessor" => "m_inspectorController->m_browserDebuggerAgent", + "domainAccessor" => "m_inspectorAgent->browserDebuggerAgent()", }; $typeTransform{"Database"} = { "forward" => "InspectorDatabaseAgent", "header" => "InspectorDatabaseAgent.h", - "domainAccessor" => "m_inspectorController->m_databaseAgent", + "domainAccessor" => "m_inspectorAgent->databaseAgent()", }; $typeTransform{"DOM"} = { "forward" => "InspectorDOMAgent", "header" => "InspectorDOMAgent.h", - "domainAccessor" => "m_inspectorController->m_domAgent", + "domainAccessor" => "m_inspectorAgent->domAgent()", }; $typeTransform{"DOMStorage"} = { "forward" => "InspectorDOMStorageAgent", "header" => "InspectorDOMStorageAgent.h", - "domainAccessor" => "m_inspectorController->m_domStorageAgent", + "domainAccessor" => "m_inspectorAgent->domStorageAgent()", }; $typeTransform{"FileSystem"} = { "forward" => "InspectorFileSystemAgent", "header" => "InspectorFileSystemAgent.h", - "domainAccessor" => "m_inspectorController->m_fileSystemAgent", + "domainAccessor" => "m_inspectorAgent->fileSystemAgent()", +}; +$typeTransform{"InjectedScript"} = { + "forwardHeader" => "InjectedScriptHost.h", + "domainAccessor" => "m_inspectorAgent->injectedScriptAgent()", }; $typeTransform{"Inspector"} = { - "forwardHeader" => "InspectorController.h", - "domainAccessor" => "m_inspectorController", + "forwardHeader" => "InspectorController.h", # FIXME: Temporary solution until extracting the real InspectorAgent from InspectorController. + "domainAccessor" => "m_inspectorAgent", }; $typeTransform{"Network"} = { "forward" => "InspectorResourceAgent", "header" => "InspectorResourceAgent.h", - "domainAccessor" => "m_inspectorController->m_resourceAgent", + "domainAccessor" => "m_inspectorAgent->resourceAgent()", }; $typeTransform{"Profiler"} = { "forward" => "InspectorProfilerAgent", "header" => "InspectorProfilerAgent.h", - "domainAccessor" => "m_inspectorController->m_profilerAgent", + "domainAccessor" => "m_inspectorAgent->profilerAgent()", +}; +$typeTransform{"Runtime"} = { + "forward" => "InspectorRuntimeAgent", + "header" => "InspectorRuntimeAgent.h", + "domainAccessor" => "m_inspectorAgent->runtimeAgent()", }; $typeTransform{"Frontend"} = { @@ -87,7 +96,8 @@ $typeTransform{"Object"} = { "defaultValue" => "InspectorObject::create()", "forward" => "InspectorObject", "header" => "InspectorValues.h", - "JSONType" => "Object" + "JSONType" => "Object", + "JSType" => "object" }; $typeTransform{"Array"} = { "param" => "PassRefPtr<InspectorArray>", @@ -95,7 +105,8 @@ $typeTransform{"Array"} = { "defaultValue" => "InspectorArray::create()", "forward" => "InspectorArray", "header" => "InspectorValues.h", - "JSONType" => "Array" + "JSONType" => "Array", + "JSType" => "object" }; $typeTransform{"Value"} = { "param" => "PassRefPtr<InspectorValue>", @@ -103,16 +114,18 @@ $typeTransform{"Value"} = { "defaultValue" => "InspectorValue::null()", "forward" => "InspectorValue", "header" => "InspectorValues.h", - "JSONType" => "Value" + "JSONType" => "Value", + "JSType" => "" }; $typeTransform{"String"} = { "param" => "const String&", "variable" => "String", "return" => "String", "defaultValue" => "\"\"", - "forwardHeader" => "wtf/Forward.h", + "forwardHeader" => "PlatformString.h", "header" => "PlatformString.h", - "JSONType" => "String" + "JSONType" => "String", + "JSType" => "string" }; $typeTransform{"long"} = { "param" => "long", @@ -120,7 +133,8 @@ $typeTransform{"long"} = { "defaultValue" => "0", "forward" => "", "header" => "", - "JSONType" => "Number" + "JSONType" => "Number", + "JSType" => "number" }; $typeTransform{"int"} = { "param" => "int", @@ -129,6 +143,7 @@ $typeTransform{"int"} = { "forward" => "", "header" => "", "JSONType" => "Number", + "JSType" => "number" }; $typeTransform{"unsigned long"} = { "param" => "unsigned long", @@ -136,7 +151,8 @@ $typeTransform{"unsigned long"} = { "defaultValue" => "0u", "forward" => "", "header" => "", - "JSONType" => "Number" + "JSONType" => "Number", + "JSType" => "number" }; $typeTransform{"unsigned int"} = { "param" => "unsigned int", @@ -144,7 +160,8 @@ $typeTransform{"unsigned int"} = { "defaultValue" => "0u", "forward" => "", "header" => "", - "JSONType" => "Number" + "JSONType" => "Number", + "JSType" => "number" }; $typeTransform{"double"} = { "param" => "double", @@ -152,7 +169,8 @@ $typeTransform{"double"} = { "defaultValue" => "0.0", "forward" => "", "header" => "", - "JSONType" => "Number" + "JSONType" => "Number", + "JSType" => "number" }; $typeTransform{"boolean"} = { "param" => "bool", @@ -160,7 +178,8 @@ $typeTransform{"boolean"} = { "defaultValue" => "false", "forward" => "", "header" => "", - "JSONType" => "Boolean" + "JSONType" => "Boolean", + "JSType" => "boolean" }; $typeTransform{"void"} = { "forward" => "", @@ -250,12 +269,13 @@ sub GenerateInterface $backendClassName = $className . "BackendDispatcher"; $backendJSStubName = $className . "BackendStub"; my @backendHead; - push(@backendHead, " ${backendClassName}(InspectorController* inspectorController) : m_inspectorController(inspectorController) { }"); + push(@backendHead, " typedef InspectorController InspectorAgent;"); # FIXME: Temporary substitution until extracting InspectorAgent from InspectorController. + push(@backendHead, " ${backendClassName}(InspectorAgent* inspectorAgent) : m_inspectorAgent(inspectorAgent) { }"); push(@backendHead, " void reportProtocolError(const long callId, const String& errorText) const;"); push(@backendHead, " void dispatch(const String& message);"); push(@backendHead, " static bool getCommandName(const String& message, String* result);"); $backendConstructor = join("\n", @backendHead); - $backendFooter = " InspectorController* m_inspectorController;"; + $backendFooter = " InspectorAgent* m_inspectorAgent;"; $backendTypes{"Inspector"} = 1; $backendTypes{"InspectorClient"} = 1; $backendTypes{"PassRefPtr"} = 1; @@ -392,7 +412,7 @@ sub generateBackendFunction } push(@function, " // use InspectorFrontend as a marker of WebInspector availability"); - push(@function, " if ((callId || protocolErrors->length()) && m_inspectorController->hasFrontend()) {"); + push(@function, " if ((callId || protocolErrors->length()) && m_inspectorAgent->hasFrontend()) {"); push(@function, " RefPtr<InspectorObject> responseMessage = InspectorObject::create();"); push(@function, " responseMessage->setNumber(\"seq\", callId);"); push(@function, " responseMessage->setString(\"domain\", \"$domain\");"); @@ -407,7 +427,7 @@ sub generateBackendFunction push(@function, " responseMessage->setObject(\"data\", responseData);"); push(@function, " }"); } - push(@function, " m_inspectorController->inspectorClient()->sendMessageToFrontend(responseMessage->toJSONString());"); + push(@function, " m_inspectorAgent->inspectorClient()->sendMessageToFrontend(responseMessage->toJSONString());"); push(@function, " }"); @@ -428,7 +448,7 @@ void ${backendClassName}::reportProtocolError(const long callId, const String& e RefPtr<InspectorArray> errors = InspectorArray::create(); errors->pushString(errorText); message->setArray("errors", errors); - m_inspectorController->inspectorClient()->sendMessageToFrontend(message->toJSONString()); + m_inspectorAgent->inspectorClient()->sendMessageToFrontend(message->toJSONString()); } EOF return split("\n", $reportProtocolError); @@ -567,7 +587,7 @@ sub generateBackendStubJS foreach my $function (@backendFunctions) { my $name = $function->signature->name; my $domain = $function->signature->extendedAttributes->{"domain"}; - my $argumentNames = join(",", map("\"" . $_->name . "\": \"" . lc($typeTransform{$_->type}->{"JSONType"}) . "\"", grep($_->direction eq "in", @{$function->parameters}))); + my $argumentNames = join(",", map("\"" . $_->name . "\": \"" . $typeTransform{$_->type}->{"JSType"} . "\"", grep($_->direction eq "in", @{$function->parameters}))); push(@JSStubs, " this._registerDelegate('{" . "\"seq\": 0, " . "\"domain\": \"$domain\", " . @@ -625,7 +645,7 @@ InspectorBackendStub.prototype = { return; } var value = args.shift(); - if (typeof value !== request.arguments[key]) { + if (request.arguments[key] && typeof value !== request.arguments[key]) { console.error("Protocol Error: Invalid type of argument '%s' for 'InspectorBackend.%s' call. It should be '%s' but it is '%s'.", key, request.command, request.arguments[key], typeof value); return; } diff --git a/Source/WebCore/inspector/ConsoleMessage.h b/Source/WebCore/inspector/ConsoleMessage.h index 310aa8e..7c3348b 100644 --- a/Source/WebCore/inspector/ConsoleMessage.h +++ b/Source/WebCore/inspector/ConsoleMessage.h @@ -46,7 +46,8 @@ class ScriptCallFrame; class ScriptCallStack; class ScriptValue; -class ConsoleMessage : public Noncopyable { +class ConsoleMessage { + WTF_MAKE_NONCOPYABLE(ConsoleMessage); WTF_MAKE_FAST_ALLOCATED; public: ConsoleMessage(MessageSource, MessageType, MessageLevel, const String& m, unsigned li, const String& u); ConsoleMessage(MessageSource, MessageType, MessageLevel, const String& m, PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>); diff --git a/Source/WebCore/inspector/InjectedScript.cpp b/Source/WebCore/inspector/InjectedScript.cpp index 3f4d819..1969f34 100644 --- a/Source/WebCore/inspector/InjectedScript.cpp +++ b/Source/WebCore/inspector/InjectedScript.cpp @@ -44,21 +44,94 @@ InjectedScript::InjectedScript(ScriptObject injectedScriptObject) { } -void InjectedScript::dispatch(const String& methodName, const String& arguments, RefPtr<InspectorValue>* result, bool* hadException) +void InjectedScript::evaluate(const String& expression, const String& objectGroup, RefPtr<InspectorValue>* result) { - ASSERT(!hasNoValue()); - if (!canAccessInspectedWindow()) { - *hadException = true; - return; - } + ScriptFunctionCall function(m_injectedScriptObject, "evaluate"); + function.appendArgument(expression); + function.appendArgument(objectGroup); + makeCall(function, result); +} - ScriptFunctionCall function(m_injectedScriptObject, "dispatch"); - function.appendArgument(methodName); - function.appendArgument(arguments); - *hadException = false; - ScriptValue resultValue = function.call(*hadException); - if (!*hadException) - *result = resultValue.toInspectorValue(m_injectedScriptObject.scriptState()); +void InjectedScript::evaluateOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, const String& objectGroup, RefPtr<InspectorValue>* result) +{ + ScriptFunctionCall function(m_injectedScriptObject, "evaluateOnCallFrame"); + function.appendArgument(callFrameId->toJSONString()); + function.appendArgument(expression); + function.appendArgument(objectGroup); + makeCall(function, result); +} + +void InjectedScript::evaluateOnSelf(const String& functionBody, PassRefPtr<InspectorArray> argumentsArray, RefPtr<InspectorValue>* result) +{ + ScriptFunctionCall function(m_injectedScriptObject, "evaluateOnSelf"); + function.appendArgument(functionBody); + function.appendArgument(argumentsArray->toJSONString()); + makeCall(function, result); +} + +void InjectedScript::getCompletions(const String& expression, bool includeInspectorCommandLineAPI, RefPtr<InspectorValue>* result) +{ + ScriptFunctionCall function(m_injectedScriptObject, "getCompletions"); + function.appendArgument(expression); + function.appendArgument(includeInspectorCommandLineAPI); + makeCall(function, result); +} + +void InjectedScript::getCompletionsOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, bool includeInspectorCommandLineAPI, RefPtr<InspectorValue>* result) +{ + ScriptFunctionCall function(m_injectedScriptObject, "getCompletionsOnCallFrame"); + function.appendArgument(callFrameId->toJSONString()); + function.appendArgument(expression); + function.appendArgument(includeInspectorCommandLineAPI); + makeCall(function, result); +} + +void InjectedScript::getProperties(PassRefPtr<InspectorObject> objectId, bool ignoreHasOwnProperty, bool abbreviate, RefPtr<InspectorValue>* result) +{ + ScriptFunctionCall function(m_injectedScriptObject, "getProperties"); + String objectIdString = objectId->toJSONString(); + function.appendArgument(objectIdString); + function.appendArgument(ignoreHasOwnProperty); + function.appendArgument(abbreviate); + makeCall(function, result); +} + +void InjectedScript::pushNodeToFrontend(PassRefPtr<InspectorObject> objectId, RefPtr<InspectorValue>* result) +{ + ScriptFunctionCall function(m_injectedScriptObject, "pushNodeToFrontend"); + function.appendArgument(objectId->toJSONString()); + makeCall(function, result); +} + +void InjectedScript::resolveNode(long nodeId, RefPtr<InspectorValue>* result) +{ + ScriptFunctionCall function(m_injectedScriptObject, "resolveNode"); + function.appendArgument(nodeId); + makeCall(function, result); +} + +void InjectedScript::getNodeProperties(long nodeId, PassRefPtr<InspectorArray> propertiesArray, RefPtr<InspectorValue>* result) +{ + ScriptFunctionCall function(m_injectedScriptObject, "getNodeProperties"); + function.appendArgument(nodeId); + function.appendArgument(propertiesArray->toJSONString()); + makeCall(function, result); +} + +void InjectedScript::getNodePrototypes(long nodeId, RefPtr<InspectorValue>* result) +{ + ScriptFunctionCall function(m_injectedScriptObject, "getNodePrototypes"); + function.appendArgument(nodeId); + makeCall(function, result); +} + +void InjectedScript::setPropertyValue(PassRefPtr<InspectorObject> objectId, const String& propertyName, const String& expression, RefPtr<InspectorValue>* result) +{ + ScriptFunctionCall function(m_injectedScriptObject, "getNodeProperties"); + function.appendArgument(objectId->toJSONString()); + function.appendArgument(propertyName); + function.appendArgument(expression); + makeCall(function, result); } #if ENABLE(JAVASCRIPT_DEBUGGER) @@ -91,11 +164,29 @@ void InjectedScript::releaseWrapperObjectGroup(const String& objectGroup) releaseFunction.appendArgument(objectGroup); releaseFunction.call(); } + bool InjectedScript::canAccessInspectedWindow() { return InjectedScriptHost::canAccessInspectedWindow(m_injectedScriptObject.scriptState()); } +void InjectedScript::makeCall(ScriptFunctionCall& function, RefPtr<InspectorValue>* result) +{ + if (hasNoValue() || !canAccessInspectedWindow()) { + *result = InspectorValue::null(); + return; + } + + bool hadException = false; + ScriptValue resultValue = function.call(hadException); + + ASSERT(!hadException); + if (!hadException) + *result = resultValue.toInspectorValue(m_injectedScriptObject.scriptState()); + else + *result = InspectorValue::null(); +} + } // namespace WebCore #endif // ENABLE(INSPECTOR) diff --git a/Source/WebCore/inspector/InjectedScript.h b/Source/WebCore/inspector/InjectedScript.h index f80cfb4..0a3f24b 100644 --- a/Source/WebCore/inspector/InjectedScript.h +++ b/Source/WebCore/inspector/InjectedScript.h @@ -36,10 +36,12 @@ #include <wtf/Forward.h> #include <wtf/Noncopyable.h> #include <wtf/PassRefPtr.h> +#include <wtf/RefPtr.h> namespace WebCore { class InspectorValue; +class ScriptFunctionCall; class InjectedScript { public: @@ -48,10 +50,22 @@ public: bool hasNoValue() const { return m_injectedScriptObject.hasNoValue(); } - void dispatch(const String& methodName, const String& arguments, RefPtr<InspectorValue>* result, bool* hadException); + void evaluate(const String& expression, const String& objectGroup, RefPtr<InspectorValue>* result); + void evaluateOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, const String& objectGroup, RefPtr<InspectorValue>* result); + void evaluateOnSelf(const String& functionBody, PassRefPtr<InspectorArray> argumentsArray, RefPtr<InspectorValue>* result); + void getCompletions(const String& expression, bool includeInspectorCommandLineAPI, RefPtr<InspectorValue>* result); + void getCompletionsOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, bool includeInspectorCommandLineAPI, RefPtr<InspectorValue>* result); + void getProperties(PassRefPtr<InspectorObject> objectId, bool ignoreHasOwnProperty, bool abbreviate, RefPtr<InspectorValue>* result); + void pushNodeToFrontend(PassRefPtr<InspectorObject> objectId, RefPtr<InspectorValue>* result); + void resolveNode(long nodeId, RefPtr<InspectorValue>* result); + void getNodeProperties(long nodeId, PassRefPtr<InspectorArray> propertiesArray, RefPtr<InspectorValue>* result); + void getNodePrototypes(long nodeId, RefPtr<InspectorValue>* result); + void setPropertyValue(PassRefPtr<InspectorObject> objectId, const String& propertyName, const String& expression, RefPtr<InspectorValue>* result); + #if ENABLE(JAVASCRIPT_DEBUGGER) PassRefPtr<InspectorValue> callFrames(); #endif + PassRefPtr<InspectorValue> wrapForConsole(ScriptValue); void releaseWrapperObjectGroup(const String&); ScriptState* scriptState() const { return m_injectedScriptObject.scriptState(); } @@ -60,6 +74,9 @@ private: friend InjectedScript InjectedScriptHost::injectedScriptFor(ScriptState*); explicit InjectedScript(ScriptObject); bool canAccessInspectedWindow(); + + void makeCall(ScriptFunctionCall&, RefPtr<InspectorValue>* result); + ScriptObject m_injectedScriptObject; }; diff --git a/Source/WebCore/inspector/InjectedScriptHost.cpp b/Source/WebCore/inspector/InjectedScriptHost.cpp index 3fd70e4..d67adaf 100644 --- a/Source/WebCore/inspector/InjectedScriptHost.cpp +++ b/Source/WebCore/inspector/InjectedScriptHost.cpp @@ -30,22 +30,21 @@ #include "config.h" #include "InjectedScriptHost.h" -#include "InjectedScriptSource.h" -#include "InspectorDatabaseAgent.h" -#include "InspectorDOMStorageAgent.h" #if ENABLE(INSPECTOR) - #include "Element.h" #include "Frame.h" #include "FrameLoader.h" #include "HTMLFrameOwnerElement.h" #include "InjectedScript.h" +#include "InjectedScriptSource.h" #include "InspectorClient.h" #include "InspectorConsoleAgent.h" #include "InspectorController.h" #include "InspectorDOMAgent.h" +#include "InspectorDOMStorageAgent.h" +#include "InspectorDatabaseAgent.h" #include "InspectorFrontend.h" #include "Pasteboard.h" @@ -81,6 +80,13 @@ InjectedScriptHost::~InjectedScriptHost() { } +void InjectedScriptHost::evaluateOnSelf(const String& functionBody, PassRefPtr<InspectorArray> argumentsArray, RefPtr<InspectorValue>* result) +{ + InjectedScript injectedScript = injectedScriptForMainFrame(); + if (!injectedScript.hasNoValue()) + injectedScript.evaluateOnSelf(functionBody, argumentsArray, result); +} + void InjectedScriptHost::clearConsoleMessages() { if (m_inspectorController) @@ -124,23 +130,23 @@ long InjectedScriptHost::inspectedNode(unsigned long num) #if ENABLE(DATABASE) Database* InjectedScriptHost::databaseForId(long databaseId) { - if (m_inspectorController && m_inspectorController->m_databaseAgent) - return m_inspectorController->m_databaseAgent->databaseForId(databaseId); + if (m_inspectorController && m_inspectorController->databaseAgent()) + return m_inspectorController->databaseAgent()->databaseForId(databaseId); return 0; } void InjectedScriptHost::selectDatabase(Database* database) { - if (m_inspectorController && m_inspectorController->m_databaseAgent) - m_inspectorController->m_databaseAgent->selectDatabase(database); + if (m_inspectorController && m_inspectorController->databaseAgent()) + m_inspectorController->databaseAgent()->selectDatabase(database); } #endif #if ENABLE(DOM_STORAGE) void InjectedScriptHost::selectDOMStorage(Storage* storage) { - if (m_inspectorController && m_inspectorController->m_domStorageAgent) - m_inspectorController->m_domStorageAgent->selectDOMStorage(storage); + if (m_inspectorController && m_inspectorController->domStorageAgent()) + m_inspectorController->domStorageAgent()->selectDOMStorage(storage); } #endif @@ -149,6 +155,20 @@ InjectedScript InjectedScriptHost::injectedScriptForId(long id) return m_idToInjectedScript.get(id); } +InjectedScript InjectedScriptHost::injectedScriptForObjectId(InspectorObject* objectId) +{ + long injectedScriptId = 0; + bool success = objectId->getNumber("injectedScriptId", &injectedScriptId); + if (success) + return injectedScriptForId(injectedScriptId); + return InjectedScript(); +} + +InjectedScript InjectedScriptHost::injectedScriptForMainFrame() +{ + return injectedScriptFor(mainWorldScriptState(m_inspectorController->inspectedPage()->mainFrame())); +} + void InjectedScriptHost::discardInjectedScripts() { IdToInjectedScriptMap::iterator end = m_idToInjectedScript.end(); @@ -174,14 +194,14 @@ InspectorDOMAgent* InjectedScriptHost::inspectorDOMAgent() { if (!m_inspectorController) return 0; - return m_inspectorController->m_domAgent.get(); + return m_inspectorController->domAgent(); } InspectorFrontend* InjectedScriptHost::frontend() { if (!m_inspectorController) return 0; - return m_inspectorController->m_frontend.get(); + return m_inspectorController->frontend(); } String InjectedScriptHost::injectedScriptSource() diff --git a/Source/WebCore/inspector/InjectedScriptHost.h b/Source/WebCore/inspector/InjectedScriptHost.h index e9c09aa..108f118 100644 --- a/Source/WebCore/inspector/InjectedScriptHost.h +++ b/Source/WebCore/inspector/InjectedScriptHost.h @@ -44,6 +44,7 @@ class Database; class InjectedScript; class InspectorDOMAgent; class InspectorFrontend; +class InspectorObject; class Node; class ScriptObject; class Storage; @@ -58,6 +59,9 @@ public: ~InjectedScriptHost(); + // Part of the protocol. + void evaluateOnSelf(const String& functionBody, PassRefPtr<InspectorArray> argumentsArray, RefPtr<InspectorValue>* result); + InspectorController* inspectorController() { return m_inspectorController; } void disconnectController() { m_inspectorController = 0; } @@ -84,6 +88,8 @@ public: pair<long, ScriptObject> injectScript(const String& source, ScriptState*); InjectedScript injectedScriptFor(ScriptState*); InjectedScript injectedScriptForId(long); + InjectedScript injectedScriptForObjectId(InspectorObject* objectId); + InjectedScript injectedScriptForMainFrame(); void discardInjectedScripts(); void releaseWrapperObjectGroup(long injectedScriptId, const String& objectGroup); diff --git a/Source/WebCore/inspector/InjectedScriptSource.js b/Source/WebCore/inspector/InjectedScriptSource.js index 90797fb..3aa24a6 100644 --- a/Source/WebCore/inspector/InjectedScriptSource.js +++ b/Source/WebCore/inspector/InjectedScriptSource.js @@ -60,7 +60,9 @@ InjectedScript.prototype = { this._objectGroups[objectGroupName] = group; } group.push(id); - objectId = this._serializeObjectId(id, objectGroupName); + objectId = { injectedScriptId: injectedScriptId, + id: id, + groupName: objectGroupName }; } return InjectedScript.RemoteObject.fromObject(object, objectId, abbreviate); } catch (e) { @@ -68,18 +70,9 @@ InjectedScript.prototype = { } }, - _serializeObjectId: function(id, groupName) - { - return injectedScriptId + ":" + id + ":" + groupName; - }, - _parseObjectId: function(objectId) { - var tokens = objectId.split(":"); - var parsedObjectId = {}; - parsedObjectId.id = parseInt(tokens[1]); - parsedObjectId.groupName = tokens[2]; - return parsedObjectId; + return eval("(" + objectId + ")"); }, releaseWrapperObjectGroup: function(objectGroupName) @@ -103,26 +96,11 @@ InjectedScript.prototype = { return result; }, - getPrototypes: function(nodeId) - { - this.releaseWrapperObjectGroup("prototypes"); - var node = this._nodeForId(nodeId); - if (!node) - return false; - - var result = []; - var prototype = node; - do { - result.push(this._wrapObject(prototype, "prototypes")); - prototype = prototype.__proto__; - } while (prototype) - return result; - }, - getProperties: function(objectId, ignoreHasOwnProperty, abbreviate) { var parsedObjectId = this._parseObjectId(objectId); var object = this._objectForId(parsedObjectId); + if (!this._isDefined(object)) return false; var properties = []; @@ -208,29 +186,14 @@ InjectedScript.prototype = { return Object.keys(propertyNameSet); }, - getCompletions: function(expression, includeInspectorCommandLineAPI, callFrameId) + getCompletions: function(expression, includeInspectorCommandLineAPI) { var props = {}; try { - var expressionResult; - // Evaluate on call frame if call frame id is available. - if (typeof callFrameId === "number") { - var callFrame = this._callFrameForId(callFrameId); - if (!callFrame) - return props; - if (expression) - expressionResult = this._evaluateOn(callFrame.evaluate, callFrame, expression, true); - else { - // Evaluate into properties in scope of the selected call frame. - var scopeChain = callFrame.scopeChain; - for (var i = 0; i < scopeChain.length; ++i) - this._populatePropertyNames(scopeChain[i], props); - } - } else { - if (!expression) - expression = "this"; - expressionResult = this._evaluateOn(inspectedWindow.eval, inspectedWindow, expression, false); - } + if (!expression) + expression = "this"; + var expressionResult = this._evaluateOn(inspectedWindow.eval, inspectedWindow, expression, false); + if (typeof expressionResult === "object") this._populatePropertyNames(expressionResult, props); @@ -243,6 +206,34 @@ InjectedScript.prototype = { return props; }, + getCompletionsOnCallFrame: function(callFrameId, expression, includeInspectorCommandLineAPI) + { + var props = {}; + try { + var callFrame = this._callFrameForId(callFrameId); + if (!callFrame) + return props; + + if (expression) { + var expressionResult = this._evaluateOn(callFrame.evaluate, callFrame, expression, true); + if (typeof expressionResult === "object") + this._populatePropertyNames(expressionResult, props); + } else { + // Evaluate into properties in scope of the selected call frame. + var scopeChain = callFrame.scopeChain; + for (var i = 0; i < scopeChain.length; ++i) + this._populatePropertyNames(scopeChain[i], props); + } + + if (includeInspectorCommandLineAPI) { + for (var prop in this._commandLineAPI) + props[prop] = true; + } + } catch(e) { + } + return props; + }, + evaluate: function(expression, objectGroup) { return this._evaluateAndWrap(inspectedWindow.eval, inspectedWindow, expression, objectGroup, false); @@ -300,7 +291,7 @@ InjectedScript.prototype = { return result; }, - evaluateInCallFrame: function(callFrameId, code, objectGroup) + evaluateOnCallFrame: function(callFrameId, code, objectGroup) { var callFrame = this._callFrameForId(callFrameId); if (!callFrame) @@ -308,10 +299,12 @@ InjectedScript.prototype = { return this._evaluateAndWrap(callFrame.evaluate, callFrame, code, objectGroup, true); }, - _callFrameForId: function(id) + _callFrameForId: function(callFrameId) { + var parsedCallFrameId = eval("(" + callFrameId + ")"); + var ordinal = parsedCallFrameId.ordinal; var callFrame = InjectedScriptHost.currentCallFrame(); - while (--id >= 0 && callFrame) + while (--ordinal >= 0 && callFrame) callFrame = callFrame.caller; return callFrame; }, @@ -323,9 +316,9 @@ InjectedScript.prototype = { return InjectedScriptHost.nodeForId(nodeId); }, - _objectForId: function(parsedObjectId) + _objectForId: function(objectId) { - return this._idToWrappedObject[parsedObjectId.id]; + return this._idToWrappedObject[objectId.id]; }, resolveNode: function(nodeId) @@ -342,12 +335,29 @@ InjectedScript.prototype = { var node = this._nodeForId(nodeId); if (!node) return false; + properties = eval("(" + properties + ")"); var result = {}; for (var i = 0; i < properties.length; ++i) result[properties[i]] = node[properties[i]]; return result; }, + getNodePrototypes: function(nodeId) + { + this.releaseWrapperObjectGroup("prototypes"); + var node = this._nodeForId(nodeId); + if (!node) + return false; + + var result = []; + var prototype = node; + do { + result.push(this._wrapObject(prototype, "prototypes")); + prototype = prototype.__proto__; + } while (prototype) + return result; + }, + pushNodeToFrontend: function(objectId) { var parsedObjectId = this._parseObjectId(objectId); @@ -359,8 +369,8 @@ InjectedScript.prototype = { evaluateOnSelf: function(funcBody, args) { - var func = window.eval("(" + funcBody + ")"); - return func.apply(this, args || []); + var func = eval("(" + funcBody + ")"); + return func.apply(this, eval("(" + args + ")") || []); }, _isDefined: function(object) @@ -536,15 +546,15 @@ InjectedScript.RemoteObject.fromObject = function(object, objectId, abbreviate) } } -InjectedScript.CallFrameProxy = function(id, callFrame) +InjectedScript.CallFrameProxy = function(ordinal, callFrame) { - this.id = id; + this.id = { ordinal: ordinal, injectedScriptId: injectedScriptId }; this.type = callFrame.type; this.functionName = (this.type === "function" ? callFrame.functionName : ""); this.sourceID = callFrame.sourceID; this.line = callFrame.line; + this.column = callFrame.column; this.scopeChain = this._wrapScopeChain(callFrame); - this.worldId = injectedScriptId; } InjectedScript.CallFrameProxy.prototype = { diff --git a/Source/WebCore/inspector/Inspector.idl b/Source/WebCore/inspector/Inspector.idl index 6c2cc2e..79b33f6 100644 --- a/Source/WebCore/inspector/Inspector.idl +++ b/Source/WebCore/inspector/Inspector.idl @@ -36,13 +36,8 @@ module core { // generic Inspector's methods /////////////////////////////////////////////////////////////////////// - // HUGE FIXME: we need to expose InjectedScript methods here. Or document InjectedScript capabilities. - [domain=Inspector] void dispatchOnInjectedScript(in long injectedScriptId, in String methodName, in String arguments, out Value result, out boolean isException); [domain=Inspector] void addScriptToEvaluateOnLoad(in String scriptSource); [domain=Inspector] void removeAllScriptsToEvaluateOnLoad(); - [domain=Inspector] void releaseWrapperObjectGroup(in long injectedScriptId, in String objectGroup); - [domain=Inspector] void getInspectorState(out Object state); - [domain=Inspector] void setMonitoringXHREnabled(in boolean enable, out boolean newState); [domain=Inspector] void reloadPage(); [domain=Inspector] void populateScriptObjects(); @@ -73,6 +68,22 @@ module core { [domain=Inspector] void deleteCookie(in String cookieName, in String domain); /////////////////////////////////////////////////////////////////////// + // Runtime + /////////////////////////////////////////////////////////////////////// + + [domain=Runtime] void evaluate(in String expression, in String objectGroup, out Value result); + [domain=Runtime] void getCompletions(in String expression, in boolean includeInspectorCommandLineAPI, out Value result); + [domain=Runtime] void getProperties(in Object objectId, in boolean ignoreHasOwnProperty, in boolean abbreviate, out Value result); + [domain=Runtime] void setPropertyValue(in Object objectId, in String propertyName, in String expression, out Value result); + [domain=Runtime] void releaseWrapperObjectGroup(in long injectedScriptId, in String objectGroup); + + /////////////////////////////////////////////////////////////////////// + // Injected Script + /////////////////////////////////////////////////////////////////////// + + [domain=InjectedScript] void evaluateOnSelf(in String functionBody, in Array argumentsArray, out Value result); + + /////////////////////////////////////////////////////////////////////// // Console API /////////////////////////////////////////////////////////////////////// @@ -82,6 +93,8 @@ module core { [notify, domain=Console] void updateConsoleMessageRepeatCount(out unsigned long count); [domain=Console] void clearConsoleMessages(); [notify, domain=Console] void consoleMessagesCleared(); + [domain=Console] void setMonitoringXHREnabled(in boolean enabled); + [notify, domain=Console] void monitoringXHRStateChanged(out boolean enabled); /////////////////////////////////////////////////////////////////////// // Network API @@ -89,8 +102,8 @@ module core { [domain=Network] void cachedResources(out Object resources); [domain=Network] void resourceContent(in unsigned long frameId, in String url, in boolean base64Encode, out String content); - [notify, domain=Network] void frameDetachedFromParent(out unsigned long frameId); + [notify, domain=Network] void frameDetachedFromParent(out unsigned long frameId); [notify, domain=Network] void identifierForInitialRequest(out long identifier, out String url, out Object loader, out Value callStack); [notify, domain=Network] void willSendRequest(out long identifier, out double time, out Object request, out Object redirectResponse); [notify, domain=Network] void markResourceAsCached(out long identifier); @@ -112,10 +125,11 @@ module core { // Database API /////////////////////////////////////////////////////////////////////// - [notify, domain=Database] void addDatabase(out Object database); - [notify, domain=Database] void selectDatabase(out int databaseId); [domain=Database] void getDatabaseTableNames(in long databaseId, out Array tableNames); [domain=Database] void executeSQL(in long databaseId, in String query, out boolean success, out long transactionId); + + [notify, domain=Database] void addDatabase(out Object database); + [notify, domain=Database] void selectDatabase(out int databaseId); [notify, domain=Database] void sqlTransactionSucceeded(out long transactionId, out Value columnNames, out Value values); [notify, domain=Database] void sqlTransactionFailed(out long transactionId, out Value sqlError); #endif @@ -177,6 +191,10 @@ module core { [domain=DOM] void performSearch(in String query, in boolean runSynchronously); [domain=DOM] void searchCanceled(); [domain=DOM] void pushNodeByPathToFrontend(in String path, out long nodeId); + [domain=DOM] void resolveNode(in long nodeId, out Value result); + [domain=DOM] void getNodeProperties(in long nodeId, in Array propertiesArray, out Value result); + [domain=DOM] void getNodePrototypes(in long nodeId, out Value result); + [domain=DOM] void pushNodeToFrontend(in Object objectId, out Value result); [notify, domain=DOM] void setDocument(out Value root); // FIXME: should be requested from the front-end as getDocument. [notify, domain=DOM] void attributesUpdated(out long id, out Array attributes); @@ -224,12 +242,12 @@ module core { [domain=Inspector] void enableDebugger(in boolean always); [domain=Inspector] void disableDebugger(in boolean always); - [domain=Inspector] void setStickyBreakpoints(in Object breakpoints); + [domain=Inspector] void setAllBrowserBreakpoints(in Object breakpoints); [notify, domain=Debugger] void debuggerWasEnabled(); [notify, domain=Debugger] void debuggerWasDisabled(); - [notify, domain=Debugger] void parsedScriptSource(out String sourceID, out String url, out int lineOffset, out int columnOffset, out int scriptWorldType); + [notify, domain=Debugger] void parsedScriptSource(out String sourceID, out String url, out int lineOffset, out int columnOffset, out int length, out int scriptWorldType); [notify, domain=Debugger] void failedToParseScriptSource(out String url, out String data, out int firstLine, out int errorLine, out String errorMessage); [domain=Debugger] void activateBreakpoints(); @@ -251,13 +269,16 @@ module core { [domain=Debugger] void pause(); [notify, domain=Debugger] void pausedScript(out Object details); [domain=Debugger] void resume(); - [notify, domain=Debugger] void resumedScript(); // FIXME: Make this out parameter fo resume if possible. - - [domain=Debugger] void setPauseOnExceptionsState(in long pauseOnExceptionsState, out long newState); + [notify, domain=Debugger] void resumedScript(); // FIXME: Make this out parameter of resume if possible. [domain=Debugger] void editScriptSource(in String sourceID, in String newContent, out boolean success, out String result, out Value newCallFrames); [domain=Debugger] void getScriptSource(in String sourceID, out String scriptSource); + [domain=Debugger] void setPauseOnExceptionsState(in long pauseOnExceptionsState, out long newState); + + [domain=Debugger] void evaluateOnCallFrame(in Object callFrameId, in String expression, in String objectGroup, out Value result); + [domain=Debugger] void getCompletionsOnCallFrame(in Object callFrameId, in String expression, in boolean includeInspectorCommandLineAPI, out Value result); + [notify, domain=Debugger] void breakpointResolved(out String breakpointId, out String sourceID, out unsigned int lineNumber, out String condition, out boolean enabled, out unsigned int originalLineNumber); #if defined(ENABLE_WORKERS) && ENABLE_WORKERS @@ -269,7 +290,7 @@ module core { // Profiler API /////////////////////////////////////////////////////////////////////// - [domain=Inspector] void enableProfiler(in boolean always); // FIXME: preferrable with Inspector domain, dispatched on backend. + [domain=Inspector] void enableProfiler(in boolean always); [domain=Inspector] void disableProfiler(in boolean always); [notify, domain=Profiler] void profilerWasEnabled(); [notify, domain=Profiler] void profilerWasDisabled(); diff --git a/Source/WebCore/inspector/InspectorApplicationCacheAgent.h b/Source/WebCore/inspector/InspectorApplicationCacheAgent.h index 3d9e494..ac0acbf 100644 --- a/Source/WebCore/inspector/InspectorApplicationCacheAgent.h +++ b/Source/WebCore/inspector/InspectorApplicationCacheAgent.h @@ -41,7 +41,8 @@ class InspectorObject; class InspectorValue; class ResourceResponse; -class InspectorApplicationCacheAgent : public Noncopyable { +class InspectorApplicationCacheAgent { + WTF_MAKE_NONCOPYABLE(InspectorApplicationCacheAgent); WTF_MAKE_FAST_ALLOCATED; public: InspectorApplicationCacheAgent(InspectorController* inspectorController, InspectorFrontend* frontend); ~InspectorApplicationCacheAgent() { } diff --git a/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.cpp b/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.cpp index a33bacc..023dc49 100644 --- a/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.cpp +++ b/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.cpp @@ -71,9 +71,71 @@ InspectorBrowserDebuggerAgent::~InspectorBrowserDebuggerAgent() { } +void InspectorBrowserDebuggerAgent::inspectedURLChanged(const KURL& url) +{ + m_eventListenerBreakpoints.clear(); + m_XHRBreakpoints.clear(); + m_hasXHRBreakpointWithEmptyURL = false; + + RefPtr<InspectorObject> allBreakpoints = m_inspectorController->state()->getObject(InspectorState::browserBreakpoints); + KURL urlCopy = url; + urlCopy.removeFragmentIdentifier(); + RefPtr<InspectorArray> breakpoints = allBreakpoints->getArray(urlCopy); + if (!breakpoints) + return; + for (unsigned i = 0; i < breakpoints->length(); ++i) + restoreStickyBreakpoint(breakpoints->get(i)->asObject()); +} + +void InspectorBrowserDebuggerAgent::restoreStickyBreakpoint(PassRefPtr<InspectorObject> breakpoint) +{ + DEFINE_STATIC_LOCAL(String, eventListenerBreakpointType, ("EventListener")); + DEFINE_STATIC_LOCAL(String, javaScriptBreakpointType, ("JS")); + DEFINE_STATIC_LOCAL(String, xhrBreakpointType, ("XHR")); + + if (!breakpoint) + return; + String type; + if (!breakpoint->getString("type", &type)) + return; + bool enabled; + if (!breakpoint->getBoolean("enabled", &enabled)) + return; + RefPtr<InspectorObject> condition = breakpoint->getObject("condition"); + if (!condition) + return; + + if (type == eventListenerBreakpointType) { + if (!enabled) + return; + String eventName; + if (!condition->getString("eventName", &eventName)) + return; + setEventListenerBreakpoint(eventName); + } else if (type == javaScriptBreakpointType && m_inspectorController->debuggerAgent()) { + String url; + if (!condition->getString("url", &url)) + return; + double lineNumber; + if (!condition->getNumber("lineNumber", &lineNumber)) + return; + String javaScriptCondition; + if (!condition->getString("condition", &javaScriptCondition)) + return; + m_inspectorController->debuggerAgent()->setStickyBreakpoint(url, static_cast<unsigned>(lineNumber), javaScriptCondition, enabled); + } else if (type == xhrBreakpointType) { + if (!enabled) + return; + String url; + if (!condition->getString("url", &url)) + return; + setXHRBreakpoint(url); + } +} + void InspectorBrowserDebuggerAgent::discardBindings() { - m_breakpoints.clear(); + m_domBreakpoints.clear(); } void InspectorBrowserDebuggerAgent::setEventListenerBreakpoint(const String& eventName) @@ -88,8 +150,8 @@ void InspectorBrowserDebuggerAgent::removeEventListenerBreakpoint(const String& void InspectorBrowserDebuggerAgent::didInsertDOMNode(Node* node) { - if (m_breakpoints.size()) { - uint32_t mask = m_breakpoints.get(InspectorDOMAgent::innerParentNode(node)); + if (m_domBreakpoints.size()) { + uint32_t mask = m_domBreakpoints.get(InspectorDOMAgent::innerParentNode(node)); uint32_t inheritableTypesMask = (mask | (mask >> domBreakpointDerivedTypeShift)) & inheritableDOMBreakpointTypesMask; if (inheritableTypesMask) updateSubtreeBreakpoints(node, inheritableTypesMask, true); @@ -98,16 +160,16 @@ void InspectorBrowserDebuggerAgent::didInsertDOMNode(Node* node) void InspectorBrowserDebuggerAgent::didRemoveDOMNode(Node* node) { - if (m_breakpoints.size()) { + if (m_domBreakpoints.size()) { // Remove subtree breakpoints. - m_breakpoints.remove(node); + m_domBreakpoints.remove(node); Vector<Node*> stack(1, InspectorDOMAgent::innerFirstChild(node)); do { Node* node = stack.last(); stack.removeLast(); if (!node) continue; - m_breakpoints.remove(node); + m_domBreakpoints.remove(node); stack.append(InspectorDOMAgent::innerFirstChild(node)); stack.append(InspectorDOMAgent::innerNextSibling(node)); } while (!stack.isEmpty()); @@ -116,12 +178,12 @@ void InspectorBrowserDebuggerAgent::didRemoveDOMNode(Node* node) void InspectorBrowserDebuggerAgent::setDOMBreakpoint(long nodeId, long type) { - Node* node = m_inspectorController->m_domAgent->nodeForId(nodeId); + Node* node = m_inspectorController->domAgent()->nodeForId(nodeId); if (!node) return; uint32_t rootBit = 1 << type; - m_breakpoints.set(node, m_breakpoints.get(node) | rootBit); + m_domBreakpoints.set(node, m_domBreakpoints.get(node) | rootBit); if (rootBit & inheritableDOMBreakpointTypesMask) { for (Node* child = InspectorDOMAgent::innerFirstChild(node); child; child = InspectorDOMAgent::innerNextSibling(child)) updateSubtreeBreakpoints(child, rootBit, true); @@ -130,16 +192,16 @@ void InspectorBrowserDebuggerAgent::setDOMBreakpoint(long nodeId, long type) void InspectorBrowserDebuggerAgent::removeDOMBreakpoint(long nodeId, long type) { - Node* node = m_inspectorController->m_domAgent->nodeForId(nodeId); + Node* node = m_inspectorController->domAgent()->nodeForId(nodeId); if (!node) return; uint32_t rootBit = 1 << type; - uint32_t mask = m_breakpoints.get(node) & ~rootBit; + uint32_t mask = m_domBreakpoints.get(node) & ~rootBit; if (mask) - m_breakpoints.set(node, mask); + m_domBreakpoints.set(node, mask); else - m_breakpoints.remove(node); + m_domBreakpoints.remove(node); if ((rootBit & inheritableDOMBreakpointTypesMask) && !(mask & (rootBit << domBreakpointDerivedTypeShift))) { for (Node* child = InspectorDOMAgent::innerFirstChild(node); child; child = InspectorDOMAgent::innerNextSibling(child)) @@ -149,7 +211,7 @@ void InspectorBrowserDebuggerAgent::removeDOMBreakpoint(long nodeId, long type) void InspectorBrowserDebuggerAgent::willInsertDOMNode(Node*, Node* parent) { - InspectorDebuggerAgent* debuggerAgent = m_inspectorController->m_debuggerAgent.get(); + InspectorDebuggerAgent* debuggerAgent = m_inspectorController->debuggerAgent(); if (!debuggerAgent) return; @@ -163,7 +225,7 @@ void InspectorBrowserDebuggerAgent::willInsertDOMNode(Node*, Node* parent) void InspectorBrowserDebuggerAgent::willRemoveDOMNode(Node* node) { - InspectorDebuggerAgent* debuggerAgent = m_inspectorController->m_debuggerAgent.get(); + InspectorDebuggerAgent* debuggerAgent = m_inspectorController->debuggerAgent(); if (!debuggerAgent) return; @@ -182,7 +244,7 @@ void InspectorBrowserDebuggerAgent::willRemoveDOMNode(Node* node) void InspectorBrowserDebuggerAgent::willModifyDOMAttr(Element* element) { - InspectorDebuggerAgent* debuggerAgent = m_inspectorController->m_debuggerAgent.get(); + InspectorDebuggerAgent* debuggerAgent = m_inspectorController->debuggerAgent(); if (!debuggerAgent) return; @@ -202,7 +264,7 @@ void InspectorBrowserDebuggerAgent::descriptionForDOMEvent(Node* target, long br if ((1 << breakpointType) & inheritableDOMBreakpointTypesMask) { // For inheritable breakpoint types, target node isn't always the same as the node that owns a breakpoint. // Target node may be unknown to frontend, so we need to push it first. - long targetNodeId = m_inspectorController->m_domAgent->pushNodePathToFrontend(target); + long targetNodeId = m_inspectorController->domAgent()->pushNodePathToFrontend(target); ASSERT(targetNodeId); description->setNumber("targetNodeId", targetNodeId); @@ -210,7 +272,7 @@ void InspectorBrowserDebuggerAgent::descriptionForDOMEvent(Node* target, long br if (!insertion) breakpointOwner = InspectorDOMAgent::innerParentNode(target); ASSERT(breakpointOwner); - while (!(m_breakpoints.get(breakpointOwner) & (1 << breakpointType))) { + while (!(m_domBreakpoints.get(breakpointOwner) & (1 << breakpointType))) { breakpointOwner = InspectorDOMAgent::innerParentNode(breakpointOwner); ASSERT(breakpointOwner); } @@ -219,7 +281,7 @@ void InspectorBrowserDebuggerAgent::descriptionForDOMEvent(Node* target, long br description->setBoolean("insertion", insertion); } - long breakpointOwnerNodeId = m_inspectorController->m_domAgent->pushNodePathToFrontend(breakpointOwner); + long breakpointOwnerNodeId = m_inspectorController->domAgent()->pushNodePathToFrontend(breakpointOwner); ASSERT(breakpointOwnerNodeId); description->setNumber("nodeId", breakpointOwnerNodeId); description->setNumber("type", breakpointType); @@ -229,18 +291,18 @@ bool InspectorBrowserDebuggerAgent::hasBreakpoint(Node* node, long type) { uint32_t rootBit = 1 << type; uint32_t derivedBit = rootBit << domBreakpointDerivedTypeShift; - return m_breakpoints.get(node) & (rootBit | derivedBit); + return m_domBreakpoints.get(node) & (rootBit | derivedBit); } void InspectorBrowserDebuggerAgent::updateSubtreeBreakpoints(Node* node, uint32_t rootMask, bool set) { - uint32_t oldMask = m_breakpoints.get(node); + uint32_t oldMask = m_domBreakpoints.get(node); uint32_t derivedMask = rootMask << domBreakpointDerivedTypeShift; uint32_t newMask = set ? oldMask | derivedMask : oldMask & ~derivedMask; if (newMask) - m_breakpoints.set(node, newMask); + m_domBreakpoints.set(node, newMask); else - m_breakpoints.remove(node); + m_domBreakpoints.remove(node); uint32_t newRootMask = rootMask & ~newMask; if (!newRootMask) @@ -252,7 +314,7 @@ void InspectorBrowserDebuggerAgent::updateSubtreeBreakpoints(Node* node, uint32_ void InspectorBrowserDebuggerAgent::pauseOnNativeEventIfNeeded(const String& categoryType, const String& eventName, bool synchronous) { - InspectorDebuggerAgent* debuggerAgent = m_inspectorController->m_debuggerAgent.get(); + InspectorDebuggerAgent* debuggerAgent = m_inspectorController->debuggerAgent(); if (!debuggerAgent) return; @@ -287,7 +349,7 @@ void InspectorBrowserDebuggerAgent::removeXHRBreakpoint(const String& url) void InspectorBrowserDebuggerAgent::willSendXMLHttpRequest(const String& url) { - InspectorDebuggerAgent* debuggerAgent = m_inspectorController->m_debuggerAgent.get(); + InspectorDebuggerAgent* debuggerAgent = m_inspectorController->debuggerAgent(); if (!debuggerAgent) return; @@ -313,13 +375,6 @@ void InspectorBrowserDebuggerAgent::willSendXMLHttpRequest(const String& url) debuggerAgent->breakProgram(NativeBreakpointDebuggerEventType, eventData.release()); } -void InspectorBrowserDebuggerAgent::clearForPageNavigation() -{ - m_eventListenerBreakpoints.clear(); - m_XHRBreakpoints.clear(); - m_hasXHRBreakpointWithEmptyURL = false; -} - } // namespace WebCore #endif // ENABLE(INSPECTOR) && ENABLE(JAVASCRIPT_DEBUGGER) diff --git a/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.h b/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.h index 537bda1..0ffa85c 100644 --- a/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.h +++ b/Source/WebCore/inspector/InspectorBrowserDebuggerAgent.h @@ -46,9 +46,11 @@ namespace WebCore { class Element; class InspectorController; class InspectorObject; +class KURL; class Node; -class InspectorBrowserDebuggerAgent : public Noncopyable { +class InspectorBrowserDebuggerAgent { + WTF_MAKE_NONCOPYABLE(InspectorBrowserDebuggerAgent); public: static PassOwnPtr<InspectorBrowserDebuggerAgent> create(InspectorController* inspectorController) { @@ -57,6 +59,8 @@ public: virtual ~InspectorBrowserDebuggerAgent(); + void inspectedURLChanged(const KURL&); + // BrowserDebugger API for InspectorFrontend void setXHRBreakpoint(const String& url); void removeXHRBreakpoint(const String& url); @@ -74,17 +78,18 @@ public: void willSendXMLHttpRequest(const String& url); void pauseOnNativeEventIfNeeded(const String& categoryType, const String& eventName, bool synchronous); - void clearForPageNavigation(); private: InspectorBrowserDebuggerAgent(InspectorController*); + void restoreStickyBreakpoint(PassRefPtr<InspectorObject> breakpoint); + void descriptionForDOMEvent(Node* target, long breakpointType, bool insertion, InspectorObject* description); void updateSubtreeBreakpoints(Node*, uint32_t rootMask, bool set); bool hasBreakpoint(Node*, long type); void discardBindings(); InspectorController* m_inspectorController; - HashMap<Node*, uint32_t> m_breakpoints; + HashMap<Node*, uint32_t> m_domBreakpoints; HashSet<String> m_eventListenerBreakpoints; HashSet<String> m_XHRBreakpoints; bool m_hasXHRBreakpointWithEmptyURL; diff --git a/Source/WebCore/inspector/InspectorCSSAgent.cpp b/Source/WebCore/inspector/InspectorCSSAgent.cpp index 725a26d..bacf741 100644 --- a/Source/WebCore/inspector/InspectorCSSAgent.cpp +++ b/Source/WebCore/inspector/InspectorCSSAgent.cpp @@ -349,6 +349,8 @@ void InspectorCSSAgent::addRule2(const long contextNodeId, const String& selecto return; InspectorStyleSheet* inspectorStyleSheet = viaInspectorStyleSheet(node->document(), true); + if (!inspectorStyleSheet) + return; CSSStyleRule* newRule = inspectorStyleSheet->addRule(selector); if (!newRule) return; @@ -447,8 +449,17 @@ InspectorStyleSheet* InspectorCSSAgent::viaInspectorStyleSheet(Document* documen RefPtr<Element> styleElement = document->createElement("style", ec); if (!ec) styleElement->setAttribute("type", "text/css", ec); - if (!ec) - document->head()->appendChild(styleElement, ec); + if (!ec) { + ContainerNode* targetNode; + // HEAD is absent in ImageDocuments, for example. + if (document->head()) + targetNode = document->head(); + else if (document->body()) + targetNode = document->body(); + else + return 0; + targetNode->appendChild(styleElement, ec); + } if (ec) return 0; StyleSheetList* styleSheets = document->styleSheets(); diff --git a/Source/WebCore/inspector/InspectorConsoleAgent.cpp b/Source/WebCore/inspector/InspectorConsoleAgent.cpp index a543cb2..2c837f3 100644 --- a/Source/WebCore/inspector/InspectorConsoleAgent.cpp +++ b/Source/WebCore/inspector/InspectorConsoleAgent.cpp @@ -33,6 +33,7 @@ #include "InspectorController.h" #include "InspectorDOMAgent.h" #include "InspectorFrontend.h" +#include "InspectorSettings.h" #include "InspectorState.h" #include "ResourceError.h" #include "ResourceResponse.h" @@ -49,9 +50,8 @@ namespace WebCore { static const unsigned maximumConsoleMessages = 1000; static const unsigned expireConsoleMessagesStep = 100; -InspectorConsoleAgent::InspectorConsoleAgent(InspectorController* inspectorController, InspectorState* state) +InspectorConsoleAgent::InspectorConsoleAgent(InspectorController* inspectorController) : m_inspectorController(inspectorController) - , m_state(state) , m_frontend(0) , m_previousMessage(0) , m_expiredConsoleMessageCount(0) @@ -165,7 +165,7 @@ void InspectorConsoleAgent::resourceRetrievedByXMLHttpRequest(const String& url, { if (!m_inspectorController->enabled()) return; - if (m_state->getBoolean(InspectorState::monitoringXHR)) + if (m_inspectorController->state()->getBoolean(InspectorState::monitoringXHR)) addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, "XHR finished loading: \"" + url + "\".", sendLineNumber, sendURL); } @@ -191,11 +191,21 @@ void InspectorConsoleAgent::didFailLoading(unsigned long identifier, const Resou addConsoleMessage(new ConsoleMessage(OtherMessageSource, NetworkErrorMessageType, ErrorMessageLevel, message, error.failingURL(), identifier)); } +void InspectorConsoleAgent::setMonitoringXHREnabled(bool enabled) +{ + m_inspectorController->state()->setBoolean(InspectorState::monitoringXHR, enabled); + m_inspectorController->settings()->setBoolean(InspectorSettings::MonitoringXHREnabled, enabled); + if (m_frontend) + m_frontend->monitoringXHRStateChanged(enabled); +} + void InspectorConsoleAgent::setConsoleMessagesEnabled(bool enabled) { - m_state->setBoolean(InspectorState::consoleMessagesEnabled, enabled); - if (!m_inspectorController->enabled()) + m_inspectorController->state()->setBoolean(InspectorState::consoleMessagesEnabled, enabled); + if (!enabled || !m_frontend) return; + + m_frontend->monitoringXHRStateChanged(m_inspectorController->state()->getBoolean(InspectorState::monitoringXHR)); if (m_expiredConsoleMessageCount) m_frontend->updateConsoleMessageExpiredCount(m_expiredConsoleMessageCount); unsigned messageCount = m_consoleMessages.size(); @@ -210,12 +220,12 @@ void InspectorConsoleAgent::addConsoleMessage(PassOwnPtr<ConsoleMessage> console if (m_previousMessage && m_previousMessage->isEqual(consoleMessage.get())) { m_previousMessage->incrementCount(); - if (m_state->getBoolean(InspectorState::consoleMessagesEnabled) && m_frontend) + if (m_inspectorController->state()->getBoolean(InspectorState::consoleMessagesEnabled) && m_frontend) m_previousMessage->updateRepeatCountInConsole(m_frontend); } else { m_previousMessage = consoleMessage.get(); m_consoleMessages.append(consoleMessage); - if (m_state->getBoolean(InspectorState::consoleMessagesEnabled) && m_frontend) + if (m_inspectorController->state()->getBoolean(InspectorState::consoleMessagesEnabled) && m_frontend) m_previousMessage->addToFrontend(m_frontend, m_inspectorController->injectedScriptHost()); } diff --git a/Source/WebCore/inspector/InspectorConsoleAgent.h b/Source/WebCore/inspector/InspectorConsoleAgent.h index 97fcb3f..411f709 100644 --- a/Source/WebCore/inspector/InspectorConsoleAgent.h +++ b/Source/WebCore/inspector/InspectorConsoleAgent.h @@ -46,9 +46,10 @@ class ScriptArguments; class ScriptCallStack; class ScriptProfile; -class InspectorConsoleAgent : public Noncopyable { +class InspectorConsoleAgent { + WTF_MAKE_NONCOPYABLE(InspectorConsoleAgent); public: - InspectorConsoleAgent(InspectorController*, InspectorState*); + InspectorConsoleAgent(InspectorController*); ~InspectorConsoleAgent(); void setConsoleMessagesEnabled(bool enabled, bool* newState); @@ -70,13 +71,13 @@ public: void addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile>, unsigned lineNumber, const String& sourceURL); void addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL); #endif + void setMonitoringXHREnabled(bool enabled); private: void setConsoleMessagesEnabled(bool); void addConsoleMessage(PassOwnPtr<ConsoleMessage>); InspectorController* m_inspectorController; - InspectorState* m_state; InspectorFrontend* m_frontend; ConsoleMessage* m_previousMessage; Vector<OwnPtr<ConsoleMessage> > m_consoleMessages; diff --git a/Source/WebCore/inspector/InspectorController.cpp b/Source/WebCore/inspector/InspectorController.cpp index 5a139b6..8533a5f 100644 --- a/Source/WebCore/inspector/InspectorController.cpp +++ b/Source/WebCore/inspector/InspectorController.cpp @@ -70,6 +70,7 @@ #include "InspectorInstrumentation.h" #include "InspectorProfilerAgent.h" #include "InspectorResourceAgent.h" +#include "InspectorRuntimeAgent.h" #include "InspectorSettings.h" #include "InspectorState.h" #include "InspectorTimelineAgent.h" @@ -95,6 +96,7 @@ #include "SharedBuffer.h" #include "TextEncoding.h" #include "TextIterator.h" +#include "TextRun.h" #include "UserGestureIndicator.h" #include "WindowFeatures.h" #include <wtf/text/StringConcatenate.h> @@ -140,7 +142,7 @@ InspectorController::InspectorController(Page* page, InspectorClient* client) , m_state(new InspectorState(client)) , m_inspectorBackendDispatcher(new InspectorBackendDispatcher(this)) , m_injectedScriptHost(InjectedScriptHost::create(this)) - , m_consoleAgent(new InspectorConsoleAgent(this, m_state.get())) + , m_consoleAgent(new InspectorConsoleAgent(this)) #if ENABLE(JAVASCRIPT_DEBUGGER) , m_attachDebuggerWhenShown(false) , m_profilerAgent(InspectorProfilerAgent::create(this)) @@ -156,10 +158,6 @@ InspectorController::~InspectorController() ASSERT(!m_client); ASSERT(!m_inspectedPage); ASSERT(!m_highlightedNode); - - releaseFrontendLifetimeAgents(); - - m_injectedScriptHost->disconnectController(); } void InspectorController::inspectedPageDestroyed() @@ -177,6 +175,9 @@ void InspectorController::inspectedPageDestroyed() ASSERT(m_inspectedPage); m_inspectedPage = 0; + releaseFrontendLifetimeAgents(); + m_injectedScriptHost->disconnectController(); + m_client->inspectorDestroyed(); m_client = 0; } @@ -213,15 +214,6 @@ bool InspectorController::searchingForNodeInPage() const return m_state->getBoolean(InspectorState::searchingForNode); } -void InspectorController::getInspectorState(RefPtr<InspectorObject>* state) -{ -#if ENABLE(JAVASCRIPT_DEBUGGER) - if (m_debuggerAgent) - m_state->setLong(InspectorState::pauseOnExceptionsState, m_debuggerAgent->pauseOnExceptionsState()); -#endif - *state = m_state->generateStateObjectForFrontend(); -} - void InspectorController::restoreInspectorStateFromCookie(const String& inspectorStateCookie) { m_state->restoreFromInspectorCookie(inspectorStateCookie); @@ -229,11 +221,13 @@ void InspectorController::restoreInspectorStateFromCookie(const String& inspecto if (!m_frontend) { connectFrontend(); m_frontend->frontendReused(); - m_frontend->inspectedURLChanged(m_inspectedPage->mainFrame()->loader()->url().string()); + m_frontend->inspectedURLChanged(inspectedURL().string()); m_domAgent->setDocument(m_inspectedPage->mainFrame()->document()); pushDataCollectedOffline(); } + m_resourceAgent = InspectorResourceAgent::restore(m_inspectedPage, m_state.get(), m_frontend.get()); + if (m_state->getBoolean(InspectorState::timelineProfilerEnabled)) startTimelineProfiler(); @@ -381,21 +375,13 @@ void InspectorController::setSearchingForNode(bool enabled, bool* newState) setSearchingForNode(enabled); } -void InspectorController::setMonitoringXHREnabled(bool enabled, bool* newState) -{ - *newState = enabled; - m_state->setBoolean(InspectorState::monitoringXHR, enabled); - m_settings->setBoolean(InspectorSettings::MonitoringXHREnabled, enabled); -} - void InspectorController::connectFrontend() { m_openingFrontend = false; releaseFrontendLifetimeAgents(); m_frontend = new InspectorFrontend(m_client); - m_domAgent = InspectorDOMAgent::create(m_frontend.get()); - m_resourceAgent = InspectorResourceAgent::create(m_inspectedPage, m_frontend.get()); - + m_domAgent = InspectorDOMAgent::create(m_injectedScriptHost.get(), m_frontend.get()); + m_runtimeAgent = InspectorRuntimeAgent::create(m_injectedScriptHost.get()); m_cssAgent->setDOMAgent(m_domAgent.get()); #if ENABLE(DATABASE) @@ -412,7 +398,7 @@ void InspectorController::connectFrontend() m_consoleAgent->setFrontend(m_frontend.get()); // Initialize Web Inspector title. - m_frontend->inspectedURLChanged(m_inspectedPage->mainFrame()->loader()->url().string()); + m_frontend->inspectedURLChanged(inspectedURL().string()); #if ENABLE(OFFLINE_WEB_APPLICATIONS) m_applicationCacheAgent = new InspectorApplicationCacheAgent(this, m_frontend.get()); @@ -501,9 +487,17 @@ void InspectorController::disconnectFrontend() m_extraHeaders.clear(); } +InspectorResourceAgent* InspectorController::resourceAgent() +{ + if (!m_resourceAgent && m_frontend) + m_resourceAgent = InspectorResourceAgent::create(m_inspectedPage, m_state.get(), m_frontend.get()); + return m_resourceAgent.get(); +} + void InspectorController::releaseFrontendLifetimeAgents() { m_resourceAgent.clear(); + m_runtimeAgent.clear(); // This should be invoked prior to m_domAgent destruction. m_cssAgent->setDOMAgent(0); @@ -607,7 +601,7 @@ void InspectorController::restoreProfiler(ProfilerRestoreAction action) if (!ScriptProfiler::isProfilerAlwaysEnabled() && m_settings->getBoolean(InspectorSettings::ProfilerAlwaysEnabled)) enableProfiler(); if (action == ProfilerRestoreResetAgent) - m_profilerAgent->resetState(); + m_profilerAgent->resetFrontendProfiles(); #endif } @@ -648,8 +642,7 @@ void InspectorController::didCommitLoad(DocumentLoader* loader) if (m_debuggerAgent) { m_debuggerAgent->clearForPageNavigation(); if (m_browserDebuggerAgent) - m_browserDebuggerAgent->clearForPageNavigation(); - restoreStickyBreakpoints(); + m_browserDebuggerAgent->inspectedURLChanged(inspectedURL()); } #endif @@ -988,23 +981,11 @@ void InspectorController::didCloseWebSocket(unsigned long identifier) #endif // ENABLE(WEB_SOCKETS) #if ENABLE(JAVASCRIPT_DEBUGGER) -void InspectorController::addProfile(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL) -{ - if (!enabled()) - return; - m_profilerAgent->addProfile(prpProfile, lineNumber, sourceURL); -} - bool InspectorController::isRecordingUserInitiatedProfile() const { return m_profilerAgent->isRecordingUserInitiatedProfile(); } -String InspectorController::getCurrentUserInitiatedProfileName(bool incrementProfileNumber) -{ - return m_profilerAgent->getCurrentUserInitiatedProfileName(incrementProfileNumber); -} - void InspectorController::startUserInitiatedProfiling() { if (!enabled()) @@ -1067,7 +1048,7 @@ void InspectorController::enableDebugger(bool always) m_debuggerAgent = InspectorDebuggerAgent::create(this, m_frontend.get()); m_browserDebuggerAgent = InspectorBrowserDebuggerAgent::create(this); - restoreStickyBreakpoints(); + m_browserDebuggerAgent->inspectedURLChanged(inspectedURL()); m_frontend->debuggerWasEnabled(); } @@ -1097,95 +1078,12 @@ void InspectorController::resume() m_debuggerAgent->resume(); } -void InspectorController::setStickyBreakpoints(PassRefPtr<InspectorObject> breakpoints) +void InspectorController::setAllBrowserBreakpoints(PassRefPtr<InspectorObject> breakpoints) { - m_state->setObject(InspectorState::stickyBreakpoints, breakpoints); -} - -void InspectorController::restoreStickyBreakpoints() -{ - RefPtr<InspectorObject> allBreakpoints = m_state->getObject(InspectorState::stickyBreakpoints); - KURL url = m_inspectedPage->mainFrame()->loader()->url(); - url.removeFragmentIdentifier(); - RefPtr<InspectorArray> breakpoints = allBreakpoints->getArray(url); - if (!breakpoints) - return; - for (unsigned i = 0; i < breakpoints->length(); ++i) - restoreStickyBreakpoint(breakpoints->get(i)->asObject()); -} - -void InspectorController::restoreStickyBreakpoint(PassRefPtr<InspectorObject> breakpoint) -{ - DEFINE_STATIC_LOCAL(String, eventListenerBreakpointType, ("EventListener")); - DEFINE_STATIC_LOCAL(String, javaScriptBreakpointType, ("JS")); - DEFINE_STATIC_LOCAL(String, xhrBreakpointType, ("XHR")); - - if (!breakpoint) - return; - String type; - if (!breakpoint->getString("type", &type)) - return; - bool enabled; - if (!breakpoint->getBoolean("enabled", &enabled)) - return; - RefPtr<InspectorObject> condition = breakpoint->getObject("condition"); - if (!condition) - return; - - if (type == eventListenerBreakpointType && m_browserDebuggerAgent) { - if (!enabled) - return; - String eventName; - if (!condition->getString("eventName", &eventName)) - return; - m_browserDebuggerAgent->setEventListenerBreakpoint(eventName); - } else if (type == javaScriptBreakpointType && m_debuggerAgent) { - String url; - if (!condition->getString("url", &url)) - return; - double lineNumber; - if (!condition->getNumber("lineNumber", &lineNumber)) - return; - String javaScriptCondition; - if (!condition->getString("condition", &javaScriptCondition)) - return; - m_debuggerAgent->setStickyBreakpoint(url, static_cast<unsigned>(lineNumber), javaScriptCondition, enabled); - } else if (type == xhrBreakpointType && m_browserDebuggerAgent) { - if (!enabled) - return; - String url; - if (!condition->getString("url", &url)) - return; - m_browserDebuggerAgent->setXHRBreakpoint(url); - } + m_state->setObject(InspectorState::browserBreakpoints, breakpoints); } #endif -void InspectorController::dispatchOnInjectedScript(long injectedScriptId, const String& methodName, const String& arguments, RefPtr<InspectorValue>* result, bool* hadException) -{ - if (!m_frontend) - return; - - // FIXME: explicitly pass injectedScriptId along with node id to the frontend. - bool injectedScriptIdIsNodeId = injectedScriptId <= 0; - - InjectedScript injectedScript; - if (injectedScriptIdIsNodeId) - injectedScript = injectedScriptForNodeId(-injectedScriptId); - else - injectedScript = injectedScriptHost()->injectedScriptForId(injectedScriptId); - - if (injectedScript.hasNoValue()) - return; - - injectedScript.dispatch(methodName, arguments, result, hadException); -} - -void InspectorController::releaseWrapperObjectGroup(long injectedScriptId, const String& objectGroup) -{ - injectedScriptHost()->releaseWrapperObjectGroup(injectedScriptId, objectGroup); -} - void InspectorController::evaluateForTestInFrontend(long callId, const String& script) { if (m_frontend) @@ -1468,27 +1366,6 @@ void InspectorController::openInInspectedWindow(const String& url) newFrame->loader()->changeLocation(mainFrame->document()->securityOrigin(), newFrame->loader()->completeURL(url), "", false, false); } -InjectedScript InspectorController::injectedScriptForNodeId(long id) -{ - - Frame* frame = 0; - if (id) { - ASSERT(m_domAgent); - Node* node = m_domAgent->nodeForId(id); - if (node) { - Document* document = node->ownerDocument(); - if (document) - frame = document->frame(); - } - } else - frame = m_inspectedPage->mainFrame(); - - if (frame) - return m_injectedScriptHost->injectedScriptFor(mainWorldScriptState(frame)); - - return InjectedScript(); -} - void InspectorController::addScriptToEvaluateOnLoad(const String& source) { m_scriptsToEvaluateOnLoad.append(source); @@ -1504,6 +1381,11 @@ void InspectorController::setInspectorExtensionAPI(const String& source) m_inspectorExtensionAPI = source; } +KURL InspectorController::inspectedURL() const +{ + return m_inspectedPage->mainFrame()->loader()->url(); +} + void InspectorController::reloadPage() { // FIXME: Why do we set the user gesture indicator here? diff --git a/Source/WebCore/inspector/InspectorController.h b/Source/WebCore/inspector/InspectorController.h index 9cddc56..90a0300 100644 --- a/Source/WebCore/inspector/InspectorController.h +++ b/Source/WebCore/inspector/InspectorController.h @@ -72,6 +72,7 @@ class InspectorFrontendClient; class InspectorObject; class InspectorProfilerAgent; class InspectorResourceAgent; +class InspectorRuntimeAgent; class InspectorSettings; class InspectorState; class InspectorStorageAgent; @@ -104,7 +105,8 @@ class WebSocketHandshakeRequest; class WebSocketHandshakeResponse; #endif -class InspectorController : public Noncopyable { +class InspectorController { + WTF_MAKE_NONCOPYABLE(InspectorController); WTF_MAKE_FAST_ALLOCATED; public: static const char* const ConsolePanel; static const char* const ElementsPanel; @@ -123,6 +125,7 @@ public: bool enabled() const; Page* inspectedPage() const { return m_inspectedPage; } + KURL inspectedURL() const; void reloadPage(); void restoreInspectorStateFromCookie(const String& inspectorCookie); @@ -143,9 +146,35 @@ public: void connectFrontend(); void reuseFrontend(); void disconnectFrontend(); + InspectorFrontend* frontend() const { return m_frontend.get(); } + + InspectorResourceAgent* resourceAgent(); + + InspectorController* inspectorAgent() { return this; } + InspectorConsoleAgent* consoleAgent() { return m_consoleAgent.get(); } + InspectorCSSAgent* cssAgent() { return m_cssAgent.get(); } + InspectorDOMAgent* domAgent() { return m_domAgent.get(); } + InjectedScriptHost* injectedScriptAgent() { return m_injectedScriptHost.get(); } + InspectorRuntimeAgent* runtimeAgent() { return m_runtimeAgent.get(); } + InspectorTimelineAgent* timelineAgent() { return m_timelineAgent.get(); } +#if ENABLE(DATABASE) + InspectorDatabaseAgent* databaseAgent() { return m_databaseAgent.get(); } +#endif +#if ENABLE(DOM_STORAGE) + InspectorDOMStorageAgent* domStorageAgent() { return m_domStorageAgent.get(); } +#endif +#if ENABLE(FILE_SYSTEM) + InspectorFileSystemAgent* fileSystemAgent() { return m_fileSystemAgent.get(); } +#endif +#if ENABLE(JAVASCRIPT_DEBUGGER) + InspectorBrowserDebuggerAgent* browserDebuggerAgent() const { return m_browserDebuggerAgent.get(); } + InspectorDebuggerAgent* debuggerAgent() const { return m_debuggerAgent.get(); } + InspectorProfilerAgent* profilerAgent() const { return m_profilerAgent.get(); } +#endif +#if ENABLE(OFFLINE_WEB_APPLICATIONS) + InspectorApplicationCacheAgent* applicationCacheAgent() { return m_applicationCacheAgent.get(); } +#endif - InspectorConsoleAgent* consoleAgent() const { return m_consoleAgent.get(); } - InspectorDOMAgent* domAgent() const { return m_domAgent.get(); } bool searchingForNodeInPage() const; void mouseDidMoveOverElement(const HitTestResult&, unsigned modifierFlags); @@ -162,15 +191,10 @@ public: void startTimelineProfiler(); void stopTimelineProfiler(); - InspectorTimelineAgent* timelineAgent() { return m_timelineAgent.get(); } void getCookies(RefPtr<InspectorArray>* cookies, WTF::String* cookiesString); void deleteCookie(const String& cookieName, const String& domain); -#if ENABLE(OFFLINE_WEB_APPLICATIONS) - InspectorApplicationCacheAgent* applicationCacheAgent() { return m_applicationCacheAgent.get(); } -#endif - void mainResourceFiredLoadEvent(DocumentLoader*, const KURL&); void mainResourceFiredDOMContentEvent(DocumentLoader*, const KURL&); @@ -204,9 +228,7 @@ public: void drawElementTitle(GraphicsContext&, const IntRect& boundingBox, const FloatRect& overlayRect, WebCore::Settings*) const; #if ENABLE(JAVASCRIPT_DEBUGGER) - void addProfile(PassRefPtr<ScriptProfile>, unsigned lineNumber, const String& sourceURL); bool isRecordingUserInitiatedProfile() const; - String getCurrentUserInitiatedProfileName(bool incrementProfileNumber = false); void startProfiling() { startUserInitiatedProfiling(); } void startUserInitiatedProfiling(); void stopProfiling() { stopUserInitiatedProfiling(); } @@ -221,19 +243,12 @@ public: bool debuggerEnabled() const { return m_debuggerAgent; } void resume(); - void setStickyBreakpoints(PassRefPtr<InspectorObject> breakpoints); + void setAllBrowserBreakpoints(PassRefPtr<InspectorObject>); #endif - void setInjectedScriptSource(const String& source); - void dispatchOnInjectedScript(long injectedScriptId, const String& methodName, const String& arguments, RefPtr<InspectorValue>* result, bool* hadException); - // Generic code called from custom implementations. - void releaseWrapperObjectGroup(long injectedScriptId, const String& objectGroup); - void evaluateForTestInFrontend(long testCallId, const String& script); - InjectedScript injectedScriptForNodeId(long id); - void addScriptToEvaluateOnLoad(const String& source); void removeAllScriptsToEvaluateOnLoad(); void setInspectorExtensionAPI(const String& source); @@ -243,20 +258,22 @@ public: void setInspectorAttachedHeight(long height); long inspectorAttachedHeight() const; -private: - friend class InspectorBackend; - friend class InspectorBackendDispatcher; - friend class InspectorBrowserDebuggerAgent; - friend class InspectorInstrumentation; - friend class InjectedScriptHost; + InspectorState* state() { return m_state.get(); } + InspectorSettings* settings() { return m_settings.get(); } - void willSendRequest(ResourceRequest&); + // InspectorAgent API + void getInspectorState(RefPtr<InspectorObject>* state); + void setMonitoringXHREnabled(bool enabled, bool* newState); + void populateScriptObjects(); + // Following are used from InspectorBackend and internally. + void setSearchingForNode(bool enabled, bool* newState); + void didEvaluateForTestInFrontend(long callId, const String& jsonResult); + // InspectorInstrumentation API void ensureSettingsLoaded(); + void willSendRequest(ResourceRequest&); - void getInspectorState(RefPtr<InspectorObject>* state); - - void populateScriptObjects(); +private: void pushDataCollectedOffline(); void restoreDebugger(); enum ProfilerRestoreAction { @@ -267,27 +284,18 @@ private: void unbindAllResources(); void setSearchingForNode(bool enabled); - // Following are used from InspectorBackend and internally. - void setSearchingForNode(bool enabled, bool* newState); - - void setMonitoringXHREnabled(bool enabled, bool* newState); void releaseFrontendLifetimeAgents(); #if ENABLE(JAVASCRIPT_DEBUGGER) void toggleRecordButton(bool); - void restoreStickyBreakpoints(); - void restoreStickyBreakpoint(PassRefPtr<InspectorObject> breakpoint); #endif PassRefPtr<InspectorObject> buildObjectForCookie(const Cookie&); PassRefPtr<InspectorArray> buildArrayForCookies(ListHashSet<Cookie>&); void focusNode(); - bool isMainResourceLoader(DocumentLoader* loader, const KURL& requestUrl); - void didEvaluateForTestInFrontend(long callId, const String& jsonResult); - Page* m_inspectedPage; InspectorClient* m_client; OwnPtr<InspectorFrontendClient> m_inspectorFrontendClient; @@ -318,6 +326,7 @@ private: RefPtr<Node> m_nodeToFocus; RefPtr<InspectorResourceAgent> m_resourceAgent; + OwnPtr<InspectorRuntimeAgent> m_runtimeAgent; #if ENABLE(DATABASE) typedef HashMap<int, RefPtr<InspectorDatabaseResource> > DatabaseResourcesMap; @@ -341,7 +350,6 @@ private: bool m_attachDebuggerWhenShown; OwnPtr<InspectorDebuggerAgent> m_debuggerAgent; OwnPtr<InspectorBrowserDebuggerAgent> m_browserDebuggerAgent; - OwnPtr<InspectorProfilerAgent> m_profilerAgent; #endif OwnPtr<HTTPHeaderMap> m_extraHeaders; diff --git a/Source/WebCore/inspector/InspectorDOMAgent.cpp b/Source/WebCore/inspector/InspectorDOMAgent.cpp index 19ae30d..6e10f09 100644 --- a/Source/WebCore/inspector/InspectorDOMAgent.cpp +++ b/Source/WebCore/inspector/InspectorDOMAgent.cpp @@ -59,6 +59,7 @@ #include "FrameTree.h" #include "HTMLElement.h" #include "HTMLFrameOwnerElement.h" +#include "InjectedScriptHost.h" #include "InspectorFrontend.h" #include "MutationEvent.h" #include "Node.h" @@ -206,8 +207,9 @@ public: } -InspectorDOMAgent::InspectorDOMAgent(InspectorFrontend* frontend) +InspectorDOMAgent::InspectorDOMAgent(InjectedScriptHost* injectedScriptHost, InspectorFrontend* frontend) : EventListener(InspectorDOMAgentType) + , m_injectedScriptHost(injectedScriptHost) , m_frontend(frontend) , m_domListener(0) , m_lastNodeId(1) @@ -758,6 +760,34 @@ void InspectorDOMAgent::searchCanceled() m_searchResults.clear(); } +void InspectorDOMAgent::resolveNode(long nodeId, RefPtr<InspectorValue>* result) +{ + InjectedScript injectedScript = injectedScriptForNodeId(nodeId); + if (!injectedScript.hasNoValue()) + injectedScript.resolveNode(nodeId, result); +} + +void InspectorDOMAgent::getNodeProperties(long nodeId, PassRefPtr<InspectorArray> propertiesArray, RefPtr<InspectorValue>* result) +{ + InjectedScript injectedScript = injectedScriptForNodeId(nodeId); + if (!injectedScript.hasNoValue()) + injectedScript.getNodeProperties(nodeId, propertiesArray, result); +} + +void InspectorDOMAgent::getNodePrototypes(long nodeId, RefPtr<InspectorValue>* result) +{ + InjectedScript injectedScript = injectedScriptForNodeId(nodeId); + if (!injectedScript.hasNoValue()) + injectedScript.getNodePrototypes(nodeId, result); +} + +void InspectorDOMAgent::pushNodeToFrontend(PassRefPtr<InspectorObject> objectId, RefPtr<InspectorValue>* result) +{ + InjectedScript injectedScript = m_injectedScriptHost->injectedScriptForObjectId(objectId.get()); + if (!injectedScript.hasNoValue()) + injectedScript.pushNodeToFrontend(objectId, result); +} + String InspectorDOMAgent::documentURLString(Document* document) const { if (!document || document->url().isNull()) @@ -1112,6 +1142,26 @@ void InspectorDOMAgent::pushNodeByPathToFrontend(const String& path, long* nodeI *nodeId = pushNodePathToFrontend(node); } +InjectedScript InspectorDOMAgent::injectedScriptForNodeId(long nodeId) +{ + Frame* frame = 0; + if (nodeId) { + Node* node = nodeForId(nodeId); + if (node) { + Document* document = node->ownerDocument(); + if (document) + frame = document->frame(); + } + } else + frame = mainFrameDocument()->frame(); + + if (frame) + return m_injectedScriptHost->injectedScriptFor(mainWorldScriptState(frame)); + + return InjectedScript(); +} + + } // namespace WebCore #endif // ENABLE(INSPECTOR) diff --git a/Source/WebCore/inspector/InspectorDOMAgent.h b/Source/WebCore/inspector/InspectorDOMAgent.h index 97175fe..e4edf5d 100644 --- a/Source/WebCore/inspector/InspectorDOMAgent.h +++ b/Source/WebCore/inspector/InspectorDOMAgent.h @@ -32,6 +32,8 @@ #include "EventListener.h" #include "EventTarget.h" +#include "InjectedScript.h" +#include "InjectedScriptHost.h" #include "InspectorValues.h" #include "NodeList.h" #include "Timer.h" @@ -45,164 +47,168 @@ #include <wtf/text/AtomicString.h> namespace WebCore { - class ContainerNode; - class CSSRule; - class CSSRuleList; - class CSSStyleDeclaration; - class CSSStyleRule; - class CSSStyleSheet; - class CharacterData; - class Document; - class Element; - class Event; - class InspectorDOMAgent; - class InspectorFrontend; - class MatchJob; - class NameNodeMap; - class Node; - class Page; +class ContainerNode; +class CSSRule; +class CSSRuleList; +class CSSStyleDeclaration; +class CSSStyleRule; +class CSSStyleSheet; +class CharacterData; +class Document; +class Element; +class Event; +class InspectorDOMAgent; +class InspectorFrontend; +class MatchJob; +class NameNodeMap; +class Node; +class Page; #if ENABLE(INSPECTOR) - struct EventListenerInfo { - EventListenerInfo(Node* node, const AtomicString& eventType, const EventListenerVector& eventListenerVector) - : node(node) - , eventType(eventType) - , eventListenerVector(eventListenerVector) +struct EventListenerInfo { + EventListenerInfo(Node* node, const AtomicString& eventType, const EventListenerVector& eventListenerVector) + : node(node) + , eventType(eventType) + , eventListenerVector(eventListenerVector) + { + } + + Node* node; + const AtomicString eventType; + const EventListenerVector eventListenerVector; +}; + +class InspectorDOMAgent : public EventListener { +public: + struct DOMListener { + virtual ~DOMListener() { } - - Node* node; - const AtomicString eventType; - const EventListenerVector eventListenerVector; - }; - - class InspectorDOMAgent : public EventListener { - public: - struct DOMListener { - virtual ~DOMListener() - { - } - virtual void didRemoveDocument(Document*) = 0; - virtual void didRemoveDOMNode(Node*) = 0; - virtual void didModifyDOMAttr(Element*) = 0; - }; - - static PassRefPtr<InspectorDOMAgent> create(InspectorFrontend* frontend) - { - return adoptRef(new InspectorDOMAgent(frontend)); - } - - static const InspectorDOMAgent* cast(const EventListener* listener) - { - return listener->type() == InspectorDOMAgentType - ? static_cast<const InspectorDOMAgent*>(listener) - : 0; - } - - InspectorDOMAgent(InspectorFrontend* frontend); - ~InspectorDOMAgent(); - - void reset(); - - virtual bool operator==(const EventListener& other); - - // Methods called from the frontend for DOM nodes inspection. - void getChildNodes(long nodeId); - void setAttribute(long elementId, const String& name, const String& value, bool* success); - void removeAttribute(long elementId, const String& name, bool* success); - void removeNode(long nodeId, long* outNodeId); - void changeTagName(long nodeId, const String& tagName, long* newId); - void getOuterHTML(long nodeId, WTF::String* outerHTML); - void setOuterHTML(long nodeId, const String& outerHTML, long* newId); - void setTextNodeValue(long nodeId, const String& value, bool* success); - void getEventListenersForNode(long nodeId, long* outNodeId, RefPtr<InspectorArray>* listenersArray); - void addInspectedNode(long nodeId); - void performSearch(const String& whitespaceTrimmedQuery, bool runSynchronously); - void searchCanceled(); - bool shouldBreakOnNodeInsertion(Node* node, Node* parent, PassRefPtr<InspectorObject> details); - bool shouldBreakOnNodeRemoval(Node* node, PassRefPtr<InspectorObject> details); - bool shouldBreakOnAttributeModification(Element* element, PassRefPtr<InspectorObject> details); - - // Methods called from the InspectorInstrumentation. - void setDocument(Document* document); - void releaseDanglingNodes(); - - void didInsertDOMNode(Node*); - void didRemoveDOMNode(Node*); - void didModifyDOMAttr(Element*); - void characterDataModified(CharacterData*); - - Node* nodeForId(long nodeId); - long pushNodePathToFrontend(Node* node); - void pushChildNodesToFrontend(long nodeId); - void pushNodeByPathToFrontend(const String& path, long* nodeId); - long inspectedNode(unsigned long num); - void copyNode(long nodeId); - const ListHashSet<RefPtr<Document> >& documents() { return m_documents; } - void setDOMListener(DOMListener*); - - String documentURLString(Document* document) const; - - // We represent embedded doms as a part of the same hierarchy. Hence we treat children of frame owners differently. - // We also skip whitespace text nodes conditionally. Following methods encapsulate these specifics. - static Node* innerFirstChild(Node*); - static Node* innerNextSibling(Node*); - static Node* innerPreviousSibling(Node*); - static unsigned innerChildNodeCount(Node*); - static Node* innerParentNode(Node*); - static bool isWhitespace(Node*); - - private: - void startListeningFrameDocument(Node* frameOwnerNode); - void startListening(Document* document); - void stopListening(Document* document); - - virtual void handleEvent(ScriptExecutionContext*, Event* event); - - // Node-related methods. - typedef HashMap<RefPtr<Node>, long> NodeToIdMap; - long bind(Node* node, NodeToIdMap* nodesMap); - void unbind(Node* node, NodeToIdMap* nodesMap); - - bool pushDocumentToFrontend(); - - bool hasBreakpoint(Node* node, long type); - void updateSubtreeBreakpoints(Node* root, uint32_t rootMask, bool value); - void descriptionForDOMEvent(Node* target, long breakpointType, bool insertion, PassRefPtr<InspectorObject> description); - - PassRefPtr<InspectorObject> buildObjectForNode(Node* node, int depth, NodeToIdMap* nodesMap); - PassRefPtr<InspectorArray> buildArrayForElementAttributes(Element* element); - PassRefPtr<InspectorArray> buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap); - PassRefPtr<InspectorObject> buildObjectForEventListener(const RegisteredEventListener& registeredEventListener, const AtomicString& eventType, Node* node); - - Document* mainFrameDocument() const; - - void onMatchJobsTimer(Timer<InspectorDOMAgent>*); - void reportNodesAsSearchResults(ListHashSet<Node*>& resultCollector); - - Node* nodeForPath(const String& path); - PassRefPtr<InspectorArray> toArray(const Vector<String>& data); - - void discardBindings(); - - InspectorFrontend* m_frontend; - DOMListener* m_domListener; - NodeToIdMap m_documentNodeToIdMap; - // Owns node mappings for dangling nodes. - Vector<NodeToIdMap*> m_danglingNodeToIdMaps; - HashMap<long, Node*> m_idToNode; - HashMap<long, NodeToIdMap*> m_idToNodesMap; - HashSet<long> m_childrenRequested; - long m_lastNodeId; - ListHashSet<RefPtr<Document> > m_documents; - Deque<MatchJob*> m_pendingMatchJobs; - Timer<InspectorDOMAgent> m_matchJobsTimer; - HashSet<RefPtr<Node> > m_searchResults; - Vector<long> m_inspectedNodes; + virtual void didRemoveDocument(Document*) = 0; + virtual void didRemoveDOMNode(Node*) = 0; + virtual void didModifyDOMAttr(Element*) = 0; }; -#endif + static PassRefPtr<InspectorDOMAgent> create(InjectedScriptHost* injectedScriptHost, InspectorFrontend* frontend) + { + return adoptRef(new InspectorDOMAgent(injectedScriptHost, frontend)); + } + + static const InspectorDOMAgent* cast(const EventListener* listener) + { + return listener->type() == InspectorDOMAgentType + ? static_cast<const InspectorDOMAgent*>(listener) + : 0; + } + + InspectorDOMAgent(InjectedScriptHost*, InspectorFrontend*); + ~InspectorDOMAgent(); + + void reset(); + + virtual bool operator==(const EventListener& other); + + // Methods called from the frontend for DOM nodes inspection. + void getChildNodes(long nodeId); + void setAttribute(long elementId, const String& name, const String& value, bool* success); + void removeAttribute(long elementId, const String& name, bool* success); + void removeNode(long nodeId, long* outNodeId); + void changeTagName(long nodeId, const String& tagName, long* newId); + void getOuterHTML(long nodeId, WTF::String* outerHTML); + void setOuterHTML(long nodeId, const String& outerHTML, long* newId); + void setTextNodeValue(long nodeId, const String& value, bool* success); + void getEventListenersForNode(long nodeId, long* outNodeId, RefPtr<InspectorArray>* listenersArray); + void addInspectedNode(long nodeId); + void performSearch(const String& whitespaceTrimmedQuery, bool runSynchronously); + void searchCanceled(); + void resolveNode(long nodeId, RefPtr<InspectorValue>* result); + void getNodeProperties(long nodeId, PassRefPtr<InspectorArray> propertiesArray, RefPtr<InspectorValue>* result); + void getNodePrototypes(long nodeId, RefPtr<InspectorValue>* result); + void pushNodeToFrontend(PassRefPtr<InspectorObject> objectId, RefPtr<InspectorValue>* result); + + // Methods called from the InspectorInstrumentation. + void setDocument(Document*); + void releaseDanglingNodes(); + + void didInsertDOMNode(Node*); + void didRemoveDOMNode(Node*); + void didModifyDOMAttr(Element*); + void characterDataModified(CharacterData*); + + Node* nodeForId(long nodeId); + long pushNodePathToFrontend(Node*); + void pushChildNodesToFrontend(long nodeId); + void pushNodeByPathToFrontend(const String& path, long* nodeId); + long inspectedNode(unsigned long num); + void copyNode(long nodeId); + const ListHashSet<RefPtr<Document> >& documents() { return m_documents; } + void setDOMListener(DOMListener*); + + String documentURLString(Document*) const; + + // We represent embedded doms as a part of the same hierarchy. Hence we treat children of frame owners differently. + // We also skip whitespace text nodes conditionally. Following methods encapsulate these specifics. + static Node* innerFirstChild(Node*); + static Node* innerNextSibling(Node*); + static Node* innerPreviousSibling(Node*); + static unsigned innerChildNodeCount(Node*); + static Node* innerParentNode(Node*); + static bool isWhitespace(Node*); + +private: + void startListeningFrameDocument(Node* frameOwnerNode); + void startListening(Document*); + void stopListening(Document*); + + virtual void handleEvent(ScriptExecutionContext*, Event*); + + // Node-related methods. + typedef HashMap<RefPtr<Node>, long> NodeToIdMap; + long bind(Node*, NodeToIdMap*); + void unbind(Node*, NodeToIdMap*); + + bool pushDocumentToFrontend(); + + bool hasBreakpoint(Node*, long type); + void updateSubtreeBreakpoints(Node* root, uint32_t rootMask, bool value); + void descriptionForDOMEvent(Node* target, long breakpointType, bool insertion, PassRefPtr<InspectorObject> description); + + PassRefPtr<InspectorObject> buildObjectForNode(Node*, int depth, NodeToIdMap*); + PassRefPtr<InspectorArray> buildArrayForElementAttributes(Element*); + PassRefPtr<InspectorArray> buildArrayForContainerChildren(Node* container, int depth, NodeToIdMap* nodesMap); + PassRefPtr<InspectorObject> buildObjectForEventListener(const RegisteredEventListener&, const AtomicString& eventType, Node*); + + Document* mainFrameDocument() const; + + void onMatchJobsTimer(Timer<InspectorDOMAgent>*); + void reportNodesAsSearchResults(ListHashSet<Node*>& resultCollector); + + Node* nodeForPath(const String& path); + PassRefPtr<InspectorArray> toArray(const Vector<String>& data); + + void discardBindings(); + + InjectedScript injectedScriptForNodeId(long nodeId); + + InjectedScriptHost* m_injectedScriptHost; + InspectorFrontend* m_frontend; + DOMListener* m_domListener; + NodeToIdMap m_documentNodeToIdMap; + // Owns node mappings for dangling nodes. + Vector<NodeToIdMap*> m_danglingNodeToIdMaps; + HashMap<long, Node*> m_idToNode; + HashMap<long, NodeToIdMap*> m_idToNodesMap; + HashSet<long> m_childrenRequested; + long m_lastNodeId; + ListHashSet<RefPtr<Document> > m_documents; + Deque<MatchJob*> m_pendingMatchJobs; + Timer<InspectorDOMAgent> m_matchJobsTimer; + HashSet<RefPtr<Node> > m_searchResults; + Vector<long> m_inspectedNodes; +}; + +#endif // ENABLE(INSPECTOR) } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorDebuggerAgent.cpp b/Source/WebCore/inspector/InspectorDebuggerAgent.cpp index 82c250a..acfbb6e 100644 --- a/Source/WebCore/inspector/InspectorDebuggerAgent.cpp +++ b/Source/WebCore/inspector/InspectorDebuggerAgent.cpp @@ -173,9 +173,18 @@ void InspectorDebuggerAgent::setPauseOnExceptionsState(long pauseState, long* ne *newState = ScriptDebugServer::shared().pauseOnExceptionsState(); } -long InspectorDebuggerAgent::pauseOnExceptionsState() +void InspectorDebuggerAgent::evaluateOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, const String& objectGroup, RefPtr<InspectorValue>* result) { - return ScriptDebugServer::shared().pauseOnExceptionsState(); + InjectedScript injectedScript = m_inspectorController->injectedScriptHost()->injectedScriptForObjectId(callFrameId.get()); + if (!injectedScript.hasNoValue()) + injectedScript.evaluateOnCallFrame(callFrameId, expression, objectGroup, result); +} + +void InspectorDebuggerAgent::getCompletionsOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, bool includeInspectorCommandLineAPI, RefPtr<InspectorValue>* result) +{ + InjectedScript injectedScript = m_inspectorController->injectedScriptHost()->injectedScriptForObjectId(callFrameId.get()); + if (!injectedScript.hasNoValue()) + injectedScript.getCompletionsOnCallFrame(callFrameId, expression, includeInspectorCommandLineAPI, result); } void InspectorDebuggerAgent::clearForPageNavigation() @@ -202,7 +211,7 @@ PassRefPtr<InspectorValue> InspectorDebuggerAgent::currentCallFrames() void InspectorDebuggerAgent::didParseSource(const String& sourceID, const String& url, const String& data, int lineOffset, int columnOffset, ScriptWorldType worldType) { // Don't send script content to the front end until it's really needed. - m_frontend->parsedScriptSource(sourceID, url, lineOffset, columnOffset, worldType); + m_frontend->parsedScriptSource(sourceID, url, lineOffset, columnOffset, data.length(), worldType); m_scriptIDToContent.set(sourceID, data); diff --git a/Source/WebCore/inspector/InspectorDebuggerAgent.h b/Source/WebCore/inspector/InspectorDebuggerAgent.h index 07d2ab9..4cb9f9c 100644 --- a/Source/WebCore/inspector/InspectorDebuggerAgent.h +++ b/Source/WebCore/inspector/InspectorDebuggerAgent.h @@ -31,6 +31,7 @@ #define InspectorDebuggerAgent_h #if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) +#include "InjectedScript.h" #include "ScriptDebugListener.h" #include "ScriptState.h" #include <wtf/Forward.h> @@ -52,22 +53,22 @@ enum DebuggerEventType { NativeBreakpointDebuggerEventType }; -class InspectorDebuggerAgent : public ScriptDebugListener, public Noncopyable { +class InspectorDebuggerAgent : public ScriptDebugListener { + WTF_MAKE_NONCOPYABLE(InspectorDebuggerAgent); WTF_MAKE_FAST_ALLOCATED; public: static PassOwnPtr<InspectorDebuggerAgent> create(InspectorController*, InspectorFrontend*); virtual ~InspectorDebuggerAgent(); static bool isDebuggerAlwaysEnabled(); + // Part of the protocol. void activateBreakpoints(); void deactivateBreakpoints(); void setStickyBreakpoint(const String& url, unsigned lineNumber, const String& condition, bool enabled); void setBreakpoint(const String& sourceID, unsigned lineNumber, const String& condition, bool enabled, String* breakpointId, unsigned int* actualLineNumber); void removeBreakpoint(const String& breakpointId); - void editScriptSource(const String& sourceID, const String& newContent, bool* success, String* result, RefPtr<InspectorValue>* newCallFrames); void getScriptSource(const String& sourceID, String* scriptSource); - void schedulePauseOnNextStatement(DebuggerEventType type, PassRefPtr<InspectorValue> data); void cancelPauseOnNextStatement(); void breakProgram(DebuggerEventType type, PassRefPtr<InspectorValue> data); @@ -76,9 +77,9 @@ public: void stepOver(); void stepInto(); void stepOut(); - void setPauseOnExceptionsState(long pauseState, long* newState); - long pauseOnExceptionsState(); + void evaluateOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, const String& objectGroup, RefPtr<InspectorValue>* result); + void getCompletionsOnCallFrame(PassRefPtr<InspectorObject> callFrameId, const String& expression, bool includeInspectorCommandLineAPI, RefPtr<InspectorValue>* result); void clearForPageNavigation(); diff --git a/Source/WebCore/inspector/InspectorFrontendClientLocal.h b/Source/WebCore/inspector/InspectorFrontendClientLocal.h index 9dcaa5a..19f6ad1 100644 --- a/Source/WebCore/inspector/InspectorFrontendClientLocal.h +++ b/Source/WebCore/inspector/InspectorFrontendClientLocal.h @@ -41,7 +41,8 @@ class InspectorController; class InspectorFrontendHost; class Page; -class InspectorFrontendClientLocal : public InspectorFrontendClient, public Noncopyable { +class InspectorFrontendClientLocal : public InspectorFrontendClient { + WTF_MAKE_NONCOPYABLE(InspectorFrontendClientLocal); WTF_MAKE_FAST_ALLOCATED; public: InspectorFrontendClientLocal(InspectorController*, Page*); virtual ~InspectorFrontendClientLocal(); diff --git a/Source/WebCore/inspector/InspectorInstrumentation.cpp b/Source/WebCore/inspector/InspectorInstrumentation.cpp index aa941df..9ae97be 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.cpp +++ b/Source/WebCore/inspector/InspectorInstrumentation.cpp @@ -93,17 +93,17 @@ void InspectorInstrumentation::inspectedPageDestroyedImpl(InspectorController* i void InspectorInstrumentation::willInsertDOMNodeImpl(InspectorController* inspectorController, Node* node, Node* parent) { #if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorController->m_browserDebuggerAgent.get()) + if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorController->browserDebuggerAgent()) browserDebuggerAgent->willInsertDOMNode(node, parent); #endif } void InspectorInstrumentation::didInsertDOMNodeImpl(InspectorController* inspectorController, Node* node) { - if (InspectorDOMAgent* domAgent = inspectorController->m_domAgent.get()) + if (InspectorDOMAgent* domAgent = inspectorController->domAgent()) domAgent->didInsertDOMNode(node); #if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorController->m_browserDebuggerAgent.get()) + if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorController->browserDebuggerAgent()) browserDebuggerAgent->didInsertDOMNode(node); #endif } @@ -111,7 +111,7 @@ void InspectorInstrumentation::didInsertDOMNodeImpl(InspectorController* inspect void InspectorInstrumentation::willRemoveDOMNodeImpl(InspectorController* inspectorController, Node* node) { #if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorController->m_browserDebuggerAgent.get()) + if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorController->browserDebuggerAgent()) browserDebuggerAgent->willRemoveDOMNode(node); #endif } @@ -119,24 +119,24 @@ void InspectorInstrumentation::willRemoveDOMNodeImpl(InspectorController* inspec void InspectorInstrumentation::didRemoveDOMNodeImpl(InspectorController* inspectorController, Node* node) { #if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorController->m_browserDebuggerAgent.get()) + if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorController->browserDebuggerAgent()) browserDebuggerAgent->didRemoveDOMNode(node); #endif - if (InspectorDOMAgent* domAgent = inspectorController->m_domAgent.get()) + if (InspectorDOMAgent* domAgent = inspectorController->domAgent()) domAgent->didRemoveDOMNode(node); } void InspectorInstrumentation::willModifyDOMAttrImpl(InspectorController* inspectorController, Element* element) { #if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorController->m_browserDebuggerAgent.get()) + if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorController->browserDebuggerAgent()) browserDebuggerAgent->willModifyDOMAttr(element); #endif } void InspectorInstrumentation::didModifyDOMAttrImpl(InspectorController* inspectorController, Element* element) { - if (InspectorDOMAgent* domAgent = inspectorController->m_domAgent.get()) + if (InspectorDOMAgent* domAgent = inspectorController->domAgent()) domAgent->didModifyDOMAttr(element); } @@ -152,14 +152,14 @@ bool InspectorInstrumentation::handleMousePressImpl(InspectorController* inspect void InspectorInstrumentation::characterDataModifiedImpl(InspectorController* inspectorController, CharacterData* characterData) { - if (InspectorDOMAgent* domAgent = inspectorController->m_domAgent.get()) + if (InspectorDOMAgent* domAgent = inspectorController->domAgent()) domAgent->characterDataModified(characterData); } void InspectorInstrumentation::willSendXMLHttpRequestImpl(InspectorController* inspectorController, const String& url) { #if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorController->m_browserDebuggerAgent.get()) + if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorController->browserDebuggerAgent()) browserDebuggerAgent->willSendXMLHttpRequest(url); #endif } @@ -433,7 +433,7 @@ void InspectorInstrumentation::didReceiveResourceResponseImpl(const InspectorIns InspectorController* ic = cookie.first; if (InspectorResourceAgent* resourceAgent = retrieveResourceAgent(ic)) resourceAgent->didReceiveResponse(identifier, loader, response); - ic->m_consoleAgent->didReceiveResponse(identifier, response); + ic->consoleAgent()->didReceiveResponse(identifier, response); if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(cookie)) timelineAgent->didReceiveResourceResponse(); } @@ -454,7 +454,7 @@ void InspectorInstrumentation::didFinishLoadingImpl(InspectorController* ic, uns void InspectorInstrumentation::didFailLoadingImpl(InspectorController* ic, unsigned long identifier, const ResourceError& error) { - ic->m_consoleAgent->didFailLoading(identifier, error); + ic->consoleAgent()->didFailLoading(identifier, error); if (InspectorTimelineAgent* timelineAgent = retrieveTimelineAgent(ic)) timelineAgent->didFinishLoadingResource(identifier, true, 0); if (InspectorResourceAgent* resourceAgent = retrieveResourceAgent(ic)) @@ -463,7 +463,7 @@ void InspectorInstrumentation::didFailLoadingImpl(InspectorController* ic, unsig void InspectorInstrumentation::resourceRetrievedByXMLHttpRequestImpl(InspectorController* ic, unsigned long identifier, const String& sourceString, const String& url, const String& sendURL, unsigned sendLineNumber) { - ic->m_consoleAgent->resourceRetrievedByXMLHttpRequest(url, sendURL, sendLineNumber); + ic->consoleAgent()->resourceRetrievedByXMLHttpRequest(url, sendURL, sendLineNumber); if (InspectorResourceAgent* resourceAgent = retrieveResourceAgent(ic)) resourceAgent->setInitialContent(identifier, sourceString, "XHR"); } @@ -549,9 +549,36 @@ void InspectorInstrumentation::consoleMarkTimelineImpl(InspectorController* insp #if ENABLE(JAVASCRIPT_DEBUGGER) void InspectorInstrumentation::addStartProfilingMessageToConsoleImpl(InspectorController* inspectorController, const String& title, unsigned lineNumber, const String& sourceURL) { - if (InspectorProfilerAgent* profilerAgent = inspectorController->m_profilerAgent.get()) + if (InspectorProfilerAgent* profilerAgent = inspectorController->profilerAgent()) profilerAgent->addStartProfilingMessageToConsole(title, lineNumber, sourceURL); } + +void InspectorInstrumentation::addProfileImpl(InspectorController* inspectorController, RefPtr<ScriptProfile> profile, ScriptCallStack* callStack) +{ + if (InspectorProfilerAgent* profilerAgent = inspectorController->profilerAgent()) { + const ScriptCallFrame& lastCaller = callStack->at(0); + profilerAgent->addProfile(profile, lastCaller.lineNumber(), lastCaller.sourceURL()); + } +} + +bool InspectorInstrumentation::profilerEnabledImpl(InspectorController* inspectorController) +{ + if (!inspectorController->enabled()) + return false; + + InspectorProfilerAgent* profilerAgent = inspectorController->profilerAgent(); + if (!profilerAgent) + return false; + + return profilerAgent->enabled(); +} + +String InspectorInstrumentation::getCurrentUserInitiatedProfileNameImpl(InspectorController* inspectorController, bool incrementProfileNumber) +{ + if (InspectorProfilerAgent* profilerAgent = inspectorController->profilerAgent()) + return profilerAgent->getCurrentUserInitiatedProfileName(incrementProfileNumber); + return ""; +} #endif #if ENABLE(DATABASE) @@ -624,7 +651,7 @@ bool InspectorInstrumentation::hasFrontend(InspectorController* inspectorControl void InspectorInstrumentation::pauseOnNativeEventIfNeeded(InspectorController* inspectorController, const String& categoryType, const String& eventName, bool synchronous) { #if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorController->m_browserDebuggerAgent.get()) + if (InspectorBrowserDebuggerAgent* browserDebuggerAgent = inspectorController->browserDebuggerAgent()) browserDebuggerAgent->pauseOnNativeEventIfNeeded(categoryType, eventName, synchronous); #endif } @@ -632,14 +659,14 @@ void InspectorInstrumentation::pauseOnNativeEventIfNeeded(InspectorController* i void InspectorInstrumentation::cancelPauseOnNativeEvent(InspectorController* inspectorController) { #if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorDebuggerAgent* debuggerAgent = inspectorController->m_debuggerAgent.get()) + if (InspectorDebuggerAgent* debuggerAgent = inspectorController->debuggerAgent()) debuggerAgent->cancelPauseOnNextStatement(); #endif } InspectorTimelineAgent* InspectorInstrumentation::retrieveTimelineAgent(InspectorController* inspectorController) { - return inspectorController->m_timelineAgent.get(); + return inspectorController->timelineAgent(); } InspectorTimelineAgent* InspectorInstrumentation::retrieveTimelineAgent(const InspectorInstrumentationCookie& cookie) @@ -652,7 +679,7 @@ InspectorTimelineAgent* InspectorInstrumentation::retrieveTimelineAgent(const In InspectorResourceAgent* InspectorInstrumentation::retrieveResourceAgent(InspectorController* ic) { - return ic->m_resourceAgent.get(); + return ic->resourceAgent(); } } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorInstrumentation.h b/Source/WebCore/inspector/InspectorInstrumentation.h index 28867cb..7a7ee43 100644 --- a/Source/WebCore/inspector/InspectorInstrumentation.h +++ b/Source/WebCore/inspector/InspectorInstrumentation.h @@ -139,6 +139,9 @@ public: #if ENABLE(JAVASCRIPT_DEBUGGER) static void addStartProfilingMessageToConsole(Page*, const String& title, unsigned lineNumber, const String& sourceURL); + static void addProfile(Page*, RefPtr<ScriptProfile>, ScriptCallStack*); + static bool profilerEnabled(Page*); + static String getCurrentUserInitiatedProfileName(Page*, bool incrementProfileNumber); #endif #if ENABLE(DATABASE) @@ -246,6 +249,9 @@ private: #if ENABLE(JAVASCRIPT_DEBUGGER) static void addStartProfilingMessageToConsoleImpl(InspectorController*, const String& title, unsigned lineNumber, const String& sourceURL); + static void addProfileImpl(InspectorController*, RefPtr<ScriptProfile>, ScriptCallStack*); + static bool profilerEnabledImpl(InspectorController*); + static String getCurrentUserInitiatedProfileNameImpl(InspectorController*, bool incrementProfileNumber); #endif #if ENABLE(DATABASE) @@ -881,6 +887,32 @@ inline void InspectorInstrumentation::addStartProfilingMessageToConsole(Page* pa addStartProfilingMessageToConsoleImpl(inspectorController, title, lineNumber, sourceURL); #endif } + +inline void InspectorInstrumentation::addProfile(Page* page, RefPtr<ScriptProfile> profile, ScriptCallStack* callStack) +{ +#if ENABLE(INSPECTOR) + if (InspectorController* inspectorController = inspectorControllerForPage(page)) + addProfileImpl(inspectorController, profile, callStack); +#endif +} + +inline bool InspectorInstrumentation::profilerEnabled(Page* page) +{ +#if ENABLE(INSPECTOR) + if (InspectorController* inspectorController = inspectorControllerForPage(page)) + return profilerEnabledImpl(inspectorController); +#endif + return false; +} + +inline String InspectorInstrumentation::getCurrentUserInitiatedProfileName(Page* page, bool incrementProfileNumber) +{ +#if ENABLE(INSPECTOR) + if (InspectorController* inspectorController = inspectorControllerForPage(page)) + return InspectorInstrumentation::getCurrentUserInitiatedProfileNameImpl(inspectorController, incrementProfileNumber); +#endif + return ""; +} #endif #if ENABLE(INSPECTOR) @@ -936,6 +968,7 @@ inline InspectorController* InspectorInstrumentation::inspectorControllerWithFro } return 0; } + #endif } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorProfilerAgent.cpp b/Source/WebCore/inspector/InspectorProfilerAgent.cpp index da9b67d..8c4f28f 100644 --- a/Source/WebCore/inspector/InspectorProfilerAgent.cpp +++ b/Source/WebCore/inspector/InspectorProfilerAgent.cpp @@ -88,6 +88,8 @@ void InspectorProfilerAgent::addProfile(PassRefPtr<ScriptProfile> prpProfile, un void InspectorProfilerAgent::addProfileFinishedMessageToConsole(PassRefPtr<ScriptProfile> prpProfile, unsigned lineNumber, const String& sourceURL) { + if (!m_frontend) + return; RefPtr<ScriptProfile> profile = prpProfile; String title = profile->title(); String message = makeString("Profile \"webkit-profile://", CPUProfileType, '/', encodeWithURLEscapeSequences(title), '#', String::number(profile->uid()), "\" finished."); @@ -96,6 +98,8 @@ void InspectorProfilerAgent::addProfileFinishedMessageToConsole(PassRefPtr<Scrip void InspectorProfilerAgent::addStartProfilingMessageToConsole(const String& title, unsigned lineNumber, const String& sourceURL) { + if (!m_frontend) + return; String message = makeString("Profile \"webkit-profile://", CPUProfileType, '/', encodeWithURLEscapeSequences(title), "#0\" started."); m_inspectorController->consoleAgent()->addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, message, lineNumber, sourceURL); } @@ -211,7 +215,12 @@ void InspectorProfilerAgent::resetState() m_currentUserInitiatedProfileNumber = 1; m_nextUserInitiatedProfileNumber = 1; m_nextUserInitiatedHeapSnapshotNumber = 1; - if (m_frontend) + resetFrontendProfiles(); +} + +void InspectorProfilerAgent::resetFrontendProfiles() +{ + if (m_frontend && m_profiles.begin() == m_profiles.end()) m_frontend->resetProfiles(); } diff --git a/Source/WebCore/inspector/InspectorProfilerAgent.h b/Source/WebCore/inspector/InspectorProfilerAgent.h index e67848d..436ae51 100644 --- a/Source/WebCore/inspector/InspectorProfilerAgent.h +++ b/Source/WebCore/inspector/InspectorProfilerAgent.h @@ -47,7 +47,8 @@ class InspectorObject; class ScriptHeapSnapshot; class ScriptProfile; -class InspectorProfilerAgent : public Noncopyable { +class InspectorProfilerAgent { + WTF_MAKE_NONCOPYABLE(InspectorProfilerAgent); WTF_MAKE_FAST_ALLOCATED; public: static PassOwnPtr<InspectorProfilerAgent> create(InspectorController*); virtual ~InspectorProfilerAgent(); @@ -65,6 +66,7 @@ public: bool isRecordingUserInitiatedProfile() { return m_recordingUserInitiatedProfile; } void removeProfile(const String& type, unsigned uid); void resetState(); + void resetFrontendProfiles(); void setFrontend(InspectorFrontend* frontend) { m_frontend = frontend; } void startUserInitiatedProfiling(); void stopUserInitiatedProfiling(bool ignoreProfile = false); diff --git a/Source/WebCore/inspector/InspectorResourceAgent.cpp b/Source/WebCore/inspector/InspectorResourceAgent.cpp index 6779790..029c79d 100644 --- a/Source/WebCore/inspector/InspectorResourceAgent.cpp +++ b/Source/WebCore/inspector/InspectorResourceAgent.cpp @@ -45,6 +45,7 @@ #include "HTMLNames.h" #include "HTTPHeaderMap.h" #include "InspectorFrontend.h" +#include "InspectorState.h" #include "InspectorValues.h" #include "KURL.h" #include "Page.h" @@ -66,6 +67,13 @@ namespace WebCore { +PassRefPtr<InspectorResourceAgent> InspectorResourceAgent::restore(Page* page, InspectorState* state, InspectorFrontend* frontend) +{ + if (state->getBoolean(InspectorState::resourceAgentEnabled)) + return create(page, state, frontend); + return 0; +} + bool InspectorResourceAgent::resourceContent(Frame* frame, const KURL& url, String* result) { if (!frame) @@ -281,6 +289,7 @@ static void populateObjectWithFrameResources(Frame* frame, PassRefPtr<InspectorO InspectorResourceAgent::~InspectorResourceAgent() { + m_state->setBoolean(InspectorState::resourceAgentEnabled, false); } void InspectorResourceAgent::identifierForInitialRequest(unsigned long identifier, const KURL& url, DocumentLoader* loader) @@ -476,10 +485,12 @@ void InspectorResourceAgent::resourceContent(unsigned long id, const String& url } } -InspectorResourceAgent::InspectorResourceAgent(Page* page, InspectorFrontend* frontend) +InspectorResourceAgent::InspectorResourceAgent(Page* page, InspectorState* state, InspectorFrontend* frontend) : m_page(page) + , m_state(state) , m_frontend(frontend) { + m_state->setBoolean(InspectorState::resourceAgentEnabled, true); } } // namespace WebCore diff --git a/Source/WebCore/inspector/InspectorResourceAgent.h b/Source/WebCore/inspector/InspectorResourceAgent.h index 1e77d58..6c2df24 100644 --- a/Source/WebCore/inspector/InspectorResourceAgent.h +++ b/Source/WebCore/inspector/InspectorResourceAgent.h @@ -49,8 +49,9 @@ class Document; class DocumentLoader; class Frame; class InspectorArray; -class InspectorObject; class InspectorFrontend; +class InspectorObject; +class InspectorState; class KURL; class Page; class ResourceError; @@ -65,11 +66,13 @@ class WebSocketHandshakeResponse; class InspectorResourceAgent : public RefCounted<InspectorResourceAgent> { public: - static PassRefPtr<InspectorResourceAgent> create(Page* page, InspectorFrontend* frontend) + static PassRefPtr<InspectorResourceAgent> create(Page* page, InspectorState* state, InspectorFrontend* frontend) { - return adoptRef(new InspectorResourceAgent(page, frontend)); + return adoptRef(new InspectorResourceAgent(page, state, frontend)); } + static PassRefPtr<InspectorResourceAgent> restore(Page*, InspectorState*, InspectorFrontend*); + static bool resourceContent(Frame*, const KURL&, String* result); static bool resourceContentBase64(Frame*, const KURL&, String* result); static PassRefPtr<SharedBuffer> resourceData(Frame*, const KURL&, String* textEncodingName); @@ -103,9 +106,10 @@ public: void resourceContent(unsigned long frameID, const String& url, bool base64Encode, String* content); private: - InspectorResourceAgent(Page* page, InspectorFrontend* frontend); + InspectorResourceAgent(Page* page, InspectorState*, InspectorFrontend* frontend); Page* m_page; + InspectorState* m_state; InspectorFrontend* m_frontend; }; diff --git a/Source/WebCore/inspector/InspectorRuntimeAgent.cpp b/Source/WebCore/inspector/InspectorRuntimeAgent.cpp new file mode 100644 index 0000000..0502437 --- /dev/null +++ b/Source/WebCore/inspector/InspectorRuntimeAgent.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2011 Google Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following disclaimer + * in the documentation and/or other materials provided with the + * distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived from + * this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "InspectorRuntimeAgent.h" + +#if ENABLE(INSPECTOR) + +#include "InjectedScriptHost.h" +#include "InspectorValues.h" + +namespace WebCore { + +InspectorRuntimeAgent::InspectorRuntimeAgent(InjectedScriptHost* injectedScriptHost) + : m_injectedScriptHost(injectedScriptHost) +{ +} + +InspectorRuntimeAgent::~InspectorRuntimeAgent() { } + +void InspectorRuntimeAgent::evaluate(const String& expression, const String& objectGroup, RefPtr<InspectorValue>* result) +{ + InjectedScript injectedScript = m_injectedScriptHost->injectedScriptForMainFrame(); + if (!injectedScript.hasNoValue()) + injectedScript.evaluate(expression, objectGroup, result); +} + +void InspectorRuntimeAgent::getCompletions(const String& expression, bool includeInspectorCommandLineAPI, RefPtr<InspectorValue>* result) +{ + InjectedScript injectedScript = m_injectedScriptHost->injectedScriptForMainFrame(); + if (!injectedScript.hasNoValue()) + injectedScript.getCompletions(expression, includeInspectorCommandLineAPI, result); +} + +void InspectorRuntimeAgent::getProperties(PassRefPtr<InspectorObject> objectId, bool ignoreHasOwnProperty, bool abbreviate, RefPtr<InspectorValue>* result) +{ + InjectedScript injectedScript = m_injectedScriptHost->injectedScriptForObjectId(objectId.get()); + if (!injectedScript.hasNoValue()) + injectedScript.getProperties(objectId, ignoreHasOwnProperty, abbreviate, result); +} + +void InspectorRuntimeAgent::setPropertyValue(PassRefPtr<InspectorObject> objectId, const String& propertyName, const String& expression, RefPtr<InspectorValue>* result) +{ + InjectedScript injectedScript = m_injectedScriptHost->injectedScriptForObjectId(objectId.get()); + if (!injectedScript.hasNoValue()) + injectedScript.setPropertyValue(objectId, propertyName, expression, result); +} + +void InspectorRuntimeAgent::releaseWrapperObjectGroup(long injectedScriptId, const String& objectGroup) +{ + m_injectedScriptHost->releaseWrapperObjectGroup(injectedScriptId, objectGroup); +} + +} // namespace WebCore + +#endif // ENABLE(INSPECTOR) diff --git a/Source/WebCore/inspector/InspectorRuntimeAgent.h b/Source/WebCore/inspector/InspectorRuntimeAgent.h new file mode 100644 index 0000000..3ac2eed --- /dev/null +++ b/Source/WebCore/inspector/InspectorRuntimeAgent.h @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2011 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. + */ + +#ifndef InspectorRuntimeAgent_h +#define InspectorRuntimeAgent_h + +#if ENABLE(INSPECTOR) + +#include "InjectedScript.h" +#include "PlatformString.h" + +#include <wtf/Noncopyable.h> +#include <wtf/PassOwnPtr.h> +#include <wtf/PassRefPtr.h> + +namespace WebCore { + +class InjectedScriptHost; +class InspectorObject; +class InspectorValue; + +class InspectorRuntimeAgent { + WTF_MAKE_NONCOPYABLE(InspectorRuntimeAgent); +public: + static PassOwnPtr<InspectorRuntimeAgent> create(InjectedScriptHost* injectedScriptHost) + { + return adoptPtr(new InspectorRuntimeAgent(injectedScriptHost)); + } + + ~InspectorRuntimeAgent(); + + // Part of the protocol. + void evaluate(const String& expression, const String& objectGroup, RefPtr<InspectorValue>* result); + void getCompletions(const String& expression, bool includeInspectorCommandLineAPI, RefPtr<InspectorValue>* result); + void getProperties(PassRefPtr<InspectorObject> objectId, bool ignoreHasOwnProperty, bool abbreviate, RefPtr<InspectorValue>* result); + void setPropertyValue(PassRefPtr<InspectorObject> objectId, const String& propertyName, const String& expression, RefPtr<InspectorValue>* result); + void releaseWrapperObjectGroup(long injectedScriptId, const String& objectGroup); + +private: + InspectorRuntimeAgent(InjectedScriptHost*); + + InjectedScriptHost* m_injectedScriptHost; +}; + +} // namespace WebCore + +#endif // ENABLE(INSPECTOR) +#endif // InspectorRuntimeAgent_h diff --git a/Source/WebCore/inspector/InspectorState.cpp b/Source/WebCore/inspector/InspectorState.cpp index 1b74518..dba9e4d 100644 --- a/Source/WebCore/inspector/InspectorState.cpp +++ b/Source/WebCore/inspector/InspectorState.cpp @@ -39,15 +39,13 @@ InspectorState::InspectorState(InspectorClient* client) : m_client(client) { // Pure reload state - registerBoolean(userInitiatedProfiling, false, String()); - registerBoolean(timelineProfilerEnabled, false, String()); - registerBoolean(searchingForNode, false, String()); - registerObject(stickyBreakpoints, String()); - - // Should go away - registerBoolean(consoleMessagesEnabled, false, "consoleMessagesEnabled"); - registerBoolean(monitoringXHR, false, "monitoringXHREnabled"); - registerLong(pauseOnExceptionsState, 0, "pauseOnExceptionsState"); + registerBoolean(userInitiatedProfiling, false); + registerBoolean(timelineProfilerEnabled, false); + registerBoolean(searchingForNode, false); + registerObject(browserBreakpoints); + registerBoolean(consoleMessagesEnabled, false); + registerBoolean(monitoringXHR, false); + registerBoolean(resourceAgentEnabled, false); } void InspectorState::restoreFromInspectorCookie(const String& json) @@ -70,16 +68,6 @@ void InspectorState::restoreFromInspectorCookie(const String& json) } } -PassRefPtr<InspectorObject> InspectorState::generateStateObjectForFrontend() -{ - RefPtr<InspectorObject> stateObject = InspectorObject::create(); - for (PropertyMap::iterator i = m_properties.begin(); i != m_properties.end(); ++i) { - if (i->second.m_frontendAlias.length()) - stateObject->setValue(i->second.m_frontendAlias, i->second.m_value); - } - return stateObject.release(); -} - void InspectorState::updateCookie() { RefPtr<InspectorObject> cookieObject = InspectorObject::create(); @@ -139,31 +127,30 @@ void InspectorState::setObject(InspectorPropertyId id, PassRefPtr<InspectorObjec updateCookie(); } -void InspectorState::registerBoolean(InspectorPropertyId propertyId, bool value, const String& frontendAlias) +void InspectorState::registerBoolean(InspectorPropertyId propertyId, bool value) { - m_properties.set(propertyId, Property::create(InspectorBasicValue::create(value), frontendAlias)); + m_properties.set(propertyId, Property::create(InspectorBasicValue::create(value))); } -void InspectorState::registerString(InspectorPropertyId propertyId, const String& value, const String& frontendAlias) +void InspectorState::registerString(InspectorPropertyId propertyId, const String& value) { - m_properties.set(propertyId, Property::create(InspectorString::create(value), frontendAlias)); + m_properties.set(propertyId, Property::create(InspectorString::create(value))); } -void InspectorState::registerLong(InspectorPropertyId propertyId, long value, const String& frontendAlias) +void InspectorState::registerLong(InspectorPropertyId propertyId, long value) { - m_properties.set(propertyId, Property::create(InspectorBasicValue::create((double)value), frontendAlias)); + m_properties.set(propertyId, Property::create(InspectorBasicValue::create((double)value))); } -void InspectorState::registerObject(InspectorPropertyId propertyId, const String& frontendAlias) +void InspectorState::registerObject(InspectorPropertyId propertyId) { - m_properties.set(propertyId, Property::create(InspectorObject::create(), frontendAlias)); + m_properties.set(propertyId, Property::create(InspectorObject::create())); } -InspectorState::Property InspectorState::Property::create(PassRefPtr<InspectorValue> value, const String& frontendAlias) +InspectorState::Property InspectorState::Property::create(PassRefPtr<InspectorValue> value) { Property property; property.m_value = value; - property.m_frontendAlias = frontendAlias; return property; } diff --git a/Source/WebCore/inspector/InspectorState.h b/Source/WebCore/inspector/InspectorState.h index 3142c92..6e12673 100644 --- a/Source/WebCore/inspector/InspectorState.h +++ b/Source/WebCore/inspector/InspectorState.h @@ -47,45 +47,42 @@ public: monitoringXHR = 1, timelineProfilerEnabled, searchingForNode, - pauseOnExceptionsState, consoleMessagesEnabled, userInitiatedProfiling, - stickyBreakpoints, + browserBreakpoints, + resourceAgentEnabled, lastPropertyId }; InspectorState(InspectorClient* client); - PassRefPtr<InspectorObject> generateStateObjectForFrontend(); void restoreFromInspectorCookie(const String& jsonString); - String getFrontendAlias(InspectorPropertyId propertyId); - bool getBoolean(InspectorPropertyId propertyId); - String getString(InspectorPropertyId propertyId); - long getLong(InspectorPropertyId propertyId); - PassRefPtr<InspectorObject> getObject(InspectorPropertyId id); + bool getBoolean(InspectorPropertyId); + String getString(InspectorPropertyId); + long getLong(InspectorPropertyId); + PassRefPtr<InspectorObject> getObject(InspectorPropertyId); void setBoolean(InspectorPropertyId propertyId, bool value) { setValue(propertyId, InspectorBasicValue::create(value)); } void setString(InspectorPropertyId propertyId, const String& value) { setValue(propertyId, InspectorString::create(value)); } void setLong(InspectorPropertyId propertyId, long value) { setValue(propertyId, InspectorBasicValue::create((double)value)); } - void setObject(InspectorPropertyId propertyId, PassRefPtr<InspectorObject> value); + void setObject(InspectorPropertyId, PassRefPtr<InspectorObject> value); private: void updateCookie(); - void setValue(InspectorPropertyId propertyId, PassRefPtr<InspectorValue> value); + void setValue(InspectorPropertyId, PassRefPtr<InspectorValue>); struct Property { - static Property create(PassRefPtr<InspectorValue> value, const String& frontendAlias); - String m_frontendAlias; + static Property create(PassRefPtr<InspectorValue> value); RefPtr<InspectorValue> m_value; }; typedef HashMap<long, Property> PropertyMap; PropertyMap m_properties; - void registerBoolean(InspectorPropertyId propertyId, bool value, const String& frontendAlias); - void registerString(InspectorPropertyId propertyId, const String& value, const String& frontendAlias); - void registerLong(InspectorPropertyId propertyId, long value, const String& frontendAlias); - void registerObject(InspectorPropertyId propertyId, const String& frontendAlias); + void registerBoolean(InspectorPropertyId, bool value); + void registerString(InspectorPropertyId, const String& value); + void registerLong(InspectorPropertyId, long value); + void registerObject(InspectorPropertyId); InspectorClient* m_client; }; diff --git a/Source/WebCore/inspector/InspectorTimelineAgent.h b/Source/WebCore/inspector/InspectorTimelineAgent.h index 33e2737..cae5aad 100644 --- a/Source/WebCore/inspector/InspectorTimelineAgent.h +++ b/Source/WebCore/inspector/InspectorTimelineAgent.h @@ -70,7 +70,8 @@ enum TimelineRecordType { ScheduleResourceRequestTimelineRecordType = 20 }; -class InspectorTimelineAgent : ScriptGCEventListener, public Noncopyable { +class InspectorTimelineAgent : ScriptGCEventListener { + WTF_MAKE_NONCOPYABLE(InspectorTimelineAgent); WTF_MAKE_FAST_ALLOCATED; public: InspectorTimelineAgent(InspectorFrontend* frontend); ~InspectorTimelineAgent(); diff --git a/Source/WebCore/inspector/InspectorValues.cpp b/Source/WebCore/inspector/InspectorValues.cpp index 89e9b7c..d1b8093 100644 --- a/Source/WebCore/inspector/InspectorValues.cpp +++ b/Source/WebCore/inspector/InspectorValues.cpp @@ -647,6 +647,14 @@ bool InspectorObject::getBoolean(const String& name, bool* output) const return value->asBoolean(output); } +bool InspectorObject::getNumber(const String& name, long* output) const +{ + RefPtr<InspectorValue> value = get(name); + if (!value) + return false; + return value->asNumber(output); +} + bool InspectorObject::getNumber(const String& name, double* output) const { RefPtr<InspectorValue> value = get(name); diff --git a/Source/WebCore/inspector/InspectorValues.h b/Source/WebCore/inspector/InspectorValues.h index 391372e..843f369 100644 --- a/Source/WebCore/inspector/InspectorValues.h +++ b/Source/WebCore/inspector/InspectorValues.h @@ -180,6 +180,7 @@ public: const_iterator find(const String& name) const; bool getBoolean(const String& name, bool* output) const; + bool getNumber(const String& name, long* output) const; bool getNumber(const String& name, double* output) const; bool getString(const String& name, String* output) const; PassRefPtr<InspectorObject> getObject(const String& name) const; diff --git a/Source/WebCore/inspector/JavaScriptCallFrame.idl b/Source/WebCore/inspector/JavaScriptCallFrame.idl index 225059d..db0e0a6 100644 --- a/Source/WebCore/inspector/JavaScriptCallFrame.idl +++ b/Source/WebCore/inspector/JavaScriptCallFrame.idl @@ -43,6 +43,7 @@ module inspector { readonly attribute JavaScriptCallFrame caller; readonly attribute long sourceID; readonly attribute long line; + readonly attribute long column; readonly attribute [CustomGetter] Array scopeChain; [Custom] unsigned short scopeType(in int scopeIndex); readonly attribute [CustomGetter] Object thisObject; diff --git a/Source/WebCore/inspector/front-end/AuditLauncherView.js b/Source/WebCore/inspector/front-end/AuditLauncherView.js index c140589..df16a41 100644 --- a/Source/WebCore/inspector/front-end/AuditLauncherView.js +++ b/Source/WebCore/inspector/front-end/AuditLauncherView.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2009 Google Inc. All rights reserved. + * Copyright (C) 2011 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 @@ -50,60 +50,38 @@ WebInspector.AuditLauncherView = function(runnerCallback) this._headerElement.className = "no-audits"; this._headerElement.textContent = WebInspector.UIString("No audits to run"); this._contentElement.appendChild(this._headerElement); + + WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceStarted, this._onResourceStarted, this); + WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceFinished, this._onResourceFinished, this); } WebInspector.AuditLauncherView.prototype = { - get totalResources() + _resetResourceCount: function() { - return this._totalResources; + this._loadedResources = 0; + this._totalResources = 0; }, - set totalResources(x) + _onResourceStarted: function(event) { - if (this._totalResources === x) + var resource = event.data; + // Ignore long-living WebSockets for the sake of progress indicator, as we won't be waiting them anyway. + if (resource.type === WebInspector.Resource.Type.WebSocket) return; - this._totalResources = x; + ++this._totalResources; this._updateResourceProgress(); }, - get loadedResources() - { - return this._loadedResources; - }, - - set loadedResources(x) + _onResourceFinished: function(event) { - if (this._loadedResources === x) + var resource = event.data; + // See resorceStarted for details. + if (resource.type === WebInspector.Resource.Type.WebSocket) return; - this._loadedResources = x; + ++this._loadedResources; this._updateResourceProgress(); }, - _resetResourceCount: function() - { - this.loadedResources = 0; - this.totalResources = 0; - }, - - resourceStarted: function(resource) - { - // Ignore long-living WebSockets for the sake of progress indicator, as we won't be waiting them anyway. - if (resource.type !== WebInspector.Resource.Type.WebSocket) - ++this.totalResources; - }, - - resourceFinished: function(resource) - { - // See resorceStarted for details. - if (resource.type !== WebInspector.Resource.Type.WebSocket) - ++this.loadedResources; - }, - - reset: function() - { - this._resetResourceCount(); - }, - addCategory: function(category) { if (!this._sortedCategories.length) @@ -264,7 +242,7 @@ WebInspector.AuditLauncherView.prototype = { this._resourceProgressContainer.addStyleClass("hidden"); } else this._resourceProgressContainer.removeStyleClass("hidden"); - this._resourceProgressTextElement.textContent = WebInspector.UIString("Loading (%d of %d)", this.loadedResources, this.totalResources); + this._resourceProgressTextElement.textContent = WebInspector.UIString("Loading (%d of %d)", this._loadedResources, this._totalResources); }, _updateButton: function() diff --git a/Source/WebCore/inspector/front-end/AuditRules.js b/Source/WebCore/inspector/front-end/AuditRules.js index 7aa891f..c2bbcbb 100644 --- a/Source/WebCore/inspector/front-end/AuditRules.js +++ b/Source/WebCore/inspector/front-end/AuditRules.js @@ -65,7 +65,7 @@ WebInspector.AuditRules.getDomainToResourcesMap = function(resources, types, nee WebInspector.AuditRules.evaluateInTargetWindow = function(func, args, callback) { - InjectedScriptAccess.getDefault().evaluateOnSelf(func.toString(), args, callback); + InspectorBackend.evaluateOnSelf(func.toString(), args, callback); } @@ -721,7 +721,7 @@ WebInspector.AuditRules.ImageDimensionsRule.prototype = { return nodeIds; } - WebInspector.AuditRules.evaluateInTargetWindow(pushImageNodes, null, receivedImages); + WebInspector.AuditRules.evaluateInTargetWindow(pushImageNodes, [], receivedImages); } } @@ -797,7 +797,7 @@ WebInspector.AuditRules.CssInHeadRule.prototype = { return found ? urlToViolationsArray : null; } - WebInspector.AuditRules.evaluateInTargetWindow(routine, null, evalCallback); + WebInspector.AuditRules.evaluateInTargetWindow(routine, [], evalCallback); } } @@ -844,7 +844,7 @@ WebInspector.AuditRules.StylesScriptsOrderRule.prototype = { return [ lateStyleUrls, cssBeforeInlineCount ]; } - WebInspector.AuditRules.evaluateInTargetWindow(routine, null, evalCallback.bind(this)); + WebInspector.AuditRules.evaluateInTargetWindow(routine, [], evalCallback.bind(this)); } } diff --git a/Source/WebCore/inspector/front-end/AuditsPanel.js b/Source/WebCore/inspector/front-end/AuditsPanel.js index c639f47..f3cbfa7 100644 --- a/Source/WebCore/inspector/front-end/AuditsPanel.js +++ b/Source/WebCore/inspector/front-end/AuditsPanel.js @@ -96,16 +96,6 @@ WebInspector.AuditsPanel.prototype = { return this._auditCategoriesById; }, - resourceStarted: function(resource) - { - this._launcherView.resourceStarted(resource); - }, - - resourceFinished: function(resource) - { - this._launcherView.resourceFinished(resource); - }, - addCategory: function(category) { this.categoriesById[category.id] = category; @@ -246,11 +236,6 @@ WebInspector.AuditsPanel.prototype = { x.show(this.viewsContainerElement); }, - reset: function() - { - this._launcherView.reset(); - }, - attach: function() { WebInspector.Panel.prototype.attach.call(this); diff --git a/Source/WebCore/inspector/front-end/Breakpoint.js b/Source/WebCore/inspector/front-end/Breakpoint.js index e5e1768..aa600a7 100644 --- a/Source/WebCore/inspector/front-end/Breakpoint.js +++ b/Source/WebCore/inspector/front-end/Breakpoint.js @@ -37,7 +37,6 @@ WebInspector.Breakpoint = function(debuggerModel, breakpointId, sourceID, url, l this.sourceID = sourceID; this._enabled = enabled; this._condition = condition || ""; - this._hit = false; this._debuggerModel = debuggerModel; } @@ -60,52 +59,14 @@ WebInspector.Breakpoint.prototype = { return this._condition; }, - get hit() + get data() { - return this._hit; - }, - - set hit(hit) - { - this._hit = hit; - this.dispatchEventToListeners("hit-state-changed"); - }, - - click: function(event) - { - WebInspector.panels.scripts.showSourceLine(this.url, this.line); - }, - - compareTo: function(other) - { - if (this.url != other.url) - return this.url < other.url ? -1 : 1; - if (this.line != other.line) - return this.line < other.line ? -1 : 1; - return 0; - }, - - populateLabelElement: function(element) - { - function didGetSourceLine(text) - { - var displayName = this.url ? WebInspector.displayNameForURL(this.url) : WebInspector.UIString("(program)"); - var labelElement = document.createTextNode(displayName + ":" + this.line); - element.appendChild(labelElement); - - var sourceTextElement = document.createElement("div"); - sourceTextElement.textContent = text; - sourceTextElement.className = "source-text monospace"; - element.appendChild(sourceTextElement); - } - var script = this._debuggerModel.scriptForSourceID(this.sourceID); - script.sourceLine(this.line, didGetSourceLine.bind(this)); + return { id: this.id, url: this.url, sourceID: this.sourceID, lineNumber: this.line, condition: this.condition }; }, remove: function() { this._debuggerModel.removeBreakpoint(this.id); - this.dispatchEventToListeners("removed"); this.removeAllListeners(); delete this._debuggerModel; } diff --git a/Source/WebCore/inspector/front-end/BreakpointManager.js b/Source/WebCore/inspector/front-end/BreakpointManager.js index 67ef112..d943d5b 100644 --- a/Source/WebCore/inspector/front-end/BreakpointManager.js +++ b/Source/WebCore/inspector/front-end/BreakpointManager.js @@ -34,7 +34,7 @@ WebInspector.BreakpointManager = function() var breakpoints = WebInspector.settings.findSettingForAllProjects("nativeBreakpoints"); for (var projectId in breakpoints) this._stickyBreakpoints[projectId] = this._validateBreakpoints(breakpoints[projectId]); - InspectorBackend.setStickyBreakpoints(this._stickyBreakpoints); + InspectorBackend.setAllBrowserBreakpoints(this._stickyBreakpoints); this._breakpoints = {}; this._domBreakpointsRestored = false; @@ -303,7 +303,7 @@ WebInspector.BreakpointManager.prototype = { WebInspector.settings.nativeBreakpoints = breakpoints; this._stickyBreakpoints[WebInspector.settings.projectId] = breakpoints; - InspectorBackend.setStickyBreakpoints(this._stickyBreakpoints); + InspectorBackend.setAllBrowserBreakpoints(this._stickyBreakpoints); }, _validateBreakpoints: function(persistentBreakpoints) diff --git a/Source/WebCore/inspector/front-end/BreakpointsSidebarPane.js b/Source/WebCore/inspector/front-end/BreakpointsSidebarPane.js index 408c5ba..b237ca2 100644 --- a/Source/WebCore/inspector/front-end/BreakpointsSidebarPane.js +++ b/Source/WebCore/inspector/front-end/BreakpointsSidebarPane.js @@ -23,7 +23,213 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.BreakpointsSidebarPane = function(title) +WebInspector.JavaScriptBreakpointsSidebarPane = function(title) +{ + WebInspector.SidebarPane.call(this, WebInspector.UIString("Breakpoints")); + + this.listElement = document.createElement("ol"); + this.listElement.className = "breakpoint-list"; + + this.emptyElement = document.createElement("div"); + this.emptyElement.className = "info"; + this.emptyElement.textContent = WebInspector.UIString("No Breakpoints"); + + this.bodyElement.appendChild(this.emptyElement); + + this._items = {}; + + WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointAdded, this._breakpointAdded, this); + WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointRemoved, this._breakpointRemoved, this); + WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this); + WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this); + WebInspector.breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.ProjectChanged, this._projectChanged, this); +} + +WebInspector.JavaScriptBreakpointsSidebarPane.prototype = { + _breakpointAdded: function(event) + { + var breakpoint = event.data; + var breakpointId = breakpoint.id; + var data = breakpoint.data; + + var element = document.createElement("li"); + + var checkbox = document.createElement("input"); + checkbox.className = "checkbox-elem"; + checkbox.type = "checkbox"; + checkbox.checked = breakpoint.enabled; + checkbox.addEventListener("click", this._breakpointItemCheckboxClicked.bind(this, breakpointId), false); + element.appendChild(checkbox); + + var label = document.createElement("span"); + element.appendChild(label); + + element._data = data; + var currentElement = this.listElement.firstChild; + while (currentElement) { + if (currentElement._data && this._compareBreakpoints(currentElement._data, element._data) > 0) + break; + currentElement = currentElement.nextSibling; + } + this._addListElement(element, currentElement); + + element.addEventListener("contextmenu", this._contextMenuEventFired.bind(this, breakpointId), true); + + this._setupBreakpointElement(data, element); + + var breakpointItem = {}; + breakpointItem.data = data; + breakpointItem.element = element; + breakpointItem.checkbox = checkbox; + this._items[breakpointId] = breakpointItem; + + if (!this.expanded) + this.expanded = true; + }, + + _breakpointRemoved: function(event) + { + var breakpointId = event.data; + var breakpointItem = this._items[breakpointId]; + if (breakpointItem) { + delete this._items[breakpointId]; + this._removeListElement(breakpointItem.element); + } + }, + + _breakpointEnableChanged: function(enabled, event) + { + var breakpointId = event.data; + var breakpointItem = this._items[breakpointId]; + if (breakpointItem) + breakpointItem.checkbox.checked = enabled; + }, + + _breakpointItemCheckboxClicked: function(breakpointId, event) + { + this._setBreakpointEnabled(breakpointId, event.target.checked); + + // Breakpoint element may have it's own click handler. + event.stopPropagation(); + }, + + _contextMenuEventFired: function(breakpointId, event) + { + var contextMenu = new WebInspector.ContextMenu(); + contextMenu.appendItem(WebInspector.UIString("Remove Breakpoint"), this._removeBreakpoint.bind(this, breakpointId)); + contextMenu.show(event); + }, + + _debuggerPaused: function(event) + { + var breakpointId = this._breakpointIdForDebuggerPausedEvent(event.data); + if (!breakpointId) + return; + var breakpointItem = this._items[breakpointId]; + if (!breakpointItem) + return; + breakpointItem.element.addStyleClass("breakpoint-hit"); + this._lastHitBreakpointItem = breakpointItem; + }, + + _debuggerResumed: function() + { + if (this._lastHitBreakpointItem) { + this._lastHitBreakpointItem.element.removeStyleClass("breakpoint-hit"); + delete this._lastHitBreakpointItem; + } + }, + + _addListElement: function(element, beforeElement) + { + if (beforeElement) + this.listElement.insertBefore(element, beforeElement); + else { + if (!this.listElement.firstChild) { + this.bodyElement.removeChild(this.emptyElement); + this.bodyElement.appendChild(this.listElement); + } + this.listElement.appendChild(element); + } + }, + + _removeListElement: function(element) + { + this.listElement.removeChild(element); + if (!this.listElement.firstChild) { + this.bodyElement.removeChild(this.listElement); + this.bodyElement.appendChild(this.emptyElement); + } + }, + + _projectChanged: function() + { + this.listElement.removeChildren(); + if (this.listElement.parentElement) { + this.bodyElement.removeChild(this.listElement); + this.bodyElement.appendChild(this.emptyElement); + } + this._items = {}; + }, + + _compare: function(x, y) + { + if (x !== y) + return x < y ? -1 : 1; + return 0; + }, + + _compareBreakpoints: function(b1, b2) + { + return this._compare(b1.url, b2.url) || this._compare(b1.lineNumber, b2.lineNumber); + }, + + _setupBreakpointElement: function(data, element) + { + var displayName = data.url ? WebInspector.displayNameForURL(data.url) : WebInspector.UIString("(program)"); + var labelElement = document.createTextNode(displayName + ":" + data.lineNumber); + element.appendChild(labelElement); + + var sourceTextElement = document.createElement("div"); + sourceTextElement.className = "source-text monospace"; + element.appendChild(sourceTextElement); + + function didGetSourceLine(text) + { + sourceTextElement.textContent = text; + } + var script = WebInspector.debuggerModel.scriptForSourceID(data.sourceID); + script.sourceLine(data.lineNumber, didGetSourceLine.bind(this)); + + element.addStyleClass("cursor-pointer"); + var clickHandler = WebInspector.panels.scripts.showSourceLine.bind(WebInspector.panels.scripts, data.url, data.lineNumber); + element.addEventListener("click", clickHandler, false); + }, + + _breakpointIdForDebuggerPausedEvent: function(details) + { + var callFrame = details.callFrames[0]; + var breakpoint = WebInspector.debuggerModel.findBreakpoint(callFrame.sourceID, callFrame.line); + if (breakpoint) + return breakpoint.id; + }, + + _setBreakpointEnabled: function(breakpointId, enabled) + { + var breakpoint = WebInspector.debuggerModel.breakpointForId(breakpointId); + WebInspector.debuggerModel.removeBreakpoint(breakpointId); + WebInspector.debuggerModel.setBreakpoint(breakpoint.sourceID, breakpoint.line, enabled, breakpoint.condition); + }, + + _removeBreakpoint: function(breakpointId) + { + WebInspector.debuggerModel.removeBreakpoint(breakpointId); + } +} + +WebInspector.JavaScriptBreakpointsSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; + +WebInspector.NativeBreakpointsSidebarPane = function(title) { WebInspector.SidebarPane.call(this, title); @@ -39,7 +245,7 @@ WebInspector.BreakpointsSidebarPane = function(title) WebInspector.breakpointManager.addEventListener(WebInspector.BreakpointManager.Events.ProjectChanged, this._projectChanged, this); } -WebInspector.BreakpointsSidebarPane.prototype = { +WebInspector.NativeBreakpointsSidebarPane.prototype = { addBreakpointItem: function(breakpointItem) { var element = breakpointItem.element; @@ -102,11 +308,11 @@ WebInspector.BreakpointsSidebarPane.prototype = { } } -WebInspector.BreakpointsSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; +WebInspector.NativeBreakpointsSidebarPane.prototype.__proto__ = WebInspector.SidebarPane.prototype; WebInspector.XHRBreakpointsSidebarPane = function() { - WebInspector.BreakpointsSidebarPane.call(this, WebInspector.UIString("XHR Breakpoints")); + WebInspector.NativeBreakpointsSidebarPane.call(this, WebInspector.UIString("XHR Breakpoints")); function addButtonClicked(event) { @@ -123,7 +329,7 @@ WebInspector.XHRBreakpointsSidebarPane = function() WebInspector.XHRBreakpointsSidebarPane.prototype = { addBreakpointItem: function(breakpointItem) { - WebInspector.BreakpointsSidebarPane.prototype.addBreakpointItem.call(this, breakpointItem); + WebInspector.NativeBreakpointsSidebarPane.prototype.addBreakpointItem.call(this, breakpointItem); breakpointItem._labelElement.addEventListener("dblclick", this._startEditingBreakpoint.bind(this, breakpointItem), false); }, @@ -166,7 +372,7 @@ WebInspector.XHRBreakpointsSidebarPane.prototype = { } } -WebInspector.XHRBreakpointsSidebarPane.prototype.__proto__ = WebInspector.BreakpointsSidebarPane.prototype; +WebInspector.XHRBreakpointsSidebarPane.prototype.__proto__ = WebInspector.NativeBreakpointsSidebarPane.prototype; WebInspector.BreakpointItem = function(breakpoint) { diff --git a/Source/WebCore/inspector/front-end/CSSCompletions.js b/Source/WebCore/inspector/front-end/CSSCompletions.js index e8d7556..f60c297 100644 --- a/Source/WebCore/inspector/front-end/CSSCompletions.js +++ b/Source/WebCore/inspector/front-end/CSSCompletions.js @@ -44,7 +44,7 @@ WebInspector.CSSCompletions.prototype = { return []; var results = []; - while (this._values[firstIndex].indexOf(prefix) === 0) + while (firstIndex < this._values.length && this._values[firstIndex].indexOf(prefix) === 0) results.push(this._values[firstIndex++]); return results; }, diff --git a/Source/WebCore/inspector/front-end/CSSKeywordCompletions.js b/Source/WebCore/inspector/front-end/CSSKeywordCompletions.js new file mode 100755 index 0000000..ac62aff --- /dev/null +++ b/Source/WebCore/inspector/front-end/CSSKeywordCompletions.js @@ -0,0 +1,438 @@ +/* + * Copyright (C) 2011 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. + */ + +WebInspector.CSSKeywordCompletions = { + forProperty: function(propertyName) + { + var acceptedKeywords = ["initial"]; + if (propertyName in this._propertyKeywordMap) + acceptedKeywords = acceptedKeywords.concat(this._propertyKeywordMap[propertyName]); + if (propertyName in this._colorAwareProperties) + acceptedKeywords = acceptedKeywords.concat(WebInspector.CSSKeywordCompletions._colors); + if (propertyName in WebInspector.StylesSidebarPane.InheritedProperties) + acceptedKeywords.push("inherit"); + return new WebInspector.CSSCompletions(acceptedKeywords); + } +}; + +WebInspector.CSSKeywordCompletions._colors = [ + "aqua", "black", "blue", "fuchsia", "gray", "green", "lime", "maroon", "navy", "olive", "orange", "purple", "red", + "silver", "teal", "white", "yellow", "transparent", "currentcolor", "grey", "aliceblue", "antiquewhite", + "aquamarine", "azure", "beige", "bisque", "blanchedalmond", "blueviolet", "brown", "burlywood", "cadetblue", + "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", + "darkgoldenrod", "darkgray", "darkgreen", "darkgrey", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", + "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkslategrey", + "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dimgrey", "dodgerblue", "firebrick", + "floralwhite", "forestgreen", "gainsboro", "ghostwhite", "gold", "goldenrod", "greenyellow", "honeydew", "hotpink", + "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", + "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgray", "lightgreen", "lightgrey", "lightpink", + "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightslategrey", "lightsteelblue", "lightyellow", + "limegreen", "linen", "magenta", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", + "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", + "mistyrose", "moccasin", "navajowhite", "oldlace", "olivedrab", "orangered", "orchid", "palegoldenrod", "palegreen", + "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "rosybrown", + "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "skyblue", "slateblue", + "slategray", "slategrey", "snow", "springgreen", "steelblue", "tan", "thistle", "tomato", "turquoise", "violet", + "wheat", "whitesmoke", "yellowgreen" +], + +WebInspector.CSSKeywordCompletions._colorAwareProperties = [ + "background", "background-color", "border", "border-color", "border-top", "border-right", "border-bottom", + "border-left", "border-top-color", "border-right-color", "border-bottom-color", "border-left-color", "color", + "outline", "outline-color", "text-line-through", "text-line-through-color", "text-overline", "text-overline-color", + "text-shadow", "text-underline", "text-underline-color", "-webkit-text-emphasis", "-webkit-text-emphasis-color" +].keySet(); + +WebInspector.CSSKeywordCompletions._propertyKeywordMap = { + "table-layout": [ + "auto", "fixed" + ], + "visibility": [ + "hidden", "visible", "collapse" + ], + "background-repeat": [ + "repeat", "repeat-x", "repeat-y", "no-repeat", "space", "round" + ], + "text-underline": [ + "none", "dotted", "dashed", "solid", "double", "dot-dash", "dot-dot-dash", "wave" + ], + "content": [ + "list-item", "close-quote", "no-close-quote", "no-open-quote", "open-quote" + ], + "list-style-image": [ + "none" + ], + "clear": [ + "none", "left", "right", "both" + ], + "text-underline-mode": [ + "continuous", "skip-white-space" + ], + "overflow-x": [ + "hidden", "auto", "visible", "overlay", "scroll" + ], + "stroke-linejoin": [ + "round", "miter", "bevel" + ], + "baseline-shift": [ + "baseline", "sub", "super" + ], + "border-bottom-width": [ + "medium", "thick", "thin" + ], + "marquee-speed": [ + "normal", "slow", "fast" + ], + "margin-top-collapse": [ + "collapse", "separate", "discard" + ], + "max-height": [ + "none" + ], + "box-orient": [ + "horizontal", "vertical", "inline-axis", "block-axis" + ], + "font-stretch": [ + "normal", "wider", "narrower", "ultra-condensed", "extra-condensed", "condensed", "semi-condensed", + "semi-expanded", "expanded", "extra-expanded", "ultra-expanded" + ], + "-webkit-color-correction": [ + "default", "srgb" + ], + "text-underline-style": [ + "none", "dotted", "dashed", "solid", "double", "dot-dash", "dot-dot-dash", "wave" + ], + "text-overline-mode": [ + "continuous", "skip-white-space" + ], + "-webkit-background-composite": [ + "highlight", "clear", "copy", "source-over", "source-in", "source-out", "source-atop", "destination-over", + "destination-in", "destination-out", "destination-atop", "xor", "plus-darker", "plus-lighter" + ], + "border-left-width": [ + "medium", "thick", "thin" + ], + "-webkit-writing-mode": [ + "lr", "rl", "tb", "lr-tb", "rl-tb", "tb-rl", "horizontal-tb", "vertical-rl", "vertical-lr", "horizontal-bt" + ], + "text-line-through-mode": [ + "continuous", "skip-white-space" + ], + "border-collapse": [ + "collapse", "separate" + ], + "page-break-inside": [ + "auto", "avoid" + ], + "border-top-width": [ + "medium", "thick", "thin" + ], + "outline-color": [ + "invert" + ], + "text-line-through-style": [ + "none", "dotted", "dashed", "solid", "double", "dot-dash", "dot-dot-dash", "wave" + ], + "outline-style": [ + "none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double" + ], + "cursor": [ + "none", "copy", "auto", "crosshair", "default", "pointer", "move", "vertical-text", "cell", "context-menu", + "alias", "progress", "no-drop", "not-allowed", "-webkit-zoom-in", "-webkit-zoom-out", "e-resize", "ne-resize", + "nw-resize", "n-resize", "se-resize", "sw-resize", "s-resize", "w-resize", "ew-resize", "ns-resize", + "nesw-resize", "nwse-resize", "col-resize", "row-resize", "text", "wait", "help", "all-scroll", "-webkit-grab", + "-webkit-grabbing" + ], + "border-width": [ + "medium", "thick", "thin" + ], + "size": [ + "a3", "a4", "a5", "b4", "b5", "landscape", "ledger", "legal", "letter", "portrait" + ], + "background-size": [ + "contain", "cover" + ], + "direction": [ + "ltr", "rtl" + ], + "marquee-direction": [ + "left", "right", "auto", "reverse", "forwards", "backwards", "ahead", "up", "down" + ], + "enable-background": [ + "accumulate", "new" + ], + "float": [ + "none", "left", "right" + ], + "overflow-y": [ + "hidden", "auto", "visible", "overlay", "scroll" + ], + "margin-bottom-collapse": [ + "collapse", "separate", "discard" + ], + "box-reflect": [ + "left", "right", "above", "below" + ], + "overflow": [ + "hidden", "auto", "visible", "overlay", "scroll" + ], + "text-rendering": [ + "auto", "optimizespeed", "optimizelegibility", "geometricprecision" + ], + "text-align": [ + "-webkit-auto", "left", "right", "center", "justify", "-webkit-left", "-webkit-right", "-webkit-center" + ], + "list-style-position": [ + "outside", "inside" + ], + "margin-bottom": [ + "auto" + ], + "color-interpolation": [ + "linearrgb" + ], + "background-origin": [ + "border-box", "content-box", "padding-box" + ], + "word-wrap": [ + "normal", "break-word" + ], + "font-weight": [ + "normal", "bold", "bolder", "lighter", "100", "200", "300", "400", "500", "600", "700", "800", "900" + ], + "margin-before-collapse": [ + "collapse", "separate", "discard" + ], + "text-overline-width": [ + "normal", "medium", "auto", "thick", "thin" + ], + "text-transform": [ + "none", "capitalize", "uppercase", "lowercase" + ], + "border-right-style": [ + "none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double" + ], + "border-left-style": [ + "none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double" + ], + "-webkit-text-emphasis": [ + "circle", "filled", "open", "dot", "double-circle", "triangle", "sesame" + ], + "font-style": [ + "italic", "oblique", "normal" + ], + "speak": [ + "none", "normal", "spell-out", "digits", "literal-punctuation", "no-punctuation" + ], + "text-line-through": [ + "none", "dotted", "dashed", "solid", "double", "dot-dash", "dot-dot-dash", "wave", "continuous", + "skip-white-space" + ], + "color-rendering": [ + "auto", "optimizespeed", "optimizequality" + ], + "list-style-type": [ + "none", "disc", "circle", "square", "decimal", "decimal-leading-zero", "arabic-indic", "binary", "bengali", + "cambodian", "khmer", "devanagari", "gujarati", "gurmukhi", "kannada", "lower-hexadecimal", "lao", "malayalam", + "mongolian", "myanmar", "octal", "oriya", "persian", "urdu", "telugu", "tibetan", "thai", "upper-hexadecimal", + "lower-roman", "upper-roman", "lower-greek", "lower-alpha", "lower-latin", "upper-alpha", "upper-latin", "afar", + "ethiopic-halehame-aa-et", "ethiopic-halehame-aa-er", "amharic", "ethiopic-halehame-am-et", "amharic-abegede", + "ethiopic-abegede-am-et", "cjk-earthly-branch", "cjk-heavenly-stem", "ethiopic", "ethiopic-halehame-gez", + "ethiopic-abegede", "ethiopic-abegede-gez", "hangul-consonant", "hangul", "lower-norwegian", "oromo", + "ethiopic-halehame-om-et", "sidama", "ethiopic-halehame-sid-et", "somali", "ethiopic-halehame-so-et", "tigre", + "ethiopic-halehame-tig", "tigrinya-er", "ethiopic-halehame-ti-er", "tigrinya-er-abegede", + "ethiopic-abegede-ti-er", "tigrinya-et", "ethiopic-halehame-ti-et", "tigrinya-et-abegede", + "ethiopic-abegede-ti-et", "upper-greek", "upper-norwegian", "asterisks", "footnotes", "hebrew", "armenian", + "lower-armenian", "upper-armenian", "georgian", "cjk-ideographic", "hiragana", "katakana", "hiragana-iroha", + "katakana-iroha" + ], + "-webkit-text-combine": [ + "none", "horizontal" + ], + "outline": [ + "none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double" + ], + "font": [ + "caption", "icon", "menu", "message-box", "small-caption", "-webkit-mini-control", "-webkit-small-control", + "-webkit-control", "status-bar", "italic", "oblique", "small-caps", "normal", "bold", "bolder", "lighter", + "100", "200", "300", "400", "500", "600", "700", "800", "900", "xx-small", "x-small", "small", "medium", + "large", "x-large", "xx-large", "-webkit-xxx-large", "smaller", "larger", "serif", "sans-serif", "cursive", + "fantasy", "monospace", "-webkit-body" + ], + "dominant-baseline": [ + "middle", "auto", "central", "text-before-edge", "text-after-edge", "ideographic", "alphabetic", "hanging", + "mathematical", "use-script", "no-change", "reset-size" + ], + "display": [ + "none", "inline", "block", "list-item", "run-in", "compact", "inline-block", "table", "inline-table", + "table-row-group", "table-header-group", "table-footer-group", "table-row", "table-column-group", + "table-column", "table-cell", "table-caption", "-webkit-box", "-webkit-inline-box", "-wap-marquee" + ], + "-webkit-text-emphasis-position": [ + "over", "under" + ], + "image-rendering": [ + "auto", "optimizespeed", "optimizequality" + ], + "alignment-baseline": [ + "baseline", "middle", "auto", "before-edge", "after-edge", "central", "text-before-edge", "text-after-edge", + "ideographic", "alphabetic", "hanging", "mathematical" + ], + "outline-width": [ + "medium", "thick", "thin" + ], + "text-line-through-width": [ + "normal", "medium", "auto", "thick", "thin" + ], + "box-align": [ + "baseline", "center", "stretch", "start", "end" + ], + "border-right-width": [ + "medium", "thick", "thin" + ], + "border-top-style": [ + "none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double" + ], + "line-height": [ + "normal" + ], + "text-overflow": [ + "clip", "ellipsis" + ], + "box-direction": [ + "normal", "reverse" + ], + "margin-after-collapse": [ + "collapse", "separate", "discard" + ], + "page-break-before": [ + "left", "right", "auto", "always", "avoid" + ], + "-webkit-hyphens": [ + "none", "auto", "manual" + ], + "border-image": [ + "repeat", "stretch" + ], + "text-decoration": [ + "blink", "line-through", "overline", "underline" + ], + "position": [ + "absolute", "fixed", "relative", "static" + ], + "font-family": [ + "serif", "sans-serif", "cursive", "fantasy", "monospace", "-webkit-body" + ], + "text-overflow-mode": [ + "clip", "ellipsis" + ], + "border-bottom-style": [ + "none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double" + ], + "unicode-bidi": [ + "normal", "bidi-override", "embed" + ], + "clip-rule": [ + "nonzero", "evenodd" + ], + "margin-left": [ + "auto" + ], + "margin-top": [ + "auto" + ], + "zoom": [ + "document", "reset" + ], + "text-overline-style": [ + "none", "dotted", "dashed", "solid", "double", "dot-dash", "dot-dot-dash", "wave" + ], + "max-width": [ + "none" + ], + "empty-cells": [ + "hide", "show" + ], + "pointer-events": [ + "none", "all", "auto", "visible", "visiblepainted", "visiblefill", "visiblestroke", "painted", "fill", "stroke" + ], + "letter-spacing": [ + "normal" + ], + "background-clip": [ + "border-box", "content-box", "padding-box" + ], + "-webkit-font-smoothing": [ + "none", "auto", "antialiased", "subpixel-antialiased" + ], + "border": [ + "none", "hidden", "inset", "groove", "ridge", "outset", "dotted", "dashed", "solid", "double" + ], + "font-size": [ + "xx-small", "x-small", "small", "medium", "large", "x-large", "xx-large", "-webkit-xxx-large", "smaller", + "larger" + ], + "font-variant": [ + "small-caps", "normal" + ], + "vertical-align": [ + "baseline", "middle", "sub", "super", "text-top", "text-bottom", "top", "bottom", "-webkit-baseline-middle" + ], + "marquee-style": [ + "none", "scroll", "slide", "alternate" + ], + "white-space": [ + "normal", "nowrap", "pre", "pre-line", "pre-wrap" + ], + "text-underline-width": [ + "normal", "medium", "auto", "thick", "thin" + ], + "box-lines": [ + "single", "multiple" + ], + "page-break-after": [ + "left", "right", "auto", "always", "avoid" + ], + "clip-path": [ + "none" + ], + "margin": [ + "auto" + ], + "marquee-repetition": [ + "infinite" + ], + "margin-right": [ + "auto" + ], + "-webkit-text-emphasis-style": [ + "circle", "filled", "open", "dot", "double-circle", "triangle", "sesame" + ] +} diff --git a/Source/WebCore/inspector/front-end/ConsoleView.js b/Source/WebCore/inspector/front-end/ConsoleView.js index a40030e..bd08e60 100644 --- a/Source/WebCore/inspector/front-end/ConsoleView.js +++ b/Source/WebCore/inspector/front-end/ConsoleView.js @@ -149,6 +149,11 @@ WebInspector.ConsoleView.prototype = { consoleMessagesCleared: function() { console.clearMessages(); + }, + + monitoringXHRStateChanged: function(enabled) + { + console._monitoringXHREnabled = enabled; } } InspectorBackend.registerDomainDispatcher("Console", dispatcher); @@ -355,14 +360,11 @@ WebInspector.ConsoleView.prototype = { // Collect comma separated object properties for the completion. var includeInspectorCommandLineAPI = (!dotNotation && !bracketNotation); - var callFrameId = WebInspector.panels.scripts.selectedCallFrameId(); var injectedScriptAccess; - if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused) { - var selectedCallFrame = WebInspector.panels.scripts.sidebarPanes.callstack.selectedCallFrame; - injectedScriptAccess = InjectedScriptAccess.get(selectedCallFrame.worldId); - } else - injectedScriptAccess = InjectedScriptAccess.getDefault(); - injectedScriptAccess.getCompletions(expressionString, includeInspectorCommandLineAPI, callFrameId, reportCompletions); + if (WebInspector.panels.scripts && WebInspector.panels.scripts.paused) + InspectorBackend.getCompletionsOnCallFrame(WebInspector.panels.scripts.selectedCallFrameId(), expressionString, includeInspectorCommandLineAPI, reportCompletions); + else + InspectorBackend.getCompletions(expressionString, includeInspectorCommandLineAPI, reportCompletions); }, _reportCompletions: function(bestMatchOnly, completionsReadyCallback, dotNotation, bracketNotation, prefix, result, isException) { @@ -416,14 +418,9 @@ WebInspector.ConsoleView.prototype = { return; } + var itemAction = InspectorBackend.setMonitoringXHREnabled.bind(InspectorBackend, !this._monitoringXHREnabled); var contextMenu = new WebInspector.ContextMenu(); - - function monitoringXHRWasChanged(newState) - { - WebInspector.monitoringXHREnabled = newState; - } - var itemAction = InspectorBackend.setMonitoringXHREnabled.bind(InspectorBackend, !WebInspector.monitoringXHREnabled, monitoringXHRWasChanged); - contextMenu.appendCheckboxItem(WebInspector.UIString("XMLHttpRequest logging"), itemAction, WebInspector.monitoringXHREnabled); + contextMenu.appendCheckboxItem(WebInspector.UIString("XMLHttpRequest logging"), itemAction, this._monitoringXHREnabled); contextMenu.appendItem(WebInspector.UIString("Clear Console"), this.requestClearMessages.bind(this)); contextMenu.show(event); }, @@ -532,8 +529,8 @@ WebInspector.ConsoleView.prototype = { function evalCallback(result) { callback(WebInspector.RemoteObject.fromPayload(result)); - }; - InjectedScriptAccess.getDefault().evaluate(expression, objectGroup, evalCallback); + } + InspectorBackend.evaluate(expression, objectGroup, evalCallback); }, _enterKeyPressed: function(event) @@ -681,6 +678,15 @@ WebInspector.ConsoleMessage = function(source, type, level, line, url, repeatCou this._parameters = parameters; this._stackTrace = stackTrace; this._requestId = requestId; + + if (stackTrace && stackTrace.length) { + var topCallFrame = stackTrace[0]; + if (!this.url) + this.url = topCallFrame.scriptName; + if (!this.line) + this.line = topCallFrame.lineNumber; + } + this._formatMessage(); } @@ -737,17 +743,8 @@ WebInspector.ConsoleMessage.prototype = { this._formattedMessage = document.createElement("span"); this._formattedMessage.className = "console-message-text source-code"; - if (stackTrace && stackTrace.length) { - var topCallFrame = stackTrace[0]; - var sourceName = topCallFrame.scriptName; - var sourceLine = topCallFrame.lineNumber; - } else { - var sourceName = this.url; - var sourceLine = this.line; - } - - if (sourceName && sourceName !== "undefined") { - var urlElement = WebInspector.linkifyResourceAsNode(sourceName, "scripts", sourceLine, "console-message-url"); + if (this.url && this.url !== "undefined") { + var urlElement = WebInspector.linkifyResourceAsNode(this.url, "scripts", this.line, "console-message-url"); this._formattedMessage.appendChild(urlElement); } diff --git a/Source/WebCore/inspector/front-end/DebuggerModel.js b/Source/WebCore/inspector/front-end/DebuggerModel.js index 8f5bcf7..717486c 100644 --- a/Source/WebCore/inspector/front-end/DebuggerModel.js +++ b/Source/WebCore/inspector/front-end/DebuggerModel.js @@ -31,6 +31,7 @@ WebInspector.DebuggerModel = function() { this._paused = false; + this._callFrames = []; this._breakpoints = {}; this._sourceIDAndLineToBreakpointId = {}; this._scripts = {}; @@ -43,6 +44,7 @@ WebInspector.DebuggerModel.Events = { DebuggerResumed: "debugger-resumed", ParsedScriptSource: "parsed-script-source", FailedToParseScriptSource: "failed-to-parse-script-source", + ScriptSourceChanged: "script-source-changed", BreakpointAdded: "breakpoint-added", BreakpointRemoved: "breakpoint-removed" } @@ -84,6 +86,7 @@ WebInspector.DebuggerModel.prototype = { delete this._breakpoints[breakpointId]; delete this._sourceIDAndLineToBreakpointId[this._encodeSourceIDAndLine(breakpoint.sourceID, breakpoint.line)]; this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointRemoved, breakpointId); + breakpoint.dispatchEventToListeners("removed"); }, _breakpointSetOnBackend: function(breakpointId, sourceID, lineNumber, condition, enabled, originalLineNumber, restored) @@ -103,6 +106,11 @@ WebInspector.DebuggerModel.prototype = { this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.BreakpointAdded, breakpoint); }, + breakpointForId: function(breakpointId) + { + return this._breakpoints[breakpointId]; + }, + queryBreakpoints: function(filter) { var breakpoints = []; @@ -129,6 +137,7 @@ WebInspector.DebuggerModel.prototype = { reset: function() { this._paused = false; + this._callFrames = []; this._breakpoints = {}; delete this._oneTimeBreakpoint; this._sourceIDAndLineToBreakpointId = {}; @@ -156,39 +165,81 @@ WebInspector.DebuggerModel.prototype = { return scripts; }, + editScriptSource: function(sourceID, scriptSource) + { + function didEditScriptSource(success, newBodyOrErrorMessage, callFrames) + { + if (success) { + if (callFrames && callFrames.length) + this._callFrames = callFrames; + this._updateScriptSource(sourceID, newBodyOrErrorMessage); + } else + WebInspector.log(newBodyOrErrorMessage, WebInspector.ConsoleMessage.MessageLevel.Warning); + } + InspectorBackend.editScriptSource(sourceID, scriptSource, didEditScriptSource.bind(this)); + }, + + _updateScriptSource: function(sourceID, scriptSource) + { + var script = this._scripts[sourceID]; + var oldSource = script.source; + script.source = scriptSource; + + // Clear and re-create breakpoints according to text diff. + var diff = Array.diff(oldSource.split("\n"), script.source.split("\n")); + for (var id in this._breakpoints) { + var breakpoint = this._breakpoints[id]; + if (breakpoint.sourceID !== sourceID) + continue; + breakpoint.remove(); + var lineNumber = breakpoint.line - 1; + var newLineNumber = diff.left[lineNumber].row; + if (newLineNumber === undefined) { + for (var i = lineNumber - 1; i >= 0; --i) { + if (diff.left[i].row === undefined) + continue; + var shiftedLineNumber = diff.left[i].row + lineNumber - i; + if (shiftedLineNumber < diff.right.length) { + var originalLineNumber = diff.right[shiftedLineNumber].row; + if (originalLineNumber === lineNumber || originalLineNumber === undefined) + newLineNumber = shiftedLineNumber; + } + break; + } + } + if (newLineNumber !== undefined) + this.setBreakpoint(sourceID, newLineNumber + 1, breakpoint.enabled, breakpoint.condition); + } + + this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ScriptSourceChanged, { sourceID: sourceID, oldSource: oldSource }); + }, + + get callFrames() + { + return this._callFrames; + }, + _pausedScript: function(details) { this._paused = true; + this._callFrames = details.callFrames; if ("_continueToLineBreakpointId" in this) { InspectorBackend.removeBreakpoint(this._continueToLineBreakpointId); delete this._continueToLineBreakpointId; } this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerPaused, details); - - if (details.eventType === WebInspector.DebuggerEventTypes.JavaScriptPause || details.eventType === WebInspector.DebuggerEventTypes.NativeBreakpoint) - return; - - var breakpoint = this.findBreakpoint(details.callFrames[0].sourceID, details.callFrames[0].line); - if (!breakpoint) - return; - breakpoint.hit = true; - this._lastHitBreakpoint = breakpoint; }, _resumedScript: function() { this._paused = false; + this._callFrames = []; this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.DebuggerResumed); - - if (!this._lastHitBreakpoint) - return; - this._lastHitBreakpoint.hit = false; - delete this._lastHitBreakpoint; }, - _parsedScriptSource: function(sourceID, sourceURL, lineOffset, columnOffset, scriptWorldType) + _parsedScriptSource: function(sourceID, sourceURL, lineOffset, columnOffset, length, scriptWorldType) { - var script = new WebInspector.Script(sourceID, sourceURL, "", lineOffset, columnOffset, undefined, undefined, scriptWorldType); + var script = new WebInspector.Script(sourceID, sourceURL, "", lineOffset, columnOffset, length, undefined, undefined, scriptWorldType); this._scripts[sourceID] = script; this.dispatchEventToListeners(WebInspector.DebuggerModel.Events.ParsedScriptSource, sourceID); }, @@ -234,9 +285,9 @@ WebInspector.DebuggerDispatcher.prototype = { WebInspector.panels.scripts.debuggerWasDisabled(); }, - parsedScriptSource: function(sourceID, sourceURL, lineOffset, columnOffset, scriptWorldType) + parsedScriptSource: function(sourceID, sourceURL, lineOffset, columnOffset, length, scriptWorldType) { - this._debuggerModel._parsedScriptSource(sourceID, sourceURL, lineOffset, columnOffset, scriptWorldType); + this._debuggerModel._parsedScriptSource(sourceID, sourceURL, lineOffset, columnOffset, length, scriptWorldType); }, failedToParseScriptSource: function(sourceURL, source, startingLine, errorLine, errorMessage) diff --git a/Source/WebCore/inspector/front-end/ElementsTreeOutline.js b/Source/WebCore/inspector/front-end/ElementsTreeOutline.js index 67d34b2..722c028 100644 --- a/Source/WebCore/inspector/front-end/ElementsTreeOutline.js +++ b/Source/WebCore/inspector/front-end/ElementsTreeOutline.js @@ -411,8 +411,7 @@ WebInspector.ElementsTreeElement.prototype = { else this.tooltip = WebInspector.UIString("%d × %d pixels (Natural: %d × %d pixels)", properties.offsetWidth, properties.offsetHeight, properties.naturalWidth, properties.naturalHeight); } - - InjectedScriptAccess.getForNode(node).getNodeProperties(node.id, ["naturalHeight", "naturalWidth", "offsetHeight", "offsetWidth"], setTooltip.bind(this)); + InspectorBackend.getNodeProperties(node.id, ["naturalHeight", "naturalWidth", "offsetHeight", "offsetWidth"], setTooltip.bind(this)); }, updateSelection: function() diff --git a/Source/WebCore/inspector/front-end/ExtensionAPI.js b/Source/WebCore/inspector/front-end/ExtensionAPI.js index a9a2423..b10452d 100644 --- a/Source/WebCore/inspector/front-end/ExtensionAPI.js +++ b/Source/WebCore/inspector/front-end/ExtensionAPI.js @@ -450,8 +450,9 @@ ExtensionServerClient.prototype = { _onCallback: function(request) { if (request.requestId in this._callbacks) { - this._callbacks[request.requestId](request.result); + var callback = this._callbacks[request.requestId]; delete this._callbacks[request.requestId]; + callback(request.result); } }, diff --git a/Source/WebCore/inspector/front-end/ExtensionPanel.js b/Source/WebCore/inspector/front-end/ExtensionPanel.js index 4b42e68..fb98350 100644 --- a/Source/WebCore/inspector/front-end/ExtensionPanel.js +++ b/Source/WebCore/inspector/front-end/ExtensionPanel.js @@ -95,7 +95,7 @@ WebInspector.ExtensionWatchSidebarPane.prototype = { setExpression: function(expression, title) { - InjectedScriptAccess.getDefault().evaluate(expression, this._onEvaluate.bind(this, title)); + InspectorBackend.evaluate(expression, "extension-watch", this._onEvaluate.bind(this, title)); }, _onEvaluate: function(title, result) diff --git a/Source/WebCore/inspector/front-end/ExtensionServer.js b/Source/WebCore/inspector/front-end/ExtensionServer.js index 1320efb..0924106 100644 --- a/Source/WebCore/inspector/front-end/ExtensionServer.js +++ b/Source/WebCore/inspector/front-end/ExtensionServer.js @@ -53,7 +53,6 @@ WebInspector.ExtensionServer = function() this._registerHandler("subscribe", this._onSubscribe.bind(this)); this._registerHandler("unsubscribe", this._onUnsubscribe.bind(this)); - window.addEventListener("message", this._onWindowMessage.bind(this), false); } @@ -68,11 +67,6 @@ WebInspector.ExtensionServer.prototype = { this._postNotification("panel-objectSelected-" + panelId, objectId); }, - notifyResourceFinished: function(resource) - { - this._postNotification("resource-finished", resource.identifier, (new WebInspector.HAREntry(resource)).build()); - }, - notifySearchAction: function(panelId, action, searchString) { this._postNotification("panel-search-" + panelId, action, searchString); @@ -114,6 +108,12 @@ WebInspector.ExtensionServer.prototype = { delete this._clientObjects[auditRun.id]; }, + _notifyResourceFinished: function(event) + { + var resource = event.data; + this._postNotification("resource-finished", resource.identifier, (new WebInspector.HAREntry(resource)).build()); + }, + _postNotification: function(type, details) { var subscribers = this._subscribers[type]; @@ -272,7 +272,7 @@ WebInspector.ExtensionServer.prototype = { var evalExpression = "JSON.stringify(eval('" + "with (window.console._commandLineAPI) with (window) {' + unescape('" + escape(message.expression) + "') + '}'));"; - InjectedScriptAccess.getDefault().evaluate(evalExpression, callback.bind(this)); + InspectorBackend.evaluate(evalExpression, "none", callback.bind(this)); }, _onRevealAndSelect: function(message) @@ -356,6 +356,9 @@ WebInspector.ExtensionServer.prototype = { initExtensions: function() { + // The networkManager is normally created after the ExtensionServer is constructed, but before initExtensions() is called. + WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceFinished, this._notifyResourceFinished, this); + InspectorExtensionRegistry.getExtensionsAsync(); }, @@ -393,7 +396,6 @@ WebInspector.ExtensionServer.prototype = { "var apiPrivate = {};" + "(" + WebInspector.commonExtensionSymbols.toString() + ")(apiPrivate);" + "(" + WebInspector.injectedExtensionAPI.toString() + ").apply(this, arguments);" + - "webInspector.resources.Types = " + JSON.stringify(resourceTypes) + ";" + platformAPI + "})"; }, diff --git a/Source/WebCore/inspector/front-end/InjectedScriptAccess.js b/Source/WebCore/inspector/front-end/InjectedScriptAccess.js deleted file mode 100644 index cb3c2b8..0000000 --- a/Source/WebCore/inspector/front-end/InjectedScriptAccess.js +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2009 Google Inc. All rights reserved. - * Copyright (C) 2009 Joseph Pecoraro - * - * 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. - */ - -function InjectedScriptAccess(worldId) { - this._worldId = worldId; -} - -InjectedScriptAccess.get = function(worldId) -{ - if (typeof worldId === "number") - return new InjectedScriptAccess(worldId); - - console.assert(false, "Access to injected script with no id"); -} - -InjectedScriptAccess.getForNode = function(node) -{ - // FIXME: do something. - return InjectedScriptAccess.get(-node.id); -} - -InjectedScriptAccess.getForObjectId = function(objectId) -{ - // FIXME: move to native layer. - var tokens = objectId.split(":"); - return InjectedScriptAccess.get(parseInt(tokens[0])); -} - -InjectedScriptAccess.getDefault = function() -{ - return InjectedScriptAccess.get(0); -} - -InjectedScriptAccess.prototype = {}; - -InjectedScriptAccess._installHandler = function(methodName, async) -{ - InjectedScriptAccess.prototype[methodName] = function() - { - var allArgs = Array.prototype.slice.call(arguments); - var callback = allArgs[allArgs.length - 1]; - var argsString = JSON.stringify(Array.prototype.slice.call(allArgs, 0, allArgs.length - 1)); - - function myCallback(result, isException) - { - if (!isException) - callback(result); - else - WebInspector.console.addMessage(WebInspector.ConsoleMessage.createTextMessage("Error dispatching: " + methodName)); - } - InspectorBackend.dispatchOnInjectedScript(this._worldId, methodName, argsString, myCallback); - }; -} - -// InjectedScriptAccess message forwarding puts some constraints on the way methods are implemented and called: -// - Make sure corresponding methods in InjectedScript return non-null and non-undefined values, -// - Make sure last parameter of all the InjectedSriptAccess.* calls is a callback function. -// We keep these sorted. -InjectedScriptAccess._installHandler("evaluate"); -InjectedScriptAccess._installHandler("evaluateInCallFrame"); -InjectedScriptAccess._installHandler("evaluateOnSelf"); -InjectedScriptAccess._installHandler("getCompletions"); -InjectedScriptAccess._installHandler("getProperties"); -InjectedScriptAccess._installHandler("getPrototypes"); -InjectedScriptAccess._installHandler("pushNodeToFrontend"); -InjectedScriptAccess._installHandler("resolveNode"); -InjectedScriptAccess._installHandler("getNodeProperties"); -InjectedScriptAccess._installHandler("setPropertyValue"); diff --git a/Source/WebCore/inspector/front-end/NetworkManager.js b/Source/WebCore/inspector/front-end/NetworkManager.js index a657377..ed4309e 100644 --- a/Source/WebCore/inspector/front-end/NetworkManager.js +++ b/Source/WebCore/inspector/front-end/NetworkManager.js @@ -30,6 +30,8 @@ WebInspector.NetworkManager = function(resourceTreeModel) { + WebInspector.Object.call(this); + this._inflightResources = {}; this._resourceTreeModel = resourceTreeModel; this._lastIdentifierForCachedResource = 0; @@ -86,6 +88,13 @@ WebInspector.NetworkManager.updateResourceWithCachedResource = function(resource WebInspector.NetworkManager.updateResourceWithResponse(resource, cachedResource.response); } +WebInspector.NetworkManager.EventTypes = { + ResourceStarted: "ResourceStarted", + ResourceUpdated: "ResourceUpdated", + ResourceFinished: "ResourceFinished", + MainResourceCommitLoad: "MainResourceCommitLoad" +} + WebInspector.NetworkManager.prototype = { reset: function() { @@ -119,7 +128,7 @@ WebInspector.NetworkManager.prototype = { if (isRedirect) this._startResource(resource); else - WebInspector.panels.network.refreshResource(resource); + this._updateResource(resource); }, markResourceAsCached: function(identifier) @@ -129,7 +138,7 @@ WebInspector.NetworkManager.prototype = { return; resource.cached = true; - WebInspector.panels.network.refreshResource(resource); + this._updateResource(resource); }, didReceiveResponse: function(identifier, time, resourceType, response) @@ -143,7 +152,7 @@ WebInspector.NetworkManager.prototype = { WebInspector.NetworkManager.updateResourceWithResponse(resource, response); - WebInspector.panels.network.refreshResource(resource); + this._updateResource(resource); this._resourceTreeModel.addResourceToFrame(resource.loader.frameId, resource); }, @@ -156,7 +165,7 @@ WebInspector.NetworkManager.prototype = { resource.resourceSize += lengthReceived; resource.endTime = time; - WebInspector.panels.network.refreshResource(resource); + this._updateResource(resource); }, didFinishLoading: function(identifier, finishTime) @@ -204,8 +213,7 @@ WebInspector.NetworkManager.prototype = { resource.type = WebInspector.Resource.Type[type]; resource.setInitialContent(sourceString); - WebInspector.panels.resources.refreshResource(resource); - WebInspector.panels.network.refreshResource(resource); + this._updateResource(resource); }, didCommitLoadForFrame: function(frame, loader) @@ -216,7 +224,7 @@ WebInspector.NetworkManager.prototype = { if (mainResource) { WebInspector.mainResource = mainResource; mainResource.isMainResource = true; - WebInspector.panels.network.mainResourceChanged(); + this.dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.MainResourceCommitLoad, mainResource); } } }, @@ -239,7 +247,7 @@ WebInspector.NetworkManager.prototype = { resource.webSocketRequestKey3 = request.webSocketRequestKey3; resource.startTime = time; - WebInspector.panels.network.refreshResource(resource); + this._updateResource(resource); }, didReceiveWebSocketHandshakeResponse: function(identifier, time, response) @@ -254,7 +262,7 @@ WebInspector.NetworkManager.prototype = { resource.webSocketChallengeResponse = response.webSocketChallengeResponse; resource.responseReceivedTime = time; - WebInspector.panels.network.refreshResource(resource); + this._updateResource(resource); }, didCloseWebSocket: function(identifier, time) @@ -283,20 +291,24 @@ WebInspector.NetworkManager.prototype = { return newResource; }, - _startResource: function(resource, skipRefresh) + _startResource: function(resource) { this._inflightResources[resource.identifier] = resource; - WebInspector.panels.network.appendResource(resource, skipRefresh); - WebInspector.panels.audits.resourceStarted(resource); + this.dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceStarted, resource); + }, + + _updateResource: function(resource) + { + this.dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceUpdated, resource); }, _finishResource: function(resource, finishTime) { resource.endTime = finishTime; resource.finished = true; - WebInspector.panels.network.refreshResource(resource); - WebInspector.panels.audits.resourceFinished(resource); - WebInspector.extensionServer.notifyResourceFinished(resource); + this.dispatchEventToListeners(WebInspector.NetworkManager.EventTypes.ResourceFinished, resource); delete this._inflightResources[resource.identifier]; } } + +WebInspector.NetworkManager.prototype.__proto__ = WebInspector.Object.prototype; diff --git a/Source/WebCore/inspector/front-end/NetworkPanel.js b/Source/WebCore/inspector/front-end/NetworkPanel.js index 28cbd36..943ee7f 100644 --- a/Source/WebCore/inspector/front-end/NetworkPanel.js +++ b/Source/WebCore/inspector/front-end/NetworkPanel.js @@ -78,6 +78,11 @@ WebInspector.NetworkPanel = function() this._filter(this._filterAllElement, false); this._toggleGridMode(); + + WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceStarted, this._onResourceStarted, this); + WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceUpdated, this._onResourceUpdated, this); + WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceFinished, this._onResourceUpdated, this); + WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.MainResourceCommitLoad, this._onMainResourceCommitLoad, this); } WebInspector.NetworkPanel.prototype = { @@ -772,7 +777,12 @@ WebInspector.NetworkPanel.prototype = { return this._resourcesById[id]; }, - appendResource: function(resource) + _onResourceStarted: function(event) + { + this._appendResource(event.data); + }, + + _appendResource: function(resource) { this._resources.push(resource); this._resourcesById[resource.identifier] = resource; @@ -781,13 +791,18 @@ WebInspector.NetworkPanel.prototype = { // Pull all the redirects of the main resource upon commit load. if (resource.redirects) { for (var i = 0; i < resource.redirects.length; ++i) - this.refreshResource(resource.redirects[i]); + this._refreshResource(resource.redirects[i]); } - this.refreshResource(resource); + this._refreshResource(resource); + }, + + _onResourceUpdated: function(event) + { + this._refreshResource(event.data); }, - refreshResource: function(resource) + _refreshResource: function(resource) { this._staleResources.push(resource); this._scheduleRefresh(); @@ -811,7 +826,7 @@ WebInspector.NetworkPanel.prototype = { this._reset(); }, - mainResourceChanged: function() + _onMainResourceCommitLoad: function() { if (this._preserveLogToggle.toggled) return; @@ -819,7 +834,7 @@ WebInspector.NetworkPanel.prototype = { this._reset(); // Now resurrect the main resource along with all redirects that lead to it. var resourcesToAppend = (WebInspector.mainResource.redirects || []).concat(WebInspector.mainResource); - resourcesToAppend.forEach(this.appendResource, this); + resourcesToAppend.forEach(this._appendResource, this); }, canShowSourceLine: function(url, line) diff --git a/Source/WebCore/inspector/front-end/PropertiesSidebarPane.js b/Source/WebCore/inspector/front-end/PropertiesSidebarPane.js index b9c212a..a1e37bc 100644 --- a/Source/WebCore/inspector/front-end/PropertiesSidebarPane.js +++ b/Source/WebCore/inspector/front-end/PropertiesSidebarPane.js @@ -42,11 +42,11 @@ WebInspector.PropertiesSidebarPane.prototype = { return; } - var self = this; - var callback = function(prototypes) { - var body = self.bodyElement; + function callback(prototypes) + { + var body = this.bodyElement; body.removeChildren(); - self.sections = []; + this.sections = []; // Get array of prototype user-friendly names. for (var i = 0; i < prototypes.length; ++i) { @@ -55,11 +55,11 @@ WebInspector.PropertiesSidebarPane.prototype = { if (title.match(/Prototype$/)) title = title.replace(/Prototype$/, ""); var section = new WebInspector.ObjectPropertiesSection(prototype, title); - self.sections.push(section); + this.sections.push(section); body.appendChild(section.element); } - }; - InjectedScriptAccess.getForNode(node).getPrototypes(node.id, callback); + } + InspectorBackend.getNodePrototypes(node.id, callback.bind(this)); } } diff --git a/Source/WebCore/inspector/front-end/RemoteObject.js b/Source/WebCore/inspector/front-end/RemoteObject.js index 4d6736c..10af2e3 100644 --- a/Source/WebCore/inspector/front-end/RemoteObject.js +++ b/Source/WebCore/inspector/front-end/RemoteObject.js @@ -52,7 +52,7 @@ WebInspector.RemoteObject.resolveNode = function(node, callback) { callback(object ? WebInspector.RemoteObject.fromPayload(object) : null); } - InjectedScriptAccess.getForNode(node).resolveNode(node.id, mycallback); + InspectorBackend.resolveNode(node.id, mycallback); } WebInspector.RemoteObject.fromPayload = function(payload) @@ -118,7 +118,7 @@ WebInspector.RemoteObject.prototype = { properties[i].value = WebInspector.RemoteObject.fromPayload(properties[i].value); callback(properties); } - InjectedScriptAccess.getForObjectId(this._objectId).getProperties(this._objectId, ignoreHasOwnProperty, abbreviate, remoteObjectBinder); + InspectorBackend.getProperties(this._objectId, !!ignoreHasOwnProperty, abbreviate, remoteObjectBinder); }, setPropertyValue: function(name, value, callback) @@ -127,12 +127,12 @@ WebInspector.RemoteObject.prototype = { callback(false); return; } - InjectedScriptAccess.getForObjectId(this._objectId).setPropertyValue(this._objectId, name, value, callback); + InspectorBackend.setPropertyValue(this._objectId, name, value, callback); }, pushNodeToFrontend: function(callback) { - InjectedScriptAccess.getForObjectId(this._objectId).pushNodeToFrontend(this._objectId, callback); + InspectorBackend.pushNodeToFrontend(this._objectId, callback); } } diff --git a/Source/WebCore/inspector/front-end/Resource.js b/Source/WebCore/inspector/front-end/Resource.js index 7340645..00c1fb9 100644 --- a/Source/WebCore/inspector/front-end/Resource.js +++ b/Source/WebCore/inspector/front-end/Resource.js @@ -44,7 +44,6 @@ WebInspector.Resource.Type = { Font: 3, Script: 4, XHR: 5, - Media: 6, WebSocket: 7, Other: 8, @@ -68,8 +67,6 @@ WebInspector.Resource.Type = { return WebInspector.UIString("Script"); case this.XHR: return WebInspector.UIString("XHR"); - case this.Media: - return WebInspector.UIString("Media"); case this.WebSocket: return WebInspector.UIString("WebSocket"); case this.Other: @@ -95,8 +92,6 @@ WebInspector.Resource.Type = { return "script"; case this.XHR: return "xhr"; - case this.Media: - return "media"; case this.WebSocket: return "websocket"; case this.Other: @@ -669,6 +664,13 @@ WebInspector.Resource.prototype = { requestContent: function(callback) { + // We do not support content retrieval for WebSockets at the moment. + // Since WebSockets are potentially long-living, fail requests immediately + // to prevent caller blocking until resource is marked as finished. + if (this.type === WebInspector.Resource.Type.WebSocket) { + callback(null, null); + return; + } if (this._content) { callback(this._content, this._contentEncoded); return; diff --git a/Source/WebCore/inspector/front-end/ResourcesPanel.js b/Source/WebCore/inspector/front-end/ResourcesPanel.js index d96989b..7e1fcc0 100644 --- a/Source/WebCore/inspector/front-end/ResourcesPanel.js +++ b/Source/WebCore/inspector/front-end/ResourcesPanel.js @@ -78,6 +78,8 @@ WebInspector.ResourcesPanel = function(database) this.sidebarElement.addEventListener("mousemove", this._onmousemove.bind(this), false); this.sidebarElement.addEventListener("mouseout", this._onmouseout.bind(this), false); + + WebInspector.networkManager.addEventListener(WebInspector.NetworkManager.EventTypes.ResourceUpdated, this._refreshResource, this); } WebInspector.ResourcesPanel.prototype = { @@ -253,8 +255,9 @@ WebInspector.ResourcesPanel.prototype = { frameTreeElement.removeChildren(); }, - refreshResource: function(resource) + _refreshResource: function(event) { + var resource = event.data; // FIXME: do not add XHR in the first place based on the native instrumentation. if (resource.type === WebInspector.Resource.Type.XHR) { var resourceTreeElement = this._findTreeElementForResource(resource); diff --git a/Source/WebCore/inspector/front-end/Script.js b/Source/WebCore/inspector/front-end/Script.js index 89b2121..6e3b18d 100644 --- a/Source/WebCore/inspector/front-end/Script.js +++ b/Source/WebCore/inspector/front-end/Script.js @@ -23,13 +23,14 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.Script = function(sourceID, sourceURL, source, lineOffset, columnOffset, errorLine, errorMessage, worldType) +WebInspector.Script = function(sourceID, sourceURL, source, lineOffset, columnOffset, length, errorLine, errorMessage, worldType) { this.sourceID = sourceID; this.sourceURL = sourceURL; this._source = source; this.lineOffset = lineOffset; this.columnOffset = columnOffset; + this.length = length; this.errorLine = errorLine; this.errorMessage = errorMessage; this.worldType = worldType; @@ -96,12 +97,15 @@ WebInspector.Script.prototype = { get source() { + if (!this._source && this.resource) + this._source = this.resource.content; return this._source; }, set source(source) { this._source = source; + delete this._lineEndings; }, requestSource: function(callback) diff --git a/Source/WebCore/inspector/front-end/ScriptFormatter.js b/Source/WebCore/inspector/front-end/ScriptFormatter.js new file mode 100644 index 0000000..69ffb74 --- /dev/null +++ b/Source/WebCore/inspector/front-end/ScriptFormatter.js @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2011 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. + */ + +WebInspector.ScriptFormatter = function(source) +{ + this._originalSource = source; + this._originalLineEndings = source.findAll("\n"); + this._originalLineEndings.push(source.length); +} + +WebInspector.ScriptFormatter.locationToPosition = function(lineEndings, location) +{ + var position = location.line ? lineEndings[location.line - 1] + 1 : 0; + return position + location.column; +} + +WebInspector.ScriptFormatter.positionToLocation = function(lineEndings, position) +{ + var location = {}; + location.line = lineEndings.upperBound(position - 1); + if (!location.line) + location.column = position; + else + location.column = position - lineEndings[location.line - 1] - 1; + return location; +} + +WebInspector.ScriptFormatter.prototype = { + format: function(callback) + { + var worker = new Worker("scriptFormatterWorker.js"); + function messageHandler(event) + { + var formattedSource = event.data; + this._formatted = true; + this._formattedSource = formattedSource; + this._formattedLineEndings = formattedSource.findAll("\n"); + this._formattedLineEndings.push(formattedSource.length); + this._buildMapping(); + callback(formattedSource); + } + worker.onmessage = messageHandler.bind(this); + worker.postMessage(this._originalSource); + }, + + _buildMapping: function() + { + this._originalSymbolPositions = []; + this._formattedSymbolPositions = []; + var lastCodePosition = 0; + var regexp = /[\$\.\w]+|{|}|;/g; + while (true) { + var match = regexp.exec(this._formattedSource); + if (!match) + break; + var position = this._originalSource.indexOf(match[0], lastCodePosition); + if (position === -1) + continue; + this._originalSymbolPositions.push(position); + this._formattedSymbolPositions.push(match.index); + lastCodePosition = position + match[0].length; + } + this._originalSymbolPositions.push(this._originalSource.length); + this._formattedSymbolPositions.push(this._formattedSource.length); + }, + + originalLineNumberToFormattedLineNumber: function(originalLineNumber) + { + if (!this._formatted) + return originalLineNumber; + var originalPosition = WebInspector.ScriptFormatter.locationToPosition(this._originalLineEndings, { line: originalLineNumber, column: 0 }); + return this.originalPositionToFormattedLineNumber(originalPosition); + }, + + formattedLineNumberToOriginalLineNumber: function(formattedLineNumber) + { + if (!this._formatted) + return formattedLineNumber; + var originalPosition = this.formattedLineNumberToOriginalPosition(formattedLineNumber); + return WebInspector.ScriptFormatter.positionToLocation(this._originalLineEndings, originalPosition).line; + }, + + originalPositionToFormattedLineNumber: function(originalPosition) + { + var lineEndings = this._formatted ? this._formattedLineEndings : this._originalLineEndings; + if (this._formatted) + formattedPosition = this._convertPosition(this._originalSymbolPositions, this._formattedSymbolPositions, originalPosition); + return WebInspector.ScriptFormatter.positionToLocation(lineEndings, formattedPosition).line; + }, + + formattedLineNumberToOriginalPosition: function(formattedLineNumber) + { + var lineEndings = this._formatted ? this._formattedLineEndings : this._originalLineEndings; + var formattedPosition = WebInspector.ScriptFormatter.locationToPosition(lineEndings, { line: formattedLineNumber, column: 0 }); + if (!this._formatted) + return formattedPosition; + return this._convertPosition(this._formattedSymbolPositions, this._originalSymbolPositions, formattedPosition); + }, + + _convertPosition: function(symbolPositions1, symbolPositions2, position) + { + var index = symbolPositions1.upperBound(position); + if (index === symbolPositions2.length - 1) + return symbolPositions2[index] - 1; + return symbolPositions2[index]; + } +} diff --git a/Source/WebCore/inspector/front-end/ScriptFormatterWorker.js b/Source/WebCore/inspector/front-end/ScriptFormatterWorker.js new file mode 100644 index 0000000..e900317 --- /dev/null +++ b/Source/WebCore/inspector/front-end/ScriptFormatterWorker.js @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2011 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. + */ + +var parse = loadModule("parse-js.js"); +var process = loadModule("process.js"); + +onmessage = function(event) { + postMessage(beautify(event.data)); +}; + +function beautify(source) +{ + var ast = parse.parse(source); + var beautifyOptions = { + indent_level: 4, + indent_start: 0, + quote_keys: false, + space_colon: false + }; + return process.gen_code(ast, beautifyOptions); +} + +function loadModule(src) +{ + var request = new XMLHttpRequest(); + request.open("GET", src, false); + request.send(); + + var exports = {}; + eval(request.responseText); + return exports; +} + +function require() +{ + return parse; +} diff --git a/Source/WebCore/inspector/front-end/ScriptView.js b/Source/WebCore/inspector/front-end/ScriptView.js index d6c1c59..f631fcc 100644 --- a/Source/WebCore/inspector/front-end/ScriptView.js +++ b/Source/WebCore/inspector/front-end/ScriptView.js @@ -30,7 +30,7 @@ WebInspector.ScriptView = function(script) this.element.addStyleClass("script-view"); var contentProvider = new WebInspector.SourceFrameContentProviderForScript(script); - this.sourceFrame = new WebInspector.SourceFrame(this.element, contentProvider, "", WebInspector.panels.scripts.canEditScripts()); + this.sourceFrame = new WebInspector.SourceFrame(this.element, contentProvider, "", true); } WebInspector.ScriptView.prototype = { diff --git a/Source/WebCore/inspector/front-end/ScriptsPanel.js b/Source/WebCore/inspector/front-end/ScriptsPanel.js index 32212d4..a74f80d 100644 --- a/Source/WebCore/inspector/front-end/ScriptsPanel.js +++ b/Source/WebCore/inspector/front-end/ScriptsPanel.js @@ -63,6 +63,15 @@ WebInspector.ScriptsPanel = function() // FIXME: append the functions select element to the top status bar when it is implemented. // this.topStatusBar.appendChild(this.functionsSelectElement); + this.formatButton = document.createElement("button"); + this.formatButton.className = "status-bar-item"; + this.formatButton.id = "format-script"; + this.formatButton.title = WebInspector.UIString("Format script."); + this.formatButton.appendChild(document.createElement("img")); + this.formatButton.addEventListener("click", this._formatScript.bind(this), false); + if (Preferences.debugMode) + this.topStatusBar.appendChild(this.formatButton); + this.sidebarButtonsElement = document.createElement("div"); this.sidebarButtonsElement.id = "scripts-sidebar-buttons"; this.topStatusBar.appendChild(this.sidebarButtonsElement); @@ -131,7 +140,7 @@ WebInspector.ScriptsPanel = function() this.sidebarPanes.watchExpressions = new WebInspector.WatchExpressionsSidebarPane(); this.sidebarPanes.callstack = new WebInspector.CallStackSidebarPane(); this.sidebarPanes.scopechain = new WebInspector.ScopeChainSidebarPane(); - this.sidebarPanes.jsBreakpoints = WebInspector.createJSBreakpointsSidebarPane(); + this.sidebarPanes.jsBreakpoints = new WebInspector.JavaScriptBreakpointsSidebarPane(); if (Preferences.nativeInstrumentationEnabled) { this.sidebarPanes.domBreakpoints = WebInspector.createDOMBreakpointsSidebarPane(); this.sidebarPanes.xhrBreakpoints = WebInspector.createXHRBreakpointsSidebarPane(); @@ -168,8 +177,6 @@ WebInspector.ScriptsPanel = function() this._pauseOnExceptionButton = new WebInspector.StatusBarButton("", "scripts-pause-on-exceptions-status-bar-item", 3); this._pauseOnExceptionButton.addEventListener("click", this._togglePauseOnExceptions.bind(this), false); - this._pauseOnExceptionButton.state = WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions; - this._pauseOnExceptionButton.title = WebInspector.UIString("Don't pause on exceptions.\nClick to Pause on all exceptions."); this._registerShortcuts(); @@ -179,6 +186,7 @@ WebInspector.ScriptsPanel = function() WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ParsedScriptSource, this._parsedScriptSource, this); WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.FailedToParseScriptSource, this._failedToParseScriptSource, this); + WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.ScriptSourceChanged, this._scriptSourceChanged, this); WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerPaused, this._debuggerPaused, this); WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.DebuggerResumed, this._debuggerResumed, this); } @@ -244,6 +252,27 @@ WebInspector.ScriptsPanel.prototype = { this._addScript(event.data); }, + _scriptSourceChanged: function(event) + { + var sourceID = event.data.sourceID; + var oldSource = event.data.oldSource; + + var script = WebInspector.debuggerModel.scriptForSourceID(sourceID); + var oldView = script._scriptView; + if (oldView) { + script._scriptView = new WebInspector.ScriptView(script); + this.viewRecreated(oldView, script._scriptView); + } + if (script.resource) { + var revertHandle = WebInspector.debuggerModel.editScriptSource.bind(WebInspector.debuggerModel, sourceID, oldSource); + script.resource.setContent(script.source, revertHandle); + } + + var callFrames = WebInspector.debuggerModel.callFrames; + if (callFrames.length) + this._debuggerPaused({ data: { callFrames: callFrames } }); + }, + _addScript: function(script) { var resource = WebInspector.resourceForURL(script.sourceURL); @@ -279,52 +308,6 @@ WebInspector.ScriptsPanel.prototype = { delete resource._scriptsPendingResourceLoad; }, - canEditScripts: function() - { - return Preferences.canEditScriptSource; - }, - - editScriptSource: function(editData, revertEditingCallback, cancelEditingCallback) - { - if (!this.canEditScripts()) - return; - - // Need to clear breakpoints and re-create them later when editing source. - var breakpoints = WebInspector.debuggerModel.queryBreakpoints(function(b) { return b.sourceID === editData.sourceID }); - for (var i = 0; i < breakpoints.length; ++i) - breakpoints[i].remove(); - - function mycallback(success, newBodyOrErrorMessage, callFrames) - { - if (success) { - var script = WebInspector.debuggerModel.scriptForSourceID(editData.sourceID); - script.source = newBodyOrErrorMessage; - var oldView = script._scriptView - if (oldView) { - script._scriptView = new WebInspector.ScriptView(script); - this.viewRecreated(oldView, script._scriptView); - } - if (script.resource) - script.resource.setContent(newBodyOrErrorMessage, revertEditingCallback); - - if (callFrames && callFrames.length) - this._debuggerPaused({ data: { callFrames: callFrames } }); - } else { - if (cancelEditingCallback) - cancelEditingCallback(); - WebInspector.log(newBodyOrErrorMessage, WebInspector.ConsoleMessage.MessageLevel.Warning); - } - for (var i = 0; i < breakpoints.length; ++i) { - var breakpoint = breakpoints[i]; - var newLine = breakpoint.line; - if (success && breakpoint.line >= editData.line) - newLine += editData.linesCountToShift; - WebInspector.debuggerModel.setBreakpoint(editData.sourceID, newLine, breakpoint.enabled, breakpoint.condition); - } - }; - InspectorBackend.editScriptSource(editData.sourceID, editData.content, mycallback.bind(this)); - }, - selectedCallFrameId: function() { var selectedCallFrame = this.sidebarPanes.callstack.selectedCallFrame; @@ -359,7 +342,7 @@ WebInspector.ScriptsPanel.prototype = { if (result) callback(WebInspector.RemoteObject.fromPayload(result)); } - InjectedScriptAccess.get(callFrame.worldId).evaluateInCallFrame(callFrame.id, code, objectGroup, evalCallback); + InspectorBackend.evaluateOnCallFrame(callFrame.id, code, objectGroup, evalCallback); }, _debuggerPaused: function(event) @@ -392,9 +375,10 @@ WebInspector.ScriptsPanel.prototype = { debuggerWasEnabled: function() { + this._setPauseOnExceptions(WebInspector.settings.pauseOnExceptionState); + if (this._debuggerEnabled) return; - this._debuggerEnabled = true; this.reset(true); }, @@ -677,7 +661,7 @@ WebInspector.ScriptsPanel.prototype = { _clearCurrentExecutionLine: function() { if (this._executionSourceFrame) - this._executionSourceFrame.executionLine = 0; + this._executionSourceFrame.clearExecutionLine(); delete this._executionSourceFrame; }, @@ -699,7 +683,7 @@ WebInspector.ScriptsPanel.prototype = { this._executionSourceFrame = this._sourceFrameForScriptOrResource(scriptOrResource); if (this._executionSourceFrame) - this._executionSourceFrame.executionLine = currentFrame.line; + this._executionSourceFrame.setExecutionLine(currentFrame.line); }, _changeVisibleFile: function(event) @@ -744,16 +728,21 @@ WebInspector.ScriptsPanel.prototype = { this.resize(); }, - updatePauseOnExceptionsState: function(pauseOnExceptionsState) + _setPauseOnExceptions: function(pauseOnExceptionsState) { - if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions) - this._pauseOnExceptionButton.title = WebInspector.UIString("Don't pause on exceptions.\nClick to Pause on all exceptions."); - else if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnAllExceptions) - this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on all exceptions.\nClick to Pause on uncaught exceptions."); - else if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnUncaughtExceptions) - this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on uncaught exceptions.\nClick to Not pause on exceptions."); - - this._pauseOnExceptionButton.state = pauseOnExceptionsState; + function callback(pauseOnExceptionsState) + { + if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions) + this._pauseOnExceptionButton.title = WebInspector.UIString("Don't pause on exceptions.\nClick to Pause on all exceptions."); + else if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnAllExceptions) + this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on all exceptions.\nClick to Pause on uncaught exceptions."); + else if (pauseOnExceptionsState == WebInspector.ScriptsPanel.PauseOnExceptionsState.PauseOnUncaughtExceptions) + this._pauseOnExceptionButton.title = WebInspector.UIString("Pause on uncaught exceptions.\nClick to Not pause on exceptions."); + + this._pauseOnExceptionButton.state = pauseOnExceptionsState; + WebInspector.settings.pauseOnExceptionState = pauseOnExceptionsState; + } + InspectorBackend.setPauseOnExceptionsState(pauseOnExceptionsState, callback.bind(this)); }, _updateDebuggerButtons: function() @@ -833,6 +822,12 @@ WebInspector.ScriptsPanel.prototype = { this._updateBackAndForwardButtons(); }, + _formatScript: function() + { + if (this.visibleView && this.visibleView.sourceFrame) + this.visibleView.sourceFrame.formatSource(); + }, + _enableDebugging: function() { if (this._debuggerEnabled) @@ -854,7 +849,7 @@ WebInspector.ScriptsPanel.prototype = { _togglePauseOnExceptions: function() { - InspectorBackend.setPauseOnExceptionsState((this._pauseOnExceptionButton.state + 1) % this._pauseOnExceptionButton.states, this.updatePauseOnExceptionsState.bind(this)); + this._setPauseOnExceptions((this._pauseOnExceptionButton.state + 1) % this._pauseOnExceptionButton.states); }, _togglePause: function() diff --git a/Source/WebCore/inspector/front-end/Settings.js b/Source/WebCore/inspector/front-end/Settings.js index bc50ce9..e26b1d7 100644 --- a/Source/WebCore/inspector/front-end/Settings.js +++ b/Source/WebCore/inspector/front-end/Settings.js @@ -65,6 +65,7 @@ WebInspector.Settings = function() this.installApplicationSetting("showUserAgentStyles", true); this.installApplicationSetting("watchExpressions", []); this.installApplicationSetting("lastActivePanel", "elements"); + this.installApplicationSetting("pauseOnExceptionState", WebInspector.ScriptsPanel.PauseOnExceptionsState.DontPauseOnExceptions); this.installProjectSetting("breakpoints", {}); this.installProjectSetting("nativeBreakpoints", []); diff --git a/Source/WebCore/inspector/front-end/SourceFrame.js b/Source/WebCore/inspector/front-end/SourceFrame.js index af10f1e..eb89f24 100644 --- a/Source/WebCore/inspector/front-end/SourceFrame.js +++ b/Source/WebCore/inspector/front-end/SourceFrame.js @@ -28,12 +28,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.SourceFrame = function(parentElement, contentProvider, url, canEditScripts) +WebInspector.SourceFrame = function(parentElement, contentProvider, url, isScript) { this._parentElement = parentElement; this._contentProvider = contentProvider; this._url = url; - this._canEditScripts = canEditScripts; + this._isScript = isScript; + this._textModel = new WebInspector.TextEditorModel(); this._textModel.replaceTabsWithSpaces = true; @@ -71,23 +72,6 @@ WebInspector.SourceFrame.prototype = { } }, - get executionLine() - { - return this._executionLine; - }, - - set executionLine(x) - { - if (this._executionLine === x) - return; - - var previousLine = this._executionLine; - this._executionLine = x; - - if (this._textViewer) - this._updateExecutionLine(previousLine); - }, - markDiff: function(diffData) { if (this._diffLines && this._textViewer) @@ -172,6 +156,7 @@ WebInspector.SourceFrame.prototype = { { this._content = content; this._textModel.setText(null, content); + this._formatter = new WebInspector.ScriptFormatter(content); this._textViewer = new WebInspector.TextViewer(this._textModel, WebInspector.platform, this._url); var element = this._textViewer.element; @@ -179,15 +164,13 @@ WebInspector.SourceFrame.prototype = { element.addEventListener("mousedown", this._mouseDown.bind(this), true); element.addEventListener("mousemove", this._mouseMove.bind(this), true); element.addEventListener("scroll", this._scroll.bind(this), true); + element.addEventListener("dblclick", this._doubleClick.bind(this), true); this._parentElement.appendChild(element); this._textViewer.beginUpdates(); this._textViewer.mimeType = mimeType; - this._addExistingMessagesToSource(); - this._updateExecutionLine(); - this._updateDiffDecorations(); - this._textViewer.resize(); + this._setTextViewerDecorations(); if (this._lineNumberToReveal) { this.revealLine(this._lineNumberToReveal); @@ -210,15 +193,34 @@ WebInspector.SourceFrame.prototype = { delete this._delayedFindSearchMatches; } + this._textViewer.endUpdates(); + + WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointAdded, this._breakpointAdded, this); + + if (this._canEditScripts) + this._textViewer.editCallback = this._editLine.bind(this); + }, + + _setTextViewerDecorations: function() + { + this._rowMessages = {}; + this._messageBubbles = {}; + + this._textViewer.beginUpdates(); + + this._addExistingMessagesToSource(); + this._updateDiffDecorations(); + + if (this._executionLine) + this.setExecutionLine(this._executionLine); + var breakpoints = this._breakpoints(); for (var i = 0; i < breakpoints.length; ++i) this._addBreakpoint(breakpoints[i]); - WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointAdded, this._breakpointAdded, this); - this._textViewer.endUpdates(); + this._textViewer.resize(); - if (this._canEditScripts) - this._textViewer.editCallback = this._editLine.bind(this); + this._textViewer.endUpdates(); }, findSearchMatches: function(query, finishedCallback) @@ -300,18 +302,22 @@ WebInspector.SourceFrame.prototype = { msg._resourceMessageRepeatCountElement.textContent = WebInspector.UIString(" (repeated %d times)", msg.repeatCount); }, - _updateExecutionLine: function(previousLine) + setExecutionLine: function(lineNumber) { - if (previousLine) { - if (previousLine - 1 < this._textModel.linesCount) - this._textViewer.removeDecoration(previousLine - 1, "webkit-execution-line"); - } - - if (!this._executionLine) + this._executionLine = lineNumber; + if (!this._textViewer) return; + var textViewerLineNumber = this._formatter.originalLineNumberToFormattedLineNumber(this._executionLine - 1); + this._textViewer.addDecoration(textViewerLineNumber, "webkit-execution-line"); + }, - if (this._executionLine < this._textModel.linesCount) - this._textViewer.addDecoration(this._executionLine - 1, "webkit-execution-line"); + clearExecutionLine: function() + { + if (!this._textViewer) + return; + var textViewerLineNumber = this._formatter.originalLineNumberToFormattedLineNumber(this._executionLine - 1); + this._textViewer.removeDecoration(textViewerLineNumber, "webkit-execution-line"); + delete this._executionLine; }, _updateDiffDecorations: function() @@ -412,14 +418,15 @@ WebInspector.SourceFrame.prototype = { _addBreakpoint: function(breakpoint) { - if (breakpoint.line > this._textModel.linesCount) + var textViewerLineNumber = this._formatter.originalLineNumberToFormattedLineNumber(breakpoint.line - 1); + if (textViewerLineNumber >= this._textModel.linesCount) return; breakpoint.addEventListener("enable-changed", this._breakpointChanged, this); breakpoint.addEventListener("condition-changed", this._breakpointChanged, this); breakpoint.addEventListener("removed", this._breakpointRemoved, this); - this._setBreakpointDecoration(breakpoint.line, breakpoint.enabled, !!breakpoint.condition); + this._setBreakpointDecoration(textViewerLineNumber, breakpoint.enabled, !!breakpoint.condition); }, _breakpointRemoved: function(event) @@ -430,18 +437,19 @@ WebInspector.SourceFrame.prototype = { breakpoint.removeEventListener("condition-changed", null, this); breakpoint.removeEventListener("removed", null, this); - this._removeBreakpointDecoration(breakpoint.line); + var textViewerLineNumber = this._formatter.originalLineNumberToFormattedLineNumber(breakpoint.line - 1); + this._removeBreakpointDecoration(textViewerLineNumber); }, _breakpointChanged: function(event) { var breakpoint = event.target; - this._setBreakpointDecoration(breakpoint.line, breakpoint.enabled, !!breakpoint.condition); + var textViewerLineNumber = this._formatter.originalLineNumberToFormattedLineNumber(breakpoint.line - 1); + this._setBreakpointDecoration(textViewerLineNumber, breakpoint.enabled, !!breakpoint.condition); }, _setBreakpointDecoration: function(lineNumber, enabled, hasCondition) { - lineNumber -= 1; this._textViewer.beginUpdates(); this._textViewer.addDecoration(lineNumber, "webkit-breakpoint"); if (enabled) @@ -457,7 +465,6 @@ WebInspector.SourceFrame.prototype = { _removeBreakpointDecoration: function(lineNumber) { - lineNumber -= 1; this._textViewer.beginUpdates(); this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint"); this._textViewer.removeDecoration(lineNumber, "webkit-breakpoint-disabled"); @@ -473,27 +480,28 @@ WebInspector.SourceFrame.prototype = { var target = event.target.enclosingNodeOrSelfWithClass("webkit-line-number"); if (!target) return; - var lineNumber = target.parentElement.lineNumber + 1; + var textViewerLineNumber = target.parentElement.lineNumber; + var originalLineNumber = this._formatter.formattedLineNumberToOriginalLineNumber(textViewerLineNumber); var contextMenu = new WebInspector.ContextMenu(); - contextMenu.appendItem(WebInspector.UIString("Continue to Here"), this._continueToLine.bind(this, lineNumber)); + contextMenu.appendItem(WebInspector.UIString("Continue to Here"), this._continueToLine.bind(this, originalLineNumber)); - var breakpoint = this._findBreakpoint(lineNumber); + var breakpoint = this._findBreakpoint(originalLineNumber); if (!breakpoint) { // This row doesn't have a breakpoint: We want to show Add Breakpoint and Add and Edit Breakpoint. - contextMenu.appendItem(WebInspector.UIString("Add Breakpoint"), this._setBreakpoint.bind(this, lineNumber, "", true)); + contextMenu.appendItem(WebInspector.UIString("Add Breakpoint"), this._setBreakpoint.bind(this, originalLineNumber, "", true)); function addConditionalBreakpoint() { - this._setBreakpointDecoration(lineNumber, true, true); + this._setBreakpointDecoration(textViewerLineNumber, true, true); function didEditBreakpointCondition(committed, condition) { - this._removeBreakpointDecoration(lineNumber); + this._removeBreakpointDecoration(textViewerLineNumber); if (committed) - this._setBreakpoint(lineNumber, true, condition); + this._setBreakpoint(originalLineNumber, true, condition); } - this._editBreakpointCondition(lineNumber, "", didEditBreakpointCondition.bind(this)); + this._editBreakpointCondition(textViewerLineNumber, "", didEditBreakpointCondition.bind(this)); } contextMenu.appendItem(WebInspector.UIString("Add Conditional Breakpoint…"), addConditionalBreakpoint.bind(this)); } else { @@ -505,16 +513,16 @@ WebInspector.SourceFrame.prototype = { { if (committed) { breakpoint.remove(); - this._setBreakpoint(breakpoint.line, breakpoint.enabled, condition); + this._setBreakpoint(originalLineNumber, breakpoint.enabled, condition); } } - this._editBreakpointCondition(lineNumber, breakpoint.condition, didEditBreakpointCondition.bind(this)); + this._editBreakpointCondition(textViewerLineNumber, breakpoint.condition, didEditBreakpointCondition.bind(this)); } contextMenu.appendItem(WebInspector.UIString("Edit Breakpoint…"), editBreakpointCondition.bind(this)); function setBreakpointEnabled(enabled) { breakpoint.remove(); - this._setBreakpoint(breakpoint.line, enabled, breakpoint.condition); + this._setBreakpoint(originalLineNumber, enabled, breakpoint.condition); } if (breakpoint.enabled) contextMenu.appendItem(WebInspector.UIString("Disable Breakpoint"), setBreakpointEnabled.bind(this, false)); @@ -538,15 +546,15 @@ WebInspector.SourceFrame.prototype = { var target = event.target.enclosingNodeOrSelfWithClass("webkit-line-number"); if (!target) return; - var lineNumber = target.parentElement.lineNumber + 1; + var originalLineNumber = this._formatter.formattedLineNumberToOriginalLineNumber(target.parentElement.lineNumber); - var breakpoint = this._findBreakpoint(lineNumber); + var breakpoint = this._findBreakpoint(originalLineNumber); if (breakpoint) { breakpoint.remove(); if (event.shiftKey) - this._setBreakpoint(breakpoint.line, !breakpoint.enabled, breakpoint.condition); + this._setBreakpoint(originalLineNumber, !breakpoint.enabled, breakpoint.condition); } else - this._setBreakpoint(lineNumber, true, ""); + this._setBreakpoint(originalLineNumber, true, ""); event.preventDefault(); }, @@ -710,7 +718,6 @@ WebInspector.SourceFrame.prototype = { _editBreakpointCondition: function(lineNumber, condition, callback) { - lineNumber -= 1; this._conditionElement = this._createConditionElement(lineNumber); this._textViewer.addDecoration(lineNumber, this._conditionElement); @@ -776,49 +783,55 @@ WebInspector.SourceFrame.prototype = { this._textViewer.resize(); }, + formatSource: function() + { + if (!this._formatter) + return; + + function didFormat(source) + { + this._textModel.setText(null, source); + this._setTextViewerDecorations(); + } + this._formatter.format(didFormat.bind(this)); + }, + _continueToLine: function(lineNumber) { var sourceID = this._sourceIDForLine(lineNumber); if (!sourceID) return; - WebInspector.debuggerModel.continueToLine(sourceID, lineNumber); + WebInspector.debuggerModel.continueToLine(sourceID, lineNumber + 1); }, - _editLine: function(lineNumber, newContent, cancelEditingCallback) + _doubleClick: function(event) { - lineNumber += 1; - - var lines = []; - var oldLines = this._content.split('\n'); - for (var i = 0; i < oldLines.length; ++i) { - if (i === lineNumber - 1) - lines.push(newContent); - else - lines.push(oldLines[i]); - } + if (!Preferences.canEditScriptSource || !this._isScript) + return; - var editData = {}; - editData.sourceID = this._sourceIDForLine(lineNumber); - editData.content = lines.join("\n"); - editData.line = lineNumber; - editData.linesCountToShift = newContent.split("\n").length - 1; - this._doEditLine(editData, cancelEditingCallback); - }, + var target = event.target.enclosingNodeOrSelfWithNodeName("TD"); + if (!target || target.parentElement.firstChild === target) + return; // Do not trigger editing from line numbers. - _revertEditLine: function(editData, contentToRevertTo) - { - var newEditData = {}; - newEditData.sourceID = editData.sourceID; - newEditData.content = contentToRevertTo; - newEditData.line = editData.line; - newEditData.linesCountToShift = -editData.linesCountToShift; - this._doEditLine(newEditData); - }, + var lineRow = target.parentElement; + var lineNumber = lineRow.lineNumber; + var sourceID = this._sourceIDForLine(lineNumber); + if (!sourceID) + return; - _doEditLine: function(editData, cancelEditingCallback) - { - var revertEditingCallback = this._revertEditLine.bind(this, editData); - WebInspector.panels.scripts.editScriptSource(editData, revertEditingCallback, cancelEditingCallback); + function didEditLine(newContent) + { + var lines = []; + var oldLines = this._content.split('\n'); + for (var i = 0; i < oldLines.length; ++i) { + if (i === lineNumber) + lines.push(newContent); + else + lines.push(oldLines[i]); + } + WebInspector.debuggerModel.editScriptSource(sourceID, lines.join("\n")); + } + this._textViewer.editLine(lineRow, didEditLine.bind(this)); }, _setBreakpoint: function(lineNumber, enabled, condition) @@ -826,7 +839,7 @@ WebInspector.SourceFrame.prototype = { var sourceID = this._sourceIDForLine(lineNumber); if (!sourceID) return; - WebInspector.debuggerModel.setBreakpoint(sourceID, lineNumber, enabled, condition); + WebInspector.debuggerModel.setBreakpoint(sourceID, lineNumber + 1, enabled, condition); if (!WebInspector.panels.scripts.breakpointsActivated) WebInspector.panels.scripts.toggleBreakpointsClicked(); }, @@ -840,7 +853,7 @@ WebInspector.SourceFrame.prototype = { _findBreakpoint: function(lineNumber) { var sourceID = this._sourceIDForLine(lineNumber); - return WebInspector.debuggerModel.findBreakpoint(sourceID, lineNumber); + return WebInspector.debuggerModel.findBreakpoint(sourceID, lineNumber + 1); }, _sourceIDForLine: function(lineNumber) @@ -849,9 +862,9 @@ WebInspector.SourceFrame.prototype = { var closestStartingLine = 0; var scripts = this._contentProvider.scripts(); for (var i = 0; i < scripts.length; ++i) { - var startingLine = scripts[i].startingLine; - if (startingLine <= lineNumber && startingLine >= closestStartingLine) { - closestStartingLine = startingLine; + var lineOffset = scripts[i].lineOffset; + if (lineOffset <= lineNumber && lineOffset >= closestStartingLine) { + closestStartingLine = lineOffset; sourceIDForLine = scripts[i].sourceID; } } diff --git a/Source/WebCore/inspector/front-end/SourceView.js b/Source/WebCore/inspector/front-end/SourceView.js index e78ff94..37caabb 100644 --- a/Source/WebCore/inspector/front-end/SourceView.js +++ b/Source/WebCore/inspector/front-end/SourceView.js @@ -33,8 +33,8 @@ WebInspector.SourceView = function(resource) this.element.addStyleClass("source"); var contentProvider = new WebInspector.SourceFrameContentProviderForResource(resource); - var canEditScripts = WebInspector.panels.scripts.canEditScripts() && resource.type === WebInspector.Resource.Type.Script; - this.sourceFrame = new WebInspector.SourceFrame(this.element, contentProvider, resource.url, canEditScripts); + var isScript = resource.type === WebInspector.Resource.Type.Script; + this.sourceFrame = new WebInspector.SourceFrame(this.element, contentProvider, resource.url, isScript); } WebInspector.SourceView.prototype = { diff --git a/Source/WebCore/inspector/front-end/StylesSidebarPane.js b/Source/WebCore/inspector/front-end/StylesSidebarPane.js index d646829..9880adc 100644 --- a/Source/WebCore/inspector/front-end/StylesSidebarPane.js +++ b/Source/WebCore/inspector/front-end/StylesSidebarPane.js @@ -81,6 +81,8 @@ WebInspector.StylesSidebarPane = function(computedStylePane) this.element.addEventListener("contextmenu", this._contextMenuEventFired.bind(this), true); } +WebInspector.StylesSidebarPane.StyleValueDelimiters = " \t\n\"':;,/()"; + // Taken from http://www.w3.org/TR/CSS21/propidx.html. WebInspector.StylesSidebarPane.InheritedProperties = [ "azimuth", "border-collapse", "border-spacing", "caption-side", "color", "cursor", "direction", "elevation", @@ -1379,6 +1381,8 @@ WebInspector.StylePropertyTreeElement.prototype = { } this.listItemElement.removeChildren(); + nameElement.normalize(); + valueElement.normalize(); if (!this.treeOutline) return; @@ -1529,16 +1533,15 @@ WebInspector.StylePropertyTreeElement.prototype = { var context = { expanded: this.expanded, hasChildren: this.hasChildren, - keyDownListener: isEditingName ? this.editingNameKeyDown.bind(this) : this.editingValueKeyDown.bind(this), - keyPressListener: isEditingName ? this.editingNameKeyPress.bind(this) : this.editingValueKeyPress.bind(this), + keyDownListener: isEditingName ? null : this.editingValueKeyDown.bind(this), isEditingName: isEditingName, }; // Lie about our children to prevent expanding on double click and to collapse shorthands. this.hasChildren = false; - selectElement.addEventListener("keydown", context.keyDownListener, false); - selectElement.addEventListener("keypress", context.keyPressListener, false); + if (!isEditingName) + selectElement.addEventListener("keydown", context.keyDownListener, false); if (selectElement.parentElement) selectElement.parentElement.addStyleClass("child-editing"); selectElement.textContent = selectElement.textContent; // remove color swatch and the like @@ -1613,76 +1616,15 @@ WebInspector.StylePropertyTreeElement.prototype = { customFinishHandler: nameValueFinishHandler.bind(this, context, isEditingName), pasteHandler: isEditingName ? pasteHandler.bind(this, context) : null }); - window.getSelection().setBaseAndExtent(selectElement, 0, selectElement, 1); - }, - - editingNameKeyPress: function(event) - { - // Complete property names. - var character = event.data.toLowerCase(); - if (character && /[a-z-]/.test(character)) { - var selection = window.getSelection(); - var prefix = selection.anchorNode.textContent.substring(0, selection.anchorOffset); - var property = WebInspector.cssNameCompletions.firstStartsWith(prefix + character); - if (!selection.isCollapsed) - selection.deleteFromDocument(); - - this.restoreNameElement(); - - if (property) { - if (property !== this.nameElement.textContent) - this.nameElement.textContent = property; - this.nameElement.firstChild.select(prefix.length + 1); - event.preventDefault(); - } - } - }, - - editingValueKeyPress: function(event) - { - // FIXME: This should complete property values. - }, - - editingNameKeyDown: function(event) - { - var showNext; - if (event.keyIdentifier === "Up") - showNext = false; - else if (event.keyIdentifier === "Down") - showNext = true; - else - return; - - var selection = window.getSelection(); - if (!selection.rangeCount) - return; - - var selectionRange = selection.getRangeAt(0); - if (selectionRange.commonAncestorContainer !== this.nameElement && !selectionRange.commonAncestorContainer.isDescendant(this.nameElement)) - return; - - const styleValueDelimeters = " \t\n\"':;,/()"; - var wordRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, styleValueDelimeters, this.nameElement); - var wordString = wordRange.toString(); - var cursorPosition = selectionRange.startOffset != selectionRange.endOffset ? selectionRange.startOffset : 0; - var prefix = selectionRange.startContainer.textContent.substring(0, cursorPosition); - var property; - - if (showNext) - property = WebInspector.cssNameCompletions.next(wordString, prefix); - else - property = WebInspector.cssNameCompletions.previous(wordString, prefix); - - if (property) { - this.nameElement.textContent = property; - this.nameElement.firstChild.select(cursorPosition); - } - event.preventDefault(); + this._prompt = new WebInspector.StylesSidebarPane.CSSPropertyPrompt(selectElement, isEditingName ? WebInspector.cssNameCompletions : WebInspector.CSSKeywordCompletions.forProperty(this.nameElement.textContent)); + window.getSelection().setBaseAndExtent(selectElement, 0, selectElement, 1); }, editingValueKeyDown: function(event) { + if (event.handled) + return; var arrowKeyPressed = (event.keyIdentifier === "Up" || event.keyIdentifier === "Down"); var pageKeyPressed = (event.keyIdentifier === "PageUp" || event.keyIdentifier === "PageDown"); if (!arrowKeyPressed && !pageKeyPressed) @@ -1696,8 +1638,7 @@ WebInspector.StylePropertyTreeElement.prototype = { if (selectionRange.commonAncestorContainer !== this.valueElement && !selectionRange.commonAncestorContainer.isDescendant(this.valueElement)) return; - const styleValueDelimeters = " \t\n\"':;,/()"; - var wordRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, styleValueDelimeters, this.valueElement); + var wordRange = selectionRange.startContainer.rangeOfWord(selectionRange.startOffset, WebInspector.StylesSidebarPane.StyleValueDelimiters, this.valueElement); var wordString = wordRange.toString(); var replacementString = wordString; @@ -1739,42 +1680,45 @@ WebInspector.StylePropertyTreeElement.prototype = { } replacementString = prefix + number + suffix; - } else { - // FIXME: this should cycle through known keywords for the current property value. - } - var replacementTextNode = document.createTextNode(replacementString); + var replacementTextNode = document.createTextNode(replacementString); - wordRange.deleteContents(); - wordRange.insertNode(replacementTextNode); + wordRange.deleteContents(); + wordRange.insertNode(replacementTextNode); - var finalSelectionRange = document.createRange(); - finalSelectionRange.setStart(replacementTextNode, 0); - finalSelectionRange.setEnd(replacementTextNode, replacementString.length); + var finalSelectionRange = document.createRange(); + finalSelectionRange.setStart(replacementTextNode, 0); + finalSelectionRange.setEnd(replacementTextNode, replacementString.length); - selection.removeAllRanges(); - selection.addRange(finalSelectionRange); + selection.removeAllRanges(); + selection.addRange(finalSelectionRange); - event.preventDefault(); + event.handled = true; + event.preventDefault(); - if (!("originalPropertyText" in this)) { - // Remember the rule's original CSS text on [Page](Up|Down), so it can be restored - // if the editing is canceled. - this.originalPropertyText = this.property.propertyText; - } + if (!("originalPropertyText" in this)) { + // Remember the rule's original CSS text on [Page](Up|Down), so it can be restored + // if the editing is canceled. + this.originalPropertyText = this.property.propertyText; + } - // Synthesize property text disregarding any comments, custom whitespace etc. - this.applyStyleText(this.nameElement.textContent + ": " + this.valueElement.textContent); + // Synthesize property text disregarding any comments, custom whitespace etc. + this.applyStyleText(this.nameElement.textContent + ": " + this.valueElement.textContent); + } }, editingEnded: function(context) { + if (this._prompt) { + this._prompt.removeFromElement(); + delete this._prompt; + } this.hasChildren = context.hasChildren; if (context.expanded) this.expand(); var editedElement = context.isEditingName ? this.nameElement : this.valueElement; - editedElement.removeEventListener("keydown", context.keyDownListener, false); - editedElement.removeEventListener("keypress", context.keyPressListener, false); + if (!context.isEditingName) + editedElement.removeEventListener("keydown", context.keyDownListener, false); if (editedElement.parentElement) editedElement.parentElement.removeStyleClass("child-editing"); @@ -1791,6 +1735,8 @@ WebInspector.StylePropertyTreeElement.prototype = { else this.updateTitle(); } + + // This should happen last, as it clears the info necessary to restore the property value after [Page]Up/Down changes. this.editingEnded(context); }, @@ -1948,3 +1894,57 @@ WebInspector.StylePropertyTreeElement.prototype = { } WebInspector.StylePropertyTreeElement.prototype.__proto__ = TreeElement.prototype; + +WebInspector.StylesSidebarPane.CSSPropertyPrompt = function(element, cssCompletions) +{ + WebInspector.TextPrompt.call(this, element, this._buildPropertyCompletions.bind(this), WebInspector.StylesSidebarPane.StyleValueDelimiters, true); + this._cssCompletions = cssCompletions; +} + +WebInspector.StylesSidebarPane.CSSPropertyPrompt.prototype = { + upKeyPressed: function(event) + { + this._handleNameOrValueUpDown(event); + }, + + downKeyPressed: function(event) + { + this._handleNameOrValueUpDown(event); + }, + + tabKeyPressed: function(event) + { + this.acceptAutoComplete(); + }, + + _handleNameOrValueUpDown: function(event) + { + var reverse = event.keyIdentifier === "Up"; + if (this.autoCompleteElement) + this.complete(false, reverse); // Accept the current suggestion, if any. + this.complete(false, reverse); // Actually increment/decrement the suggestion. + event.handled = true; + }, + + _buildPropertyCompletions: function(wordRange, bestMatchOnly, completionsReadyCallback) + { + var prefix = wordRange.toString().toLowerCase(); + if (!prefix.length) + return; + + var results; + if (bestMatchOnly) { + results = []; + var firstMatch = this._cssCompletions.firstStartsWith(prefix); + if (firstMatch) + results.push(firstMatch); + return completionsReadyCallback(results); + } + + results = this._cssCompletions.startsWith(prefix); + if (results) + completionsReadyCallback(results); + } +} + +WebInspector.StylesSidebarPane.CSSPropertyPrompt.prototype.__proto__ = WebInspector.TextPrompt.prototype; diff --git a/Source/WebCore/inspector/front-end/TextPrompt.js b/Source/WebCore/inspector/front-end/TextPrompt.js index 21a5bde..ac54d8c 100644 --- a/Source/WebCore/inspector/front-end/TextPrompt.js +++ b/Source/WebCore/inspector/front-end/TextPrompt.js @@ -26,15 +26,18 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.TextPrompt = function(element, completions, stopCharacters) +WebInspector.TextPrompt = function(element, completions, stopCharacters, omitHistory) { this.element = element; this.element.addStyleClass("text-prompt"); this.completions = completions; this.completionStopCharacters = stopCharacters; - this.history = []; - this.historyOffset = 0; - this.element.addEventListener("keydown", this._onKeyDown.bind(this), true); + if (!omitHistory) { + this.history = []; + this.historyOffset = 0; + } + this._boundOnKeyDown = this._onKeyDown.bind(this); + this.element.addEventListener("keydown", this._boundOnKeyDown, true); } WebInspector.TextPrompt.prototype = { @@ -55,6 +58,12 @@ WebInspector.TextPrompt.prototype = { this.moveCaretToEndOfPrompt(); }, + removeFromElement: function() + { + this.clearAutoComplete(true); + this.element.removeEventListener("keydown", this._boundOnKeyDown, true); + }, + _onKeyDown: function(event) { function defaultAction() @@ -63,16 +72,20 @@ WebInspector.TextPrompt.prototype = { this.autoCompleteSoon(); } + if (event.handled) + return; + var handled = false; + switch (event.keyIdentifier) { case "Up": - this._upKeyPressed(event); + this.upKeyPressed(event); break; case "Down": - this._downKeyPressed(event); + this.downKeyPressed(event); break; case "U+0009": // Tab - this._tabKeyPressed(event); + this.tabKeyPressed(event); break; case "Right": case "End": @@ -85,7 +98,7 @@ WebInspector.TextPrompt.prototype = { case "Control": break; case "U+0050": // Ctrl+P = Previous - if (WebInspector.isMac() && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) { + if (this.history && WebInspector.isMac() && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) { handled = true; this._moveBackInHistory(); break; @@ -93,7 +106,7 @@ WebInspector.TextPrompt.prototype = { defaultAction.call(this); break; case "U+004E": // Ctrl+N = Next - if (WebInspector.isMac() && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) { + if (this.history && WebInspector.isMac() && event.ctrlKey && !event.metaKey && !event.altKey && !event.shiftKey) { handled = true; this._moveForwardInHistory(); break; @@ -105,7 +118,9 @@ WebInspector.TextPrompt.prototype = { break; } + handled |= event.handled; if (handled) { + event.handled = true; event.preventDefault(); event.stopPropagation(); } @@ -376,39 +391,33 @@ WebInspector.TextPrompt.prototype = { selection.addRange(selectionRange); }, - _tabKeyPressed: function(event) + tabKeyPressed: function(event) { - event.preventDefault(); - event.stopPropagation(); - + event.handled = true; this.complete(false, event.shiftKey); }, - _upKeyPressed: function(event) + upKeyPressed: function(event) { if (!this.isCaretOnFirstLine()) return; - event.preventDefault(); - event.stopPropagation(); - + event.handled = true; this._moveBackInHistory(); }, - _downKeyPressed: function(event) + downKeyPressed: function(event) { if (!this.isCaretOnLastLine()) return; - event.preventDefault(); - event.stopPropagation(); - + event.handled = true; this._moveForwardInHistory(); }, _moveBackInHistory: function() { - if (this.historyOffset == this.history.length) + if (!this.history || this.historyOffset == this.history.length) return; this.clearAutoComplete(true); @@ -437,7 +446,7 @@ WebInspector.TextPrompt.prototype = { _moveForwardInHistory: function() { - if (this.historyOffset === 0) + if (!this.history || this.historyOffset === 0) return; this.clearAutoComplete(true); diff --git a/Source/WebCore/inspector/front-end/TextViewer.js b/Source/WebCore/inspector/front-end/TextViewer.js index f116dea..ea36513 100644 --- a/Source/WebCore/inspector/front-end/TextViewer.js +++ b/Source/WebCore/inspector/front-end/TextViewer.js @@ -43,7 +43,6 @@ WebInspector.TextViewer = function(textModel, platform, url) this.element.addEventListener("keydown", this._handleKeyDown.bind(this), false); this.element.addEventListener("beforecopy", this._beforeCopy.bind(this), false); this.element.addEventListener("copy", this._copy.bind(this), false); - this.element.addEventListener("dblclick", this._handleDoubleClick.bind(this), false); this._url = url; @@ -80,11 +79,6 @@ WebInspector.TextViewer.prototype = { chunk.element.scrollIntoViewIfNeeded(); }, - set editCallback(editCallback) - { - this._editCallback = editCallback; - }, - addDecoration: function(lineNumber, decoration) { var chunk = this._makeLineAChunk(lineNumber); @@ -231,20 +225,20 @@ WebInspector.TextViewer.prototype = { scrollValue = -1; else if (event.keyCode == WebInspector.KeyboardShortcut.Keys.Down.code) scrollValue = 1; - + if (scrollValue) { event.preventDefault(); event.stopPropagation(); this.element.scrollByLines(scrollValue); return; } - + scrollValue = 0; if (event.keyCode === WebInspector.KeyboardShortcut.Keys.Left.code) scrollValue = -40; else if (event.keyCode == WebInspector.KeyboardShortcut.Keys.Right.code) scrollValue = 40; - + if (scrollValue) { event.preventDefault(); event.stopPropagation(); @@ -252,42 +246,25 @@ WebInspector.TextViewer.prototype = { } }, - _handleDoubleClick: function(e) + editLine: function(lineRow, callback) { - if (!this._editCallback) - return; - - var cell = e.target.enclosingNodeOrSelfWithNodeName("TD"); - if (!cell) - return; - - var lineRow = cell.parentElement; - if (lineRow.firstChild === cell) - return; // Do not trigger editing from line numbers. - - var oldContent = lineRow.lastChild.innerHTML; - var cancelEditingCallback = this._cancelEditingLine.bind(this, lineRow.lastChild, oldContent); - var commitEditingCallback = this._commitEditingLine.bind(this, lineRow.lineNumber, lineRow.lastChild, cancelEditingCallback); - this._editingLine = WebInspector.startEditing(lineRow.lastChild, { + var element = lineRow.lastChild; + var oldContent = element.innerHTML; + function finishEditing(committed, e, newContent) + { + if (committed) + callback(newContent); + element.innerHTML = oldContent; + delete this._editingLine; + } + this._editingLine = WebInspector.startEditing(element, { context: null, - commitHandler: commitEditingCallback, - cancelHandler: cancelEditingCallback, + commitHandler: finishEditing.bind(this, true), + cancelHandler: finishEditing.bind(this, false), multiline: true }); }, - _commitEditingLine: function(lineNumber, element, cancelEditingCallback) - { - this._editCallback(lineNumber, element.textContent, cancelEditingCallback); - delete this._editingLine; - }, - - _cancelEditingLine: function(element, oldContent, e) - { - element.innerHTML = oldContent; - delete this._editingLine; - }, - _beforeCopy: function(e) { e.preventDefault(); @@ -786,7 +763,7 @@ WebInspector.TextChunk.prototype = { var lineContentElement = document.createElement("td"); lineContentElement.className = "webkit-line-content"; - lineRow.appendChild(lineContentElement); + lineRow.appendChild(lineContentElement); } lineRow.lineNumber = lineNumber; lineNumberElement.textContent = lineNumber + 1; diff --git a/Source/WebCore/inspector/front-end/UglifyJS/parse-js.js b/Source/WebCore/inspector/front-end/UglifyJS/parse-js.js new file mode 100644 index 0000000..a218c01 --- /dev/null +++ b/Source/WebCore/inspector/front-end/UglifyJS/parse-js.js @@ -0,0 +1,1233 @@ +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + + This version is suitable for Node.js. With minimal changes (the + exports stuff) it should work on any JS platform. + + This file contains the tokenizer/parser. It is a port to JavaScript + of parse-js [1], a JavaScript parser library written in Common Lisp + by Marijn Haverbeke. Thank you Marijn! + + [1] http://marijn.haverbeke.nl/parse-js/ + + Exported functions: + + - tokenizer(code) -- returns a function. Call the returned + function to fetch the next token. + + - parse(code) -- returns an AST of the given JavaScript code. + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + <mihai.bazon@gmail.com> + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com> + Based on parse-js (http://marijn.haverbeke.nl/parse-js/). + + 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. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 HOLDER 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. + + ***********************************************************************/ + +/* -----[ Tokenizer (constants) ]----- */ + +var KEYWORDS = array_to_hash([ + "break", + "case", + "catch", + "const", + "continue", + "default", + "delete", + "do", + "else", + "finally", + "for", + "function", + "if", + "in", + "instanceof", + "new", + "return", + "switch", + "throw", + "try", + "typeof", + "var", + "void", + "while", + "with" +]); + +var RESERVED_WORDS = array_to_hash([ + "abstract", + "boolean", + "byte", + "char", + "class", + "debugger", + "double", + "enum", + "export", + "extends", + "final", + "float", + "goto", + "implements", + "import", + "int", + "interface", + "long", + "native", + "package", + "private", + "protected", + "public", + "short", + "static", + "super", + "synchronized", + "throws", + "transient", + "volatile" +]); + +var KEYWORDS_BEFORE_EXPRESSION = array_to_hash([ + "return", + "new", + "delete", + "throw", + "else", + "case" +]); + +var KEYWORDS_ATOM = array_to_hash([ + "false", + "null", + "true", + "undefined" +]); + +var OPERATOR_CHARS = array_to_hash(characters("+-*&%=<>!?|~^")); + +var RE_HEX_NUMBER = /^0x[0-9a-f]+$/i; +var RE_OCT_NUMBER = /^0[0-7]+$/; +var RE_DEC_NUMBER = /^\d*\.?\d*(?:e[+-]?\d*(?:\d\.?|\.?\d)\d*)?$/i; + +var OPERATORS = array_to_hash([ + "in", + "instanceof", + "typeof", + "new", + "void", + "delete", + "++", + "--", + "+", + "-", + "!", + "~", + "&", + "|", + "^", + "*", + "/", + "%", + ">>", + "<<", + ">>>", + "<", + ">", + "<=", + ">=", + "==", + "===", + "!=", + "!==", + "?", + "=", + "+=", + "-=", + "/=", + "*=", + "%=", + ">>=", + "<<=", + ">>>=", + "~=", + "%=", + "|=", + "^=", + "&=", + "&&", + "||" +]); + +var WHITESPACE_CHARS = array_to_hash(characters(" \n\r\t")); + +var PUNC_BEFORE_EXPRESSION = array_to_hash(characters("[{}(,.;:")); + +var PUNC_CHARS = array_to_hash(characters("[]{}(),;:")); + +var REGEXP_MODIFIERS = array_to_hash(characters("gmsiy")); + +/* -----[ Tokenizer ]----- */ + +function is_alphanumeric_char(ch) { + ch = ch.charCodeAt(0); + return (ch >= 48 && ch <= 57) || + (ch >= 65 && ch <= 90) || + (ch >= 97 && ch <= 122); +}; + +function is_identifier_char(ch) { + return is_alphanumeric_char(ch) || ch == "$" || ch == "_"; +}; + +function is_digit(ch) { + ch = ch.charCodeAt(0); + return ch >= 48 && ch <= 57; +}; + +function parse_js_number(num) { + if (RE_HEX_NUMBER.test(num)) { + return parseInt(num.substr(2), 16); + } else if (RE_OCT_NUMBER.test(num)) { + return parseInt(num.substr(1), 8); + } else if (RE_DEC_NUMBER.test(num)) { + return parseFloat(num); + } +}; + +function JS_Parse_Error(message, line, col, pos) { + this.message = message; + this.line = line; + this.col = col; + this.pos = pos; + try { + ({})(); + } catch(ex) { + this.stack = ex.stack; + }; +}; + +JS_Parse_Error.prototype.toString = function() { + return this.message + " (line: " + this.line + ", col: " + this.col + ", pos: " + this.pos + ")" + "\n\n" + this.stack; +}; + +function js_error(message, line, col, pos) { + throw new JS_Parse_Error(message, line, col, pos); +}; + +function is_token(token, type, val) { + return token.type == type && (val == null || token.value == val); +}; + +var EX_EOF = {}; + +function tokenizer($TEXT, skip_comments) { + + var S = { + text : $TEXT.replace(/\r\n?|[\n\u2028\u2029]/g, "\n").replace(/^\uFEFF/, ''), + pos : 0, + tokpos : 0, + line : 0, + tokline : 0, + col : 0, + tokcol : 0, + newline_before : false, + regex_allowed : false + }; + + function peek() { return S.text.charAt(S.pos); }; + + function next(signal_eof) { + var ch = S.text.charAt(S.pos++); + if (signal_eof && !ch) + throw EX_EOF; + if (ch == "\n") { + S.newline_before = true; + ++S.line; + S.col = 0; + } else { + ++S.col; + } + return ch; + }; + + function eof() { + return !S.peek(); + }; + + function find(what, signal_eof) { + var pos = S.text.indexOf(what, S.pos); + if (signal_eof && pos == -1) throw EX_EOF; + return pos; + }; + + function start_token() { + S.tokline = S.line; + S.tokcol = S.col; + S.tokpos = S.pos; + }; + + function token(type, value) { + S.regex_allowed = ((type == "operator" && !HOP(UNARY_POSTFIX, value)) || + (type == "keyword" && HOP(KEYWORDS_BEFORE_EXPRESSION, value)) || + (type == "punc" && HOP(PUNC_BEFORE_EXPRESSION, value))); + var ret = { + type : type, + value : value, + line : S.tokline, + col : S.tokcol, + pos : S.tokpos, + nlb : S.newline_before + }; + S.newline_before = false; + return ret; + }; + + function skip_whitespace() { + while (HOP(WHITESPACE_CHARS, peek())) + next(); + }; + + function read_while(pred) { + var ret = "", ch = peek(), i = 0; + while (ch && pred(ch, i++)) { + ret += next(); + ch = peek(); + } + return ret; + }; + + function parse_error(err) { + js_error(err, S.tokline, S.tokcol, S.tokpos); + }; + + function read_num(prefix) { + var has_e = false, after_e = false, has_x = false; + var num = read_while(function(ch, i){ + if (ch == "x" || ch == "X") { + if (has_x) return false; + return has_x = true; + } + if (!has_x && (ch == "E" || ch == "e")) { + if (has_e) return false; + return has_e = after_e = true; + } + if (ch == "-") { + if (after_e || (i == 0 && !prefix)) return true; + return false; + } + if (ch == "+") return after_e; + after_e = false; + return is_alphanumeric_char(ch) || ch == "."; + }); + if (prefix) + num = prefix + num; + var valid = parse_js_number(num); + if (!isNaN(valid)) { + return token("num", valid); + } else { + parse_error("Invalid syntax: " + num); + } + }; + + function read_escaped_char() { + var ch = next(true); + switch (ch) { + case "n" : return "\n"; + case "r" : return "\r"; + case "t" : return "\t"; + case "b" : return "\b"; + case "v" : return "\v"; + case "f" : return "\f"; + case "0" : return "\0"; + case "x" : return String.fromCharCode(hex_bytes(2)); + case "u" : return String.fromCharCode(hex_bytes(4)); + default : return ch; + } + }; + + function hex_bytes(n) { + var num = 0; + for (; n > 0; --n) { + var digit = parseInt(next(true), 16); + if (isNaN(digit)) + parse_error("Invalid hex-character pattern in string"); + num = (num << 4) | digit; + } + return num; + }; + + function read_string() { + return with_eof_error("Unterminated string constant", function(){ + var quote = next(), ret = ""; + for (;;) { + var ch = next(true); + if (ch == "\\") ch = read_escaped_char(); + else if (ch == quote) break; + ret += ch; + } + return token("string", ret); + }); + }; + + function read_line_comment() { + next(); + var i = find("\n"), ret; + if (i == -1) { + ret = S.text.substr(S.pos); + S.pos = S.text.length; + } else { + ret = S.text.substring(S.pos, i); + S.pos = i; + } + return token("comment1", ret); + }; + + function read_multiline_comment() { + next(); + return with_eof_error("Unterminated multiline comment", function(){ + var i = find("*/", true), + text = S.text.substring(S.pos, i), + tok = token("comment2", text); + S.pos = i + 2; + S.newline_before = text.indexOf("\n") >= 0; + return tok; + }); + }; + + function read_regexp() { + return with_eof_error("Unterminated regular expression", function(){ + var prev_backslash = false, regexp = "", ch, in_class = false; + while ((ch = next(true))) if (prev_backslash) { + regexp += "\\" + ch; + prev_backslash = false; + } else if (ch == "[") { + in_class = true; + regexp += ch; + } else if (ch == "]" && in_class) { + in_class = false; + regexp += ch; + } else if (ch == "/" && !in_class) { + break; + } else if (ch == "\\") { + prev_backslash = true; + } else { + regexp += ch; + } + var mods = read_while(function(ch){ + return HOP(REGEXP_MODIFIERS, ch); + }); + return token("regexp", [ regexp, mods ]); + }); + }; + + function read_operator(prefix) { + function grow(op) { + var bigger = op + peek(); + if (HOP(OPERATORS, bigger)) { + next(); + return grow(bigger); + } else { + return op; + } + }; + return token("operator", grow(prefix || next())); + }; + + var handle_slash = skip_comments ? function() { + next(); + var regex_allowed = S.regex_allowed; + switch (peek()) { + case "/": read_line_comment(); S.regex_allowed = regex_allowed; return next_token(); + case "*": read_multiline_comment(); S.regex_allowed = regex_allowed; return next_token(); + } + return S.regex_allowed ? read_regexp() : read_operator("/"); + } : function() { + next(); + switch (peek()) { + case "/": return read_line_comment(); + case "*": return read_multiline_comment(); + } + return S.regex_allowed ? read_regexp() : read_operator("/"); + }; + + function handle_dot() { + next(); + return is_digit(peek()) + ? read_num(".") + : token("punc", "."); + }; + + function read_word() { + var word = read_while(is_identifier_char); + return !HOP(KEYWORDS, word) + ? token("name", word) + : HOP(OPERATORS, word) + ? token("operator", word) + : HOP(KEYWORDS_ATOM, word) + ? token("atom", word) + : token("keyword", word); + }; + + function with_eof_error(eof_error, cont) { + try { + return cont(); + } catch(ex) { + if (ex === EX_EOF) parse_error(eof_error); + else throw ex; + } + }; + + function next_token(force_regexp) { + if (force_regexp) + return read_regexp(); + skip_whitespace(); + start_token(); + var ch = peek(); + if (!ch) return token("eof"); + if (is_digit(ch)) return read_num(); + if (ch == '"' || ch == "'") return read_string(); + if (HOP(PUNC_CHARS, ch)) return token("punc", next()); + if (ch == ".") return handle_dot(); + if (ch == "/") return handle_slash(); + if (HOP(OPERATOR_CHARS, ch)) return read_operator(); + if (is_identifier_char(ch)) return read_word(); + parse_error("Unexpected character '" + ch + "'"); + }; + + next_token.context = function(nc) { + if (nc) S = nc; + return S; + }; + + return next_token; + +}; + +/* -----[ Parser (constants) ]----- */ + +var UNARY_PREFIX = array_to_hash([ + "typeof", + "void", + "delete", + "--", + "++", + "!", + "~", + "-", + "+" +]); + +var UNARY_POSTFIX = array_to_hash([ "--", "++" ]); + +var ASSIGNMENT = (function(a, ret, i){ + while (i < a.length) { + ret[a[i]] = a[i].substr(0, a[i].length - 1); + i++; + } + return ret; +})( + ["+=", "-=", "/=", "*=", "%=", ">>=", "<<=", ">>>=", "~=", "%=", "|=", "^=", "&="], + { "=": true }, + 0 +); + +var PRECEDENCE = (function(a, ret){ + for (var i = 0, n = 1; i < a.length; ++i, ++n) { + var b = a[i]; + for (var j = 0; j < b.length; ++j) { + ret[b[j]] = n; + } + } + return ret; +})( + [ + ["||"], + ["&&"], + ["|"], + ["^"], + ["&"], + ["==", "===", "!=", "!=="], + ["<", ">", "<=", ">=", "in", "instanceof"], + [">>", "<<", ">>>"], + ["+", "-"], + ["*", "/", "%"] + ], + {} +); + +var STATEMENTS_WITH_LABELS = array_to_hash([ "for", "do", "while", "switch" ]); + +var ATOMIC_START_TOKEN = array_to_hash([ "atom", "num", "string", "regexp", "name" ]); + +/* -----[ Parser ]----- */ + +function NodeWithToken(str, start, end) { + this.name = str; + this.start = start; + this.end = end; +}; + +NodeWithToken.prototype.toString = function() { return this.name; }; + +function parse($TEXT, strict_mode, embed_tokens) { + + var S = { + input: tokenizer($TEXT, true), + token: null, + prev: null, + peeked: null, + in_function: 0, + in_loop: 0, + labels: [] + }; + + S.token = next(); + + function is(type, value) { + return is_token(S.token, type, value); + }; + + function peek() { return S.peeked || (S.peeked = S.input()); }; + + function next() { + S.prev = S.token; + if (S.peeked) { + S.token = S.peeked; + S.peeked = null; + } else { + S.token = S.input(); + } + return S.token; + }; + + function prev() { + return S.prev; + }; + + function croak(msg, line, col, pos) { + var ctx = S.input.context(); + js_error(msg, + line != null ? line : ctx.tokline, + col != null ? col : ctx.tokcol, + pos != null ? pos : ctx.tokpos); + }; + + function token_error(token, msg) { + croak(msg, token.line, token.col); + }; + + function unexpected(token) { + if (token == null) + token = S.token; + token_error(token, "Unexpected token: " + token.type + " (" + token.value + ")"); + }; + + function expect_token(type, val) { + if (is(type, val)) { + return next(); + } + token_error(S.token, "Unexpected token " + S.token.type + ", expected " + type); + }; + + function expect(punc) { return expect_token("punc", punc); }; + + function can_insert_semicolon() { + return !strict_mode && ( + S.token.nlb || is("eof") || is("punc", "}") + ); + }; + + function semicolon() { + if (is("punc", ";")) next(); + else if (!can_insert_semicolon()) unexpected(); + }; + + function as() { + return slice(arguments); + }; + + function parenthesised() { + expect("("); + var ex = expression(); + expect(")"); + return ex; + }; + + function add_tokens(str, start, end) { + return new NodeWithToken(str, start, end); + }; + + var statement = embed_tokens ? function() { + var start = S.token; + var stmt = $statement(); + stmt[0] = add_tokens(stmt[0], start, prev()); + return stmt; + } : $statement; + + function $statement() { + if (is("operator", "/")) { + S.peeked = null; + S.token = S.input(true); // force regexp + } + switch (S.token.type) { + case "num": + case "string": + case "regexp": + case "operator": + case "atom": + return simple_statement(); + + case "name": + return is_token(peek(), "punc", ":") + ? labeled_statement(prog1(S.token.value, next, next)) + : simple_statement(); + + case "punc": + switch (S.token.value) { + case "{": + return as("block", block_()); + case "[": + case "(": + return simple_statement(); + case ";": + next(); + return as("block"); + default: + unexpected(); + } + + case "keyword": + switch (prog1(S.token.value, next)) { + case "break": + return break_cont("break"); + + case "continue": + return break_cont("continue"); + + case "debugger": + semicolon(); + return as("debugger"); + + case "do": + return (function(body){ + expect_token("keyword", "while"); + return as("do", prog1(parenthesised, semicolon), body); + })(in_loop(statement)); + + case "for": + return for_(); + + case "function": + return function_(true); + + case "if": + return if_(); + + case "return": + if (S.in_function == 0) + croak("'return' outside of function"); + return as("return", + is("punc", ";") + ? (next(), null) + : can_insert_semicolon() + ? null + : prog1(expression, semicolon)); + + case "switch": + return as("switch", parenthesised(), switch_block_()); + + case "throw": + return as("throw", prog1(expression, semicolon)); + + case "try": + return try_(); + + case "var": + return prog1(var_, semicolon); + + case "const": + return prog1(const_, semicolon); + + case "while": + return as("while", parenthesised(), in_loop(statement)); + + case "with": + return as("with", parenthesised(), statement()); + + default: + unexpected(); + } + } + }; + + function labeled_statement(label) { + S.labels.push(label); + var start = S.token, stat = statement(); + if (strict_mode && !HOP(STATEMENTS_WITH_LABELS, stat[0])) + unexpected(start); + S.labels.pop(); + return as("label", label, stat); + }; + + function simple_statement() { + return as("stat", prog1(expression, semicolon)); + }; + + function break_cont(type) { + var name = is("name") ? S.token.value : null; + if (name != null) { + next(); + if (!member(name, S.labels)) + croak("Label " + name + " without matching loop or statement"); + } + else if (S.in_loop == 0) + croak(type + " not inside a loop or switch"); + semicolon(); + return as(type, name); + }; + + function for_() { + expect("("); + var has_var = is("keyword", "var"); + if (has_var) + next(); + if (is("name") && is_token(peek(), "operator", "in")) { + // for (i in foo) + var name = S.token.value; + next(); next(); + var obj = expression(); + expect(")"); + return as("for-in", has_var, name, obj, in_loop(statement)); + } else { + // classic for + var init = is("punc", ";") ? null : has_var ? var_() : expression(); + expect(";"); + var test = is("punc", ";") ? null : expression(); + expect(";"); + var step = is("punc", ")") ? null : expression(); + expect(")"); + return as("for", init, test, step, in_loop(statement)); + } + }; + + function function_(in_statement) { + var name = is("name") ? prog1(S.token.value, next) : null; + if (in_statement && !name) + unexpected(); + expect("("); + return as(in_statement ? "defun" : "function", + name, + // arguments + (function(first, a){ + while (!is("punc", ")")) { + if (first) first = false; else expect(","); + if (!is("name")) unexpected(); + a.push(S.token.value); + next(); + } + next(); + return a; + })(true, []), + // body + (function(){ + ++S.in_function; + var loop = S.in_loop; + S.in_loop = 0; + var a = block_(); + --S.in_function; + S.in_loop = loop; + return a; + })()); + }; + + function if_() { + var cond = parenthesised(), body = statement(), belse; + if (is("keyword", "else")) { + next(); + belse = statement(); + } + return as("if", cond, body, belse); + }; + + function block_() { + expect("{"); + var a = []; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + a.push(statement()); + } + next(); + return a; + }; + + var switch_block_ = curry(in_loop, function(){ + expect("{"); + var a = [], cur = null; + while (!is("punc", "}")) { + if (is("eof")) unexpected(); + if (is("keyword", "case")) { + next(); + cur = []; + a.push([ expression(), cur ]); + expect(":"); + } + else if (is("keyword", "default")) { + next(); + expect(":"); + cur = []; + a.push([ null, cur ]); + } + else { + if (!cur) unexpected(); + cur.push(statement()); + } + } + next(); + return a; + }); + + function try_() { + var body = block_(), bcatch, bfinally; + if (is("keyword", "catch")) { + next(); + expect("("); + if (!is("name")) + croak("Name expected"); + var name = S.token.value; + next(); + expect(")"); + bcatch = [ name, block_() ]; + } + if (is("keyword", "finally")) { + next(); + bfinally = block_(); + } + if (!bcatch && !bfinally) + croak("Missing catch/finally blocks"); + return as("try", body, bcatch, bfinally); + }; + + function vardefs() { + var a = []; + for (;;) { + if (!is("name")) + unexpected(); + var name = S.token.value; + next(); + if (is("operator", "=")) { + next(); + a.push([ name, expression(false) ]); + } else { + a.push([ name ]); + } + if (!is("punc", ",")) + break; + next(); + } + return a; + }; + + function var_() { + return as("var", vardefs()); + }; + + function const_() { + return as("const", vardefs()); + }; + + function new_() { + var newexp = expr_atom(false), args; + if (is("punc", "(")) { + next(); + args = expr_list(")"); + } else { + args = []; + } + return subscripts(as("new", newexp, args), true); + }; + + function expr_atom(allow_calls) { + if (is("operator", "new")) { + next(); + return new_(); + } + if (is("operator") && HOP(UNARY_PREFIX, S.token.value)) { + return make_unary("unary-prefix", + prog1(S.token.value, next), + expr_atom(allow_calls)); + } + if (is("punc")) { + switch (S.token.value) { + case "(": + next(); + return subscripts(prog1(expression, curry(expect, ")")), allow_calls); + case "[": + next(); + return subscripts(array_(), allow_calls); + case "{": + next(); + return subscripts(object_(), allow_calls); + } + unexpected(); + } + if (is("keyword", "function")) { + next(); + return subscripts(function_(false), allow_calls); + } + if (HOP(ATOMIC_START_TOKEN, S.token.type)) { + var atom = S.token.type == "regexp" + ? as("regexp", S.token.value[0], S.token.value[1]) + : as(S.token.type, S.token.value); + return subscripts(prog1(atom, next), allow_calls); + } + unexpected(); + }; + + function expr_list(closing, allow_trailing_comma) { + var first = true, a = []; + while (!is("punc", closing)) { + if (first) first = false; else expect(","); + if (allow_trailing_comma && is("punc", closing)) + break; + a.push(expression(false)); + } + next(); + return a; + }; + + function array_() { + return as("array", expr_list("]", !strict_mode)); + }; + + function object_() { + var first = true, a = []; + while (!is("punc", "}")) { + if (first) first = false; else expect(","); + if (!strict_mode && is("punc", "}")) + // allow trailing comma + break; + var type = S.token.type; + var name = as_property_name(); + if (type == "name" && (name == "get" || name == "set") && !is("punc", ":")) { + a.push([ as_name(), function_(false), name ]); + } else { + expect(":"); + a.push([ name, expression(false) ]); + } + } + next(); + return as("object", a); + }; + + function as_property_name() { + switch (S.token.type) { + case "num": + case "string": + return prog1(S.token.value, next); + } + return as_name(); + }; + + function as_name() { + switch (S.token.type) { + case "name": + case "operator": + case "keyword": + case "atom": + return prog1(S.token.value, next); + default: + unexpected(); + } + }; + + function subscripts(expr, allow_calls) { + if (is("punc", ".")) { + next(); + return subscripts(as("dot", expr, as_name()), allow_calls); + } + if (is("punc", "[")) { + next(); + return subscripts(as("sub", expr, prog1(expression, curry(expect, "]"))), allow_calls); + } + if (allow_calls && is("punc", "(")) { + next(); + return subscripts(as("call", expr, expr_list(")")), true); + } + if (allow_calls && is("operator") && HOP(UNARY_POSTFIX, S.token.value)) { + return prog1(curry(make_unary, "unary-postfix", S.token.value, expr), + next); + } + return expr; + }; + + function make_unary(tag, op, expr) { + if ((op == "++" || op == "--") && !is_assignable(expr)) + croak("Invalid use of " + op + " operator"); + return as(tag, op, expr); + }; + + function expr_op(left, min_prec) { + var op = is("operator") ? S.token.value : null; + var prec = op != null ? PRECEDENCE[op] : null; + if (prec != null && prec > min_prec) { + next(); + var right = expr_op(expr_atom(true), prec); + return expr_op(as("binary", op, left, right), min_prec); + } + return left; + }; + + function expr_ops() { + return expr_op(expr_atom(true), 0); + }; + + function maybe_conditional() { + var expr = expr_ops(); + if (is("operator", "?")) { + next(); + var yes = expression(false); + expect(":"); + return as("conditional", expr, yes, expression(false)); + } + return expr; + }; + + function is_assignable(expr) { + switch (expr[0]) { + case "dot": + case "sub": + return true; + case "name": + return expr[1] != "this"; + } + }; + + function maybe_assign() { + var left = maybe_conditional(), val = S.token.value; + if (is("operator") && HOP(ASSIGNMENT, val)) { + if (is_assignable(left)) { + next(); + return as("assign", ASSIGNMENT[val], left, maybe_assign()); + } + croak("Invalid assignment"); + } + return left; + }; + + function expression(commas) { + if (arguments.length == 0) + commas = true; + var expr = maybe_assign(); + if (commas && is("punc", ",")) { + next(); + return as("seq", expr, expression()); + } + return expr; + }; + + function in_loop(cont) { + try { + ++S.in_loop; + return cont(); + } finally { + --S.in_loop; + } + }; + + return as("toplevel", (function(a){ + while (!is("eof")) + a.push(statement()); + return a; + })([])); + +}; + +/* -----[ Utilities ]----- */ + +function curry(f) { + var args = slice(arguments, 1); + return function() { return f.apply(this, args.concat(slice(arguments))); }; +}; + +function prog1(ret) { + if (ret instanceof Function) + ret = ret(); + for (var i = 1, n = arguments.length; --n > 0; ++i) + arguments[i](); + return ret; +}; + +function array_to_hash(a) { + var ret = {}; + for (var i = 0; i < a.length; ++i) + ret[a[i]] = true; + return ret; +}; + +function slice(a, start) { + return Array.prototype.slice.call(a, start == null ? 0 : start); +}; + +function characters(str) { + return str.split(""); +}; + +function member(name, array) { + for (var i = array.length; --i >= 0;) + if (array[i] === name) + return true; + return false; +}; + +function HOP(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +}; + +/* -----[ Exports ]----- */ + +exports.tokenizer = tokenizer; +exports.parse = parse; +exports.slice = slice; +exports.curry = curry; +exports.member = member; +exports.array_to_hash = array_to_hash; +exports.PRECEDENCE = PRECEDENCE; +exports.KEYWORDS_ATOM = KEYWORDS_ATOM; +exports.RESERVED_WORDS = RESERVED_WORDS; +exports.KEYWORDS = KEYWORDS; +exports.ATOMIC_START_TOKEN = ATOMIC_START_TOKEN; +exports.OPERATORS = OPERATORS; +exports.is_alphanumeric_char = is_alphanumeric_char; diff --git a/Source/WebCore/inspector/front-end/UglifyJS/process.js b/Source/WebCore/inspector/front-end/UglifyJS/process.js new file mode 100755 index 0000000..65dbc0e --- /dev/null +++ b/Source/WebCore/inspector/front-end/UglifyJS/process.js @@ -0,0 +1,1560 @@ +/*********************************************************************** + + A JavaScript tokenizer / parser / beautifier / compressor. + + This version is suitable for Node.js. With minimal changes (the + exports stuff) it should work on any JS platform. + + This file implements some AST processors. They work on data built + by parse-js. + + Exported functions: + + - ast_mangle(ast, include_toplevel) -- mangles the + variable/function names in the AST. Returns an AST. Pass true + as second argument to mangle toplevel names too. + + - ast_squeeze(ast) -- employs various optimizations to make the + final generated code even smaller. Returns an AST. + + - gen_code(ast, beautify) -- generates JS code from the AST. Pass + true (or an object, see the code for some options) as second + argument to get "pretty" (indented) code. + + -------------------------------- (C) --------------------------------- + + Author: Mihai Bazon + <mihai.bazon@gmail.com> + http://mihai.bazon.net/blog + + Distributed under the BSD license: + + Copyright 2010 (c) Mihai Bazon <mihai.bazon@gmail.com> + + 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. + + THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER “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 HOLDER 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. + + ***********************************************************************/ + +var jsp = require("./parse-js"), + slice = jsp.slice, + member = jsp.member, + PRECEDENCE = jsp.PRECEDENCE, + OPERATORS = jsp.OPERATORS; + +/* -----[ helper for AST traversal ]----- */ + +function ast_walker(ast) { + function _vardefs(defs) { + return MAP(defs, function(def){ + var a = [ def[0] ]; + if (def.length > 1) + a[1] = walk(def[1]); + return a; + }); + }; + var walkers = { + "string": function(str) { + return [ "string", str ]; + }, + "num": function(num) { + return [ "num", num ]; + }, + "name": function(name) { + return [ "name", name ]; + }, + "toplevel": function(statements) { + return [ "toplevel", MAP(statements, walk) ]; + }, + "block": function(statements) { + var out = [ "block" ]; + if (statements != null) + out.push(MAP(statements, walk)); + return out; + }, + "var": function(defs) { + return [ "var", _vardefs(defs) ]; + }, + "const": function(defs) { + return [ "const", _vardefs(defs) ]; + }, + "try": function(t, c, f) { + return [ + "try", + MAP(t, walk), + c != null ? [ c[0], MAP(c[1], walk) ] : null, + f != null ? MAP(f, walk) : null + ]; + }, + "throw": function(expr) { + return [ "throw", walk(expr) ]; + }, + "new": function(ctor, args) { + return [ "new", walk(ctor), MAP(args, walk) ]; + }, + "switch": function(expr, body) { + return [ "switch", walk(expr), MAP(body, function(branch){ + return [ branch[0] ? walk(branch[0]) : null, + MAP(branch[1], walk) ]; + }) ]; + }, + "break": function(label) { + return [ "break", label ]; + }, + "continue": function(label) { + return [ "continue", label ]; + }, + "conditional": function(cond, t, e) { + return [ "conditional", walk(cond), walk(t), walk(e) ]; + }, + "assign": function(op, lvalue, rvalue) { + return [ "assign", op, walk(lvalue), walk(rvalue) ]; + }, + "dot": function(expr) { + return [ "dot", walk(expr) ].concat(slice(arguments, 1)); + }, + "call": function(expr, args) { + return [ "call", walk(expr), MAP(args, walk) ]; + }, + "function": function(name, args, body) { + return [ "function", name, args.slice(), MAP(body, walk) ]; + }, + "defun": function(name, args, body) { + return [ "defun", name, args.slice(), MAP(body, walk) ]; + }, + "if": function(conditional, t, e) { + return [ "if", walk(conditional), walk(t), walk(e) ]; + }, + "for": function(init, cond, step, block) { + return [ "for", walk(init), walk(cond), walk(step), walk(block) ]; + }, + "for-in": function(has_var, key, hash, block) { + return [ "for-in", has_var, key, walk(hash), walk(block) ]; + }, + "while": function(cond, block) { + return [ "while", walk(cond), walk(block) ]; + }, + "do": function(cond, block) { + return [ "do", walk(cond), walk(block) ]; + }, + "return": function(expr) { + return [ "return", walk(expr) ]; + }, + "binary": function(op, left, right) { + return [ "binary", op, walk(left), walk(right) ]; + }, + "unary-prefix": function(op, expr) { + return [ "unary-prefix", op, walk(expr) ]; + }, + "unary-postfix": function(op, expr) { + return [ "unary-postfix", op, walk(expr) ]; + }, + "sub": function(expr, subscript) { + return [ "sub", walk(expr), walk(subscript) ]; + }, + "object": function(props) { + return [ "object", MAP(props, function(p){ + return p.length == 2 + ? [ p[0], walk(p[1]) ] + : [ p[0], walk(p[1]), p[2] ]; // get/set-ter + }) ]; + }, + "regexp": function(rx, mods) { + return [ "regexp", rx, mods ]; + }, + "array": function(elements) { + return [ "array", MAP(elements, walk) ]; + }, + "stat": function(stat) { + return [ "stat", walk(stat) ]; + }, + "seq": function() { + return [ "seq" ].concat(MAP(slice(arguments), walk)); + }, + "label": function(name, block) { + return [ "label", name, walk(block) ]; + }, + "with": function(expr, block) { + return [ "with", walk(expr), walk(block) ]; + }, + "atom": function(name) { + return [ "atom", name ]; + } + }; + + var user = {}; + var stack = []; + function walk(ast) { + if (ast == null) + return null; + try { + stack.push(ast); + var type = ast[0]; + var gen = user[type]; + if (gen) { + var ret = gen.apply(ast, ast.slice(1)); + if (ret != null) + return ret; + } + gen = walkers[type]; + return gen.apply(ast, ast.slice(1)); + } finally { + stack.pop(); + } + }; + + function with_walkers(walkers, cont){ + var save = {}, i; + for (i in walkers) if (HOP(walkers, i)) { + save[i] = user[i]; + user[i] = walkers[i]; + } + var ret = cont(); + for (i in save) if (HOP(save, i)) { + if (!save[i]) delete user[i]; + else user[i] = save[i]; + } + return ret; + }; + + return { + walk: walk, + with_walkers: with_walkers, + parent: function() { + return stack[stack.length - 2]; // last one is current node + }, + stack: function() { + return stack; + } + }; +}; + +/* -----[ Scope and mangling ]----- */ + +function Scope(parent) { + this.names = {}; // names defined in this scope + this.mangled = {}; // mangled names (orig.name => mangled) + this.rev_mangled = {}; // reverse lookup (mangled => orig.name) + this.cname = -1; // current mangled name + this.refs = {}; // names referenced from this scope + this.uses_with = false; // will become TRUE if eval() is detected in this or any subscopes + this.uses_eval = false; // will become TRUE if with() is detected in this or any subscopes + this.parent = parent; // parent scope + this.children = []; // sub-scopes + if (parent) { + this.level = parent.level + 1; + parent.children.push(this); + } else { + this.level = 0; + } +}; + +var base54 = (function(){ + var DIGITS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ$_"; + return function(num) { + var ret = ""; + do { + ret = DIGITS.charAt(num % 54) + ret; + num = Math.floor(num / 54); + } while (num > 0); + return ret; + }; +})(); + +Scope.prototype = { + has: function(name) { + for (var s = this; s; s = s.parent) + if (HOP(s.names, name)) + return s; + }, + has_mangled: function(mname) { + for (var s = this; s; s = s.parent) + if (HOP(s.rev_mangled, mname)) + return s; + }, + toJSON: function() { + return { + names: this.names, + uses_eval: this.uses_eval, + uses_with: this.uses_with + }; + }, + + next_mangled: function() { + // we must be careful that the new mangled name: + // + // 1. doesn't shadow a mangled name from a parent + // scope, unless we don't reference the original + // name from this scope OR from any sub-scopes! + // This will get slow. + // + // 2. doesn't shadow an original name from a parent + // scope, in the event that the name is not mangled + // in the parent scope and we reference that name + // here OR IN ANY SUBSCOPES! + // + // 3. doesn't shadow a name that is referenced but not + // defined (possibly global defined elsewhere). + for (;;) { + var m = base54(++this.cname), prior; + + // case 1. + prior = this.has_mangled(m); + if (prior && this.refs[prior.rev_mangled[m]] === prior) + continue; + + // case 2. + prior = this.has(m); + if (prior && prior !== this && this.refs[m] === prior && !prior.has_mangled(m)) + continue; + + // case 3. + if (HOP(this.refs, m) && this.refs[m] == null) + continue; + + // I got "do" once. :-/ + if (!is_identifier(m)) + continue; + + return m; + } + }, + get_mangled: function(name, newMangle) { + if (this.uses_eval || this.uses_with) return name; // no mangle if eval or with is in use + var s = this.has(name); + if (!s) return name; // not in visible scope, no mangle + if (HOP(s.mangled, name)) return s.mangled[name]; // already mangled in this scope + if (!newMangle) return name; // not found and no mangling requested + + var m = s.next_mangled(); + s.rev_mangled[m] = name; + return s.mangled[name] = m; + }, + define: function(name) { + if (name != null) + return this.names[name] = name; + } +}; + +function ast_add_scope(ast) { + + var current_scope = null; + var w = ast_walker(), walk = w.walk; + var having_eval = []; + + function with_new_scope(cont) { + current_scope = new Scope(current_scope); + var ret = current_scope.body = cont(); + ret.scope = current_scope; + current_scope = current_scope.parent; + return ret; + }; + + function define(name) { + return current_scope.define(name); + }; + + function reference(name) { + current_scope.refs[name] = true; + }; + + function _lambda(name, args, body) { + return [ this[0], define(name), args, with_new_scope(function(){ + MAP(args, define); + return MAP(body, walk); + })]; + }; + + return with_new_scope(function(){ + // process AST + var ret = w.with_walkers({ + "function": _lambda, + "defun": _lambda, + "with": function(expr, block) { + for (var s = current_scope; s; s = s.parent) + s.uses_with = true; + }, + "var": function(defs) { + MAP(defs, function(d){ define(d[0]) }); + }, + "const": function(defs) { + MAP(defs, function(d){ define(d[0]) }); + }, + "try": function(t, c, f) { + if (c != null) return [ + "try", + MAP(t, walk), + [ define(c[0]), MAP(c[1], walk) ], + f != null ? MAP(f, walk) : null + ]; + }, + "name": function(name) { + if (name == "eval") + having_eval.push(current_scope); + reference(name); + }, + "for-in": function(has_var, name) { + if (has_var) define(name); + else reference(name); + } + }, function(){ + return walk(ast); + }); + + // the reason why we need an additional pass here is + // that names can be used prior to their definition. + + // scopes where eval was detected and their parents + // are marked with uses_eval, unless they define the + // "eval" name. + MAP(having_eval, function(scope){ + if (!scope.has("eval")) while (scope) { + scope.uses_eval = true; + scope = scope.parent; + } + }); + + // for referenced names it might be useful to know + // their origin scope. current_scope here is the + // toplevel one. + function fixrefs(scope, i) { + // do children first; order shouldn't matter + for (i = scope.children.length; --i >= 0;) + fixrefs(scope.children[i]); + for (i in scope.refs) if (HOP(scope.refs, i)) { + // find origin scope and propagate the reference to origin + for (var origin = scope.has(i), s = scope; s; s = s.parent) { + s.refs[i] = origin; + if (s === origin) break; + } + } + }; + fixrefs(current_scope); + + return ret; + }); + +}; + +/* -----[ mangle names ]----- */ + +function ast_mangle(ast, do_toplevel) { + var w = ast_walker(), walk = w.walk, scope; + + function get_mangled(name, newMangle) { + if (!do_toplevel && !scope.parent) return name; // don't mangle toplevel + return scope.get_mangled(name, newMangle); + }; + + function _lambda(name, args, body) { + if (name) name = get_mangled(name); + body = with_scope(body.scope, function(){ + args = MAP(args, function(name){ return get_mangled(name) }); + return MAP(body, walk); + }); + return [ this[0], name, args, body ]; + }; + + function with_scope(s, cont) { + var _scope = scope; + scope = s; + for (var i in s.names) if (HOP(s.names, i)) { + get_mangled(i, true); + } + var ret = cont(); + ret.scope = s; + scope = _scope; + return ret; + }; + + function _vardefs(defs) { + return MAP(defs, function(d){ + return [ get_mangled(d[0]), walk(d[1]) ]; + }); + }; + + return w.with_walkers({ + "function": _lambda, + "defun": function() { + // move function declarations to the top when + // they are not in some block. + var ast = _lambda.apply(this, arguments); + switch (w.parent()[0]) { + case "toplevel": + case "function": + case "defun": + return MAP.at_top(ast); + } + return ast; + }, + "var": function(defs) { + return [ "var", _vardefs(defs) ]; + }, + "const": function(defs) { + return [ "const", _vardefs(defs) ]; + }, + "name": function(name) { + return [ "name", get_mangled(name) ]; + }, + "try": function(t, c, f) { + return [ "try", + MAP(t, walk), + c != null ? [ get_mangled(c[0]), MAP(c[1], walk) ] : null, + f != null ? MAP(f, walk) : null ]; + }, + "toplevel": function(body) { + return with_scope(this.scope, function(){ + return [ "toplevel", MAP(body, walk) ]; + }); + }, + "for-in": function(has_var, name, obj, stat) { + return [ "for-in", has_var, get_mangled(name), walk(obj), walk(stat) ]; + } + }, function() { + return walk(ast_add_scope(ast)); + }); +}; + +/* -----[ + - compress foo["bar"] into foo.bar, + - remove block brackets {} where possible + - join consecutive var declarations + - various optimizations for IFs: + - if (cond) foo(); else bar(); ==> cond?foo():bar(); + - if (cond) foo(); ==> cond&&foo(); + - if (foo) return bar(); else return baz(); ==> return foo?bar():baz(); // also for throw + - if (foo) return bar(); else something(); ==> {if(foo)return bar();something()} + ]----- */ + +var warn = function(){}; + +function best_of(ast1, ast2) { + return gen_code(ast1).length > gen_code(ast2[0] == "stat" ? ast2[1] : ast2).length ? ast2 : ast1; +}; + +function last_stat(b) { + if (b[0] == "block" && b[1] && b[1].length > 0) + return b[1][b[1].length - 1]; + return b; +} + +function aborts(t) { + if (t) { + t = last_stat(t); + if (t[0] == "return" || t[0] == "break" || t[0] == "continue" || t[0] == "throw") + return true; + } +}; + +function negate(c) { + var not_c = [ "unary-prefix", "!", c ]; + switch (c[0]) { + case "unary-prefix": + return c[1] == "!" ? c[2] : not_c; + case "binary": + var op = c[1], left = c[2], right = c[3]; + switch (op) { + case "<=": return [ "binary", ">", left, right ]; + case "<": return [ "binary", ">=", left, right ]; + case ">=": return [ "binary", "<", left, right ]; + case ">": return [ "binary", "<=", left, right ]; + case "==": return [ "binary", "!=", left, right ]; + case "!=": return [ "binary", "==", left, right ]; + case "===": return [ "binary", "!==", left, right ]; + case "!==": return [ "binary", "===", left, right ]; + case "&&": return best_of(not_c, [ "binary", "||", negate(left), negate(right) ]); + case "||": return best_of(not_c, [ "binary", "&&", negate(left), negate(right) ]); + } + break; + } + return not_c; +}; + +function make_conditional(c, t, e) { + if (c[0] == "unary-prefix" && c[1] == "!") { + return e ? [ "conditional", c[2], e, t ] : [ "binary", "||", c[2], t ]; + } else { + return e ? [ "conditional", c, t, e ] : [ "binary", "&&", c, t ]; + } +}; + +function empty(b) { + return !b || (b[0] == "block" && (!b[1] || b[1].length == 0)); +}; + +function ast_squeeze(ast, options) { + options = defaults(options, { + make_seqs : true, + dead_code : true, + no_warnings : false, + extra : false + }); + + var w = ast_walker(), walk = w.walk, scope; + + function with_scope(s, cont) { + var _scope = scope; + scope = s; + var ret = cont(); + ret.scope = s; + scope = _scope; + return ret; + }; + + function is_constant(node) { + return node[0] == "string" || node[0] == "num"; + }; + + function find_first_execute(node) { + if (!node) + return false; + + switch (node[0]) { + case "num": + case "string": + case "name": + return node; + case "call": + case "conditional": + case "for": + case "if": + case "new": + case "return": + case "stat": + case "switch": + case "throw": + return find_first_execute(node[1]); + case "binary": + return find_first_execute(node[2]); + case "assign": + if (node[1] === true) + return find_first_execute(node[3]); + break; + case "var": + if (node[1][0].length > 1) + return find_first_execute(node[1][0][1]); + break; + } + return null; + } + + function find_assign_recursive(p, v) { + if (p[0] == "assign" && p[1] != true || p[0] == "unary-prefix") { + if (p[2][0] == "name" && v[0] == "name" && p[2][1] == v[1]) + return true; + return false; + } + + if (p[0] != "assign" || p[1] !== true) + return false; + + if ((is_constant(p[3]) && p[3][0] == v[0] && p[3][1] == v[1]) || + (p[3][0] == "name" && v[0] == "name" && p[3][1] == v[1]) || + (p[2][0] == "name" && v[0] == "name" && p[2][1] == v[1])) + return true; + + return find_assign_recursive(p[3], v); + }; + + function rmblock(block) { + if (block != null && block[0] == "block" && block[1] && block[1].length == 1) + block = block[1][0]; + return block; + }; + + function clone(obj) { + if (obj && obj.constructor == Array) + return MAP(obj, clone); + return obj; + }; + + function make_seq_to_statements(node) { + if (node[0] != "seq") { + switch (node[0]) { + case "var": + case "const": + return [ node ]; + default: + return [ [ "stat", node ] ]; + } + } + + var ret = []; + for (var i = 1; i < node.length; i++) + ret.push.apply(ret, make_seq_to_statements(node[i])); + + return ret; + }; + + function _lambda(name, args, body) { + return [ this[0], name, args, with_scope(body.scope, function(){ + return tighten(MAP(body, walk), "lambda"); + }) ]; + }; + + // we get here for blocks that have been already transformed. + // this function does a few things: + // 1. discard useless blocks + // 2. join consecutive var declarations + // 3. remove obviously dead code + // 4. transform consecutive statements using the comma operator + // 5. if block_type == "lambda" and it detects constructs like if(foo) return ... - rewrite like if (!foo) { ... } + function tighten(statements, block_type) { + statements = statements.reduce(function(a, stat){ + if (stat[0] == "block") { + if (stat[1]) { + a.push.apply(a, stat[1]); + } + } else { + a.push(stat); + } + return a; + }, []); + + if (options.extra) { + // Detightening things. We do this because then we can assume that the + // statements are structured in a specific way. + statements = (function(a, prev) { + statements.forEach(function(cur) { + switch (cur[0]) { + case "for": + if (cur[1] != null) { + a.push.apply(a, make_seq_to_statements(cur[1])); + cur[1] = null; + } + a.push(cur); + break; + case "stat": + var stats = make_seq_to_statements(cur[1]); + stats.forEach(function(s) { + if (s[1][0] == "unary-postfix") + s[1][0] = "unary-prefix"; + }); + a.push.apply(a, stats); + break; + default: + a.push(cur); + } + }); + return a; + })([]); + + statements = (function(a, prev) { + statements.forEach(function(cur) { + if (!(prev && prev[0] == "stat")) { + a.push(cur); + prev = cur; + return; + } + + var p = prev[1]; + var c = find_first_execute(cur); + if (c && find_assign_recursive(p, c)) { + var old_cur = clone(cur); + c.splice(0, c.length); + c.push.apply(c, p); + var tmp_cur = best_of(cur, [ "toplevel", [ prev, old_cur ] ]); + if (tmp_cur == cur) { + a[a.length -1] = cur; + } else { + cur = old_cur; + a.push(cur); + } + } else { + a.push(cur); + } + prev = cur; + }); + return a; + })([]); + } + + statements = (function(a, prev){ + statements.forEach(function(cur){ + if (prev && ((cur[0] == "var" && prev[0] == "var") || + (cur[0] == "const" && prev[0] == "const"))) { + prev[1] = prev[1].concat(cur[1]); + } else { + a.push(cur); + prev = cur; + } + }); + return a; + })([]); + + if (options.dead_code) statements = (function(a, has_quit){ + statements.forEach(function(st){ + if (has_quit) { + if (member(st[0], [ "function", "defun" , "var", "const" ])) { + a.push(st); + } + else if (!options.no_warnings) + warn("Removing unreachable code: " + gen_code(st, true)); + } + else { + a.push(st); + if (member(st[0], [ "return", "throw", "break", "continue" ])) + has_quit = true; + } + }); + return a; + })([]); + + if (options.make_seqs) statements = (function(a, prev) { + statements.forEach(function(cur){ + if (prev && prev[0] == "stat" && cur[0] == "stat") { + prev[1] = [ "seq", prev[1], cur[1] ]; + } else { + a.push(cur); + prev = cur; + } + }); + return a; + })([]); + + if (options.extra) { + statements = (function(a, prev){ + statements.forEach(function(cur){ + var replaced = false; + if (prev && cur[0] == "for" && cur[1] == null && (prev[0] == "var" || prev[0] == "const" || prev[0] == "stat")) { + cur[1] = prev; + a[a.length - 1] = cur; + } else { + a.push(cur); + } + prev = cur; + }); + return a; + })([]); + } + + if (block_type == "lambda") statements = (function(i, a, stat){ + while (i < statements.length) { + stat = statements[i++]; + if (stat[0] == "if" && !stat[3]) { + if (stat[2][0] == "return" && stat[2][1] == null) { + a.push(make_if(negate(stat[1]), [ "block", statements.slice(i) ])); + break; + } + var last = last_stat(stat[2]); + if (last[0] == "return" && last[1] == null) { + a.push(make_if(stat[1], [ "block", stat[2][1].slice(0, -1) ], [ "block", statements.slice(i) ])); + break; + } + } + a.push(stat); + } + return a; + })(0, []); + + return statements; + }; + + function make_if(c, t, e) { + c = walk(c); + t = walk(t); + e = walk(e); + + if (empty(t)) { + c = negate(c); + t = e; + e = null; + } else if (empty(e)) { + e = null; + } else { + // if we have both else and then, maybe it makes sense to switch them? + (function(){ + var a = gen_code(c); + var n = negate(c); + var b = gen_code(n); + if (b.length < a.length) { + var tmp = t; + t = e; + e = tmp; + c = n; + } + })(); + } + if (empty(e) && empty(t)) + return [ "stat", c ]; + var ret = [ "if", c, t, e ]; + if (t[0] == "stat") { + if (e) { + if (e[0] == "stat") { + ret = best_of(ret, [ "stat", make_conditional(c, t[1], e[1]) ]); + } + } + else { + ret = best_of(ret, [ "stat", make_conditional(c, t[1]) ]); + } + } + else if (e && t[0] == e[0] && (t[0] == "return" || t[0] == "throw")) { + ret = best_of(ret, [ t[0], make_conditional(c, t[1], e[1] ) ]); + } + else if (e && aborts(t)) { + ret = [ [ "if", c, t ] ]; + if (e[0] == "block") { + if (e[1]) ret = ret.concat(e[1]); + } + else { + ret.push(e); + } + ret = walk([ "block", ret ]); + } + else if (t && aborts(e)) { + ret = [ [ "if", negate(c), e ] ]; + if (t[0] == "block") { + if (t[1]) ret = ret.concat(t[1]); + } else { + ret.push(t); + } + ret = walk([ "block", ret ]); + } + return ret; + }; + + return w.with_walkers({ + "sub": function(expr, subscript) { + if (subscript[0] == "string") { + var name = subscript[1]; + if (is_identifier(name)) { + return [ "dot", walk(expr), name ]; + } + } + }, + "if": make_if, + "toplevel": function(body) { + return [ "toplevel", with_scope(this.scope, function(){ + return tighten(MAP(body, walk)); + }) ]; + }, + "switch": function(expr, body) { + var last = body.length - 1; + return [ "switch", walk(expr), MAP(body, function(branch, i){ + var block = tighten(MAP(branch[1], walk)); + if (i == last && block.length > 0) { + var node = block[block.length - 1]; + if (node[0] == "break" && !node[1]) + block.pop(); + } + return [ branch[0] ? walk(branch[0]) : null, block ]; + }) ]; + }, + "function": _lambda, + "defun": _lambda, + "block": function(body) { + if (body) return rmblock([ "block", tighten(MAP(body, walk)) ]); + }, + "binary": function(op, left, right) { + left = walk(left); + right = walk(right); + var best = [ "binary", op, left, right ]; + if (is_constant(right)) { + if (is_constant(left)) { + var val = null; + switch (op) { + case "+": val = left[1] + right[1]; break; + case "*": val = left[1] * right[1]; break; + case "/": val = left[1] / right[1]; break; + case "-": val = left[1] - right[1]; break; + case "<<": val = left[1] << right[1]; break; + case ">>": val = left[1] >> right[1]; break; + case ">>>": val = left[1] >>> right[1]; break; + } + if (val != null) { + best = best_of(best, [ typeof val == "string" ? "string" : "num", val ]); + } + } else if (left[0] == "binary" && left[1] == "+" && left[3][0] == "string") { + best = best_of(best, [ "binary", "+", left[2], [ "string", left[3][1] + right[1] ] ]); + } + } + return best; + }, + "conditional": function(c, t, e) { + return make_conditional(walk(c), walk(t), walk(e)); + }, + "try": function(t, c, f) { + return [ + "try", + tighten(MAP(t, walk)), + c != null ? [ c[0], tighten(MAP(c[1], walk)) ] : null, + f != null ? tighten(MAP(f, walk)) : null + ]; + }, + "unary-prefix": function(op, cond) { + if (op == "!") { + cond = walk(cond); + if (cond[0] == "unary-prefix" && cond[1] == "!") { + var p = w.parent(); + if (p[0] == "unary-prefix" && p[1] == "!") + return cond[2]; + return [ "unary-prefix", "!", cond ]; + } + return best_of(this, negate(cond)); + } + }, + "name": function(name) { + switch (name) { + case "true": return [ "unary-prefix", "!", [ "num", 0 ]]; + case "false": return [ "unary-prefix", "!", [ "num", 1 ]]; + } + }, + "new": function(ctor, args) { + if (ctor[0] == "name" && ctor[1] == "Array" && !scope.has("Array")) { + if (args.length != 1) { + return [ "array", args ]; + } else { + return [ "call", [ "name", "Array" ], args ]; + } + } + }, + "call": function(expr, args) { + if (expr[0] == "name" && expr[1] == "Array" && args.length != 1 && !scope.has("Array")) { + return [ "array", args ]; + } + } + }, function() { + return walk(ast_add_scope(ast)); + }); +}; + +/* -----[ re-generate code from the AST ]----- */ + +var DOT_CALL_NO_PARENS = jsp.array_to_hash([ + "name", + "array", + "string", + "dot", + "sub", + "call", + "regexp" +]); + +function make_string(str) { + var dq = 0, sq = 0; + str = str.replace(/[\\\b\f\n\r\t\x22\x27]/g, function(s){ + switch (s) { + case "\\": return "\\\\"; + case "\b": return "\\b"; + case "\f": return "\\f"; + case "\n": return "\\n"; + case "\r": return "\\r"; + case "\t": return "\\t"; + case '"': ++dq; return '"'; + case "'": ++sq; return "'"; + } + return s; + }); + if (dq > sq) { + return "'" + str.replace(/\x27/g, "\\'") + "'"; + } else { + return '"' + str.replace(/\x22/g, '\\"') + '"'; + } +}; + +function gen_code(ast, beautify) { + if (beautify) beautify = defaults(beautify, { + indent_start : 0, + indent_level : 4, + quote_keys : false, + space_colon : false + }); + var indentation = 0, + newline = beautify ? "\n" : "", + space = beautify ? " " : ""; + + function indent(line) { + if (line == null) + line = ""; + if (beautify) + line = repeat_string(" ", beautify.indent_start + indentation * beautify.indent_level) + line; + return line; + }; + + function with_indent(cont, incr) { + if (incr == null) incr = 1; + indentation += incr; + try { return cont.apply(null, slice(arguments, 1)); } + finally { indentation -= incr; } + }; + + function add_spaces(a) { + if (beautify) + return a.join(" "); + var b = []; + for (var i = 0; i < a.length; ++i) { + var next = a[i + 1]; + b.push(a[i]); + if (next && + ((/[a-z0-9_\x24]$/i.test(a[i].toString()) && /^[a-z0-9_\x24]/i.test(next.toString())) || + (/[\+\-]$/.test(a[i].toString()) && /^[\+\-]/.test(next.toString())))) { + b.push(" "); + } + } + return b.join(""); + }; + + function add_commas(a) { + return a.join("," + space); + }; + + function parenthesize(expr) { + var gen = make(expr); + for (var i = 1; i < arguments.length; ++i) { + var el = arguments[i]; + if ((el instanceof Function && el(expr)) || expr[0] == el) + return "(" + gen + ")"; + } + return gen; + }; + + function best_of(a) { + if (a.length == 1) { + return a[0]; + } + if (a.length == 2) { + var b = a[1]; + a = a[0]; + return a.length <= b.length ? a : b; + } + return best_of([ a[0], best_of(a.slice(1)) ]); + }; + + function needs_parens(expr) { + if (expr[0] == "function") { + // dot/call on a literal function requires the + // function literal itself to be parenthesized + // only if it's the first "thing" in a + // statement. This means that the parent is + // "stat", but it could also be a "seq" and + // we're the first in this "seq" and the + // parent is "stat", and so on. Messy stuff, + // but it worths the trouble. + var a = slice($stack), self = a.pop(), p = a.pop(); + while (p) { + if (p[0] == "stat") return true; + if ((p[0] == "seq" && p[1] === self) || + (p[0] == "call" && p[1] === self) || + (p[0] == "binary" && p[2] === self)) { + self = p; + p = a.pop(); + } else { + return false; + } + } + } + return !HOP(DOT_CALL_NO_PARENS, expr[0]); + }; + + function make_num(num) { + var str = num.toString(10), a = [ str.replace(/^0\./, ".") ], m; + if (Math.floor(num) === num) { + a.push("0x" + num.toString(16).toLowerCase(), // probably pointless + "0" + num.toString(8)); // same. + if ((m = /^(.*?)(0+)$/.exec(num))) { + a.push(m[1] + "e" + m[2].length); + } + } else if ((m = /^0?\.(0+)(.*)$/.exec(num))) { + a.push(m[2] + "e-" + (m[1].length + m[2].length), + str.substr(str.indexOf("."))); + } + return best_of(a); + }; + + var generators = { + "string": make_string, + "num": make_num, + "name": make_name, + "toplevel": function(statements) { + return make_block_statements(statements) + .join(newline + newline); + }, + "block": make_block, + "var": function(defs) { + return "var " + add_commas(MAP(defs, make_1vardef)) + ";"; + }, + "const": function(defs) { + return "const " + add_commas(MAP(defs, make_1vardef)) + ";"; + }, + "try": function(tr, ca, fi) { + var out = [ "try", make_block(tr) ]; + if (ca) out.push("catch", "(" + ca[0] + ")", make_block(ca[1])); + if (fi) out.push("finally", make_block(fi)); + return add_spaces(out); + }, + "throw": function(expr) { + return add_spaces([ "throw", make(expr) ]) + ";"; + }, + "new": function(ctor, args) { + args = args.length > 0 ? "(" + add_commas(MAP(args, make)) + ")" : ""; + return add_spaces([ "new", parenthesize(ctor, "seq", "binary", "conditional", "assign", function(expr){ + var w = ast_walker(), has_call = {}; + try { + w.with_walkers({ + "call": function() { throw has_call }, + "function": function() { return this } + }, function(){ + w.walk(expr); + }); + } catch(ex) { + if (ex === has_call) + return true; + throw ex; + } + }) + args ]); + }, + "switch": function(expr, body) { + return add_spaces([ "switch", "(" + make(expr) + ")", make_switch_block(body) ]); + }, + "break": function(label) { + var out = "break"; + if (label != null) + out += " " + make_name(label); + return out + ";"; + }, + "continue": function(label) { + var out = "continue"; + if (label != null) + out += " " + make_name(label); + return out + ";"; + }, + "conditional": function(co, th, el) { + return add_spaces([ parenthesize(co, "assign", "seq", "conditional"), "?", + parenthesize(th, "seq"), ":", + parenthesize(el, "seq") ]); + }, + "assign": function(op, lvalue, rvalue) { + if (op && op !== true) op += "="; + else op = "="; + return add_spaces([ make(lvalue), op, parenthesize(rvalue, "seq") ]); + }, + "dot": function(expr) { + var out = make(expr), i = 1; + if (needs_parens(expr)) + out = "(" + out + ")"; + while (i < arguments.length) + out += "." + make_name(arguments[i++]); + return out; + }, + "call": function(func, args) { + var f = make(func); + if (needs_parens(func)) + f = "(" + f + ")"; + return f + "(" + add_commas(MAP(args, function(expr){ + return parenthesize(expr, "seq"); + })) + ")"; + }, + "function": make_function, + "defun": make_function, + "if": function(co, th, el) { + var out = [ "if", "(" + make(co) + ")", el ? make_then(th) : make(th) ]; + if (el) { + out.push("else", make(el)); + } + return add_spaces(out); + }, + "for": function(init, cond, step, block) { + var out = [ "for" ]; + init = (init != null ? make(init) : "").replace(/;*\s*$/, ";" + space); + cond = (cond != null ? make(cond) : "").replace(/;*\s*$/, ";" + space); + step = (step != null ? make(step) : "").replace(/;*\s*$/, ""); + var args = init + cond + step; + if (args == "; ; ") args = ";;"; + out.push("(" + args + ")", make(block)); + return add_spaces(out); + }, + "for-in": function(has_var, key, hash, block) { + var out = add_spaces([ "for", "(" ]); + if (has_var) + out += "var "; + out += add_spaces([ make_name(key) + " in " + make(hash) + ")", make(block) ]); + return out; + }, + "while": function(condition, block) { + return add_spaces([ "while", "(" + make(condition) + ")", make(block) ]); + }, + "do": function(condition, block) { + return add_spaces([ "do", make(block), "while", "(" + make(condition) + ")" ]) + ";"; + }, + "return": function(expr) { + var out = [ "return" ]; + if (expr != null) out.push(make(expr)); + return add_spaces(out) + ";"; + }, + "binary": function(operator, lvalue, rvalue) { + var left = make(lvalue), right = make(rvalue); + // XXX: I'm pretty sure other cases will bite here. + // we need to be smarter. + // adding parens all the time is the safest bet. + if (member(lvalue[0], [ "assign", "conditional", "seq" ]) || + lvalue[0] == "binary" && PRECEDENCE[operator] > PRECEDENCE[lvalue[1]]) { + left = "(" + left + ")"; + } + if (member(rvalue[0], [ "assign", "conditional", "seq" ]) || + rvalue[0] == "binary" && PRECEDENCE[operator] >= PRECEDENCE[rvalue[1]]) { + right = "(" + right + ")"; + } + return add_spaces([ left, operator, right ]); + }, + "unary-prefix": function(operator, expr) { + var val = make(expr); + if (!(expr[0] == "num" || (expr[0] == "unary-prefix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr))) + val = "(" + val + ")"; + return operator + (jsp.is_alphanumeric_char(operator.charAt(0)) ? " " : "") + val; + }, + "unary-postfix": function(operator, expr) { + var val = make(expr); + if (!(expr[0] == "num" || (expr[0] == "unary-postfix" && !HOP(OPERATORS, operator + expr[1])) || !needs_parens(expr))) + val = "(" + val + ")"; + return val + operator; + }, + "sub": function(expr, subscript) { + var hash = make(expr); + if (needs_parens(expr)) + hash = "(" + hash + ")"; + return hash + "[" + make(subscript) + "]"; + }, + "object": function(props) { + if (props.length == 0) + return "{}"; + return "{" + newline + with_indent(function(){ + return MAP(props, function(p){ + if (p.length == 3) { + // getter/setter. The name is in p[0], the arg.list in p[1][2], the + // body in p[1][3] and type ("get" / "set") in p[2]. + return indent(make_function(p[0], p[1][2], p[1][3], p[2])); + } + var key = p[0], val = make(p[1]); + if (beautify && beautify.quote_keys) { + key = make_string(key); + } else if (typeof key == "number" || !beautify && +key + "" == key) { + key = make_num(+key); + } else if (!is_identifier(key)) { + key = make_string(key); + } + return indent(add_spaces(beautify && beautify.space_colon + ? [ key, ":", val ] + : [ key + ":", val ])); + }).join("," + newline); + }) + newline + indent("}"); + }, + "regexp": function(rx, mods) { + return "/" + rx + "/" + mods; + }, + "array": function(elements) { + if (elements.length == 0) return "[]"; + return add_spaces([ "[", add_commas(MAP(elements, function(el){ + return parenthesize(el, "seq"); + })), "]" ]); + }, + "stat": function(stmt) { + return make(stmt).replace(/;*\s*$/, ";"); + }, + "seq": function() { + return add_commas(MAP(slice(arguments), make)); + }, + "label": function(name, block) { + return add_spaces([ make_name(name), ":", make(block) ]); + }, + "with": function(expr, block) { + return add_spaces([ "with", "(" + make(expr) + ")", make(block) ]); + }, + "atom": function(name) { + return make_name(name); + }, + "comment1": function(text) { + return "//" + text + "\n"; + }, + "comment2": function(text) { + return "/*" + text + "*/"; + } + }; + + // The squeezer replaces "block"-s that contain only a single + // statement with the statement itself; technically, the AST + // is correct, but this can create problems when we output an + // IF having an ELSE clause where the THEN clause ends in an + // IF *without* an ELSE block (then the outer ELSE would refer + // to the inner IF). This function checks for this case and + // adds the block brackets if needed. + function make_then(th) { + if (th[0] == "do") { + // https://github.com/mishoo/UglifyJS/issues/#issue/57 + // IE croaks with "syntax error" on code like this: + // if (foo) do ... while(cond); else ... + // we need block brackets around do/while + return make([ "block", [ th ]]); + } + var b = th; + while (true) { + var type = b[0]; + if (type == "if") { + if (!b[3]) + // no else, we must add the block + return make([ "block", [ th ]]); + b = b[3]; + } + else if (type == "while" || type == "do") b = b[2]; + else if (type == "for" || type == "for-in") b = b[4]; + else break; + } + return make(th); + }; + + function make_function(name, args, body, keyword) { + var out = keyword || "function"; + if (name) { + out += " " + make_name(name); + } + out += "(" + add_commas(MAP(args, make_name)) + ")"; + return add_spaces([ out, make_block(body) ]); + }; + + function make_name(name) { + return name.toString(); + }; + + function make_block_statements(statements) { + for (var a = [], last = statements.length - 1, i = 0; i <= last; ++i) { + var stat = statements[i]; + var code = make(stat); + if (code != ";") { + if (!beautify && i == last) + code = code.replace(/;+\s*$/, ""); + a.push(code); + } + } + return MAP(a, indent); + }; + + function make_switch_block(body) { + var n = body.length; + if (n == 0) return "{}"; + return "{" + newline + MAP(body, function(branch, i){ + var has_body = branch[1].length > 0, code = with_indent(function(){ + return indent(branch[0] + ? add_spaces([ "case", make(branch[0]) + ":" ]) + : "default:"); + }, 0.5) + (has_body ? newline + with_indent(function(){ + return make_block_statements(branch[1]).join(newline); + }) : ""); + if (!beautify && has_body && i < n - 1) + code += ";"; + return code; + }).join(newline) + newline + indent("}"); + }; + + function make_block(statements) { + if (!statements) return ";"; + if (statements.length == 0) return "{}"; + return "{" + newline + with_indent(function(){ + return make_block_statements(statements).join(newline); + }) + newline + indent("}"); + }; + + function make_1vardef(def) { + var name = def[0], val = def[1]; + if (val != null) + name = add_spaces([ name, "=", make(val) ]); + return name; + }; + + var $stack = []; + + function make(node) { + var type = node[0]; + var gen = generators[type]; + if (!gen) + throw new Error("Can't find generator for \"" + type + "\""); + $stack.push(node); + var ret = gen.apply(type, node.slice(1)); + $stack.pop(); + return ret; + }; + + return make(ast); +}; + +/* -----[ Utilities ]----- */ + +function repeat_string(str, i) { + if (i <= 0) return ""; + if (i == 1) return str; + var d = repeat_string(str, i >> 1); + d += d; + if (i & 1) d += str; + return d; +}; + +function defaults(args, defs) { + var ret = {}; + if (args === true) + args = {}; + for (var i in defs) if (HOP(defs, i)) { + ret[i] = (args && HOP(args, i)) ? args[i] : defs[i]; + } + return ret; +}; + +function is_identifier(name) { + return /^[a-z_$][a-z0-9_$]*$/i.test(name) + && name != "this" + && !HOP(jsp.KEYWORDS_ATOM, name) + && !HOP(jsp.RESERVED_WORDS, name) + && !HOP(jsp.KEYWORDS, name); +}; + +function HOP(obj, prop) { + return Object.prototype.hasOwnProperty.call(obj, prop); +}; + +// some utilities + +var MAP; + +(function(){ + MAP = function(a, f, o) { + var ret = []; + for (var i = 0; i < a.length; ++i) { + var val = f.call(o, a[i], i); + if (val instanceof AtTop) ret.unshift(val.v); + else ret.push(val); + } + return ret; + }; + MAP.at_top = function(val) { return new AtTop(val) }; + function AtTop(val) { this.v = val }; +})(); + +/* -----[ Exports ]----- */ + +exports.ast_walker = ast_walker; +exports.ast_mangle = ast_mangle; +exports.ast_squeeze = ast_squeeze; +exports.gen_code = gen_code; +exports.ast_add_scope = ast_add_scope; +exports.ast_squeeze_more = require("./squeeze-more").ast_squeeze_more; +exports.set_logger = function(logger) { warn = logger }; diff --git a/Source/WebCore/inspector/front-end/WebKit.qrc b/Source/WebCore/inspector/front-end/WebKit.qrc index 80a6533..edc1861 100644 --- a/Source/WebCore/inspector/front-end/WebKit.qrc +++ b/Source/WebCore/inspector/front-end/WebKit.qrc @@ -23,6 +23,7 @@ <file>CookieParser.js</file> <file>CookiesTable.js</file> <file>CSSCompletions.js</file> + <file>CSSKeywordCompletions.js</file> <file>CSSStyleModel.js</file> <file>Database.js</file> <file>DatabaseQueryView.js</file> @@ -51,7 +52,6 @@ <file>HelpScreen.js</file> <file>ImageView.js</file> <file>InjectedFakeWorker.js</file> - <file>InjectedScriptAccess.js</file> <file>inspector.js</file> <file>InspectorFrontendHostStub.js</file> <file>KeyboardShortcut.js</file> @@ -81,6 +81,8 @@ <file>ResourcesPanel.js</file> <file>ScopeChainSidebarPane.js</file> <file>Script.js</file> + <file>ScriptFormatter.js</file> + <file>ScriptFormatterWorker.js</file> <file>ScriptsPanel.js</file> <file>ScriptView.js</file> <file>Section.js</file> @@ -114,6 +116,8 @@ <file>WatchExpressionsSidebarPane.js</file> <file>WelcomeView.js</file> <file>WorkersSidebarPane.js</file> + <file>UglifyJS/parse-js.js</file> + <file>UglifyJS/process.js</file> <file>audits.css</file> <file>goToLineDialog.css</file> <file>heapProfiler.css</file> diff --git a/Source/WebCore/inspector/front-end/inspector.css b/Source/WebCore/inspector/front-end/inspector.css index c908427..f629d12 100644 --- a/Source/WebCore/inspector/front-end/inspector.css +++ b/Source/WebCore/inspector/front-end/inspector.css @@ -778,8 +778,8 @@ body.platform-linux .monospace, body.platform-linux .source-code { color: red; } -.auto-complete-text { - color: rgb(128, 128, 128); +.auto-complete-text, .editing .auto-complete-text { + color: rgb(128, 128, 128) !important; -webkit-user-select: none; -webkit-user-modify: read-only; } diff --git a/Source/WebCore/inspector/front-end/inspector.html b/Source/WebCore/inspector/front-end/inspector.html index 44f096f..0e0b9e9 100644 --- a/Source/WebCore/inspector/front-end/inspector.html +++ b/Source/WebCore/inspector/front-end/inspector.html @@ -92,6 +92,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="EventListenersSidebarPane.js"></script> <script type="text/javascript" src="Color.js"></script> <script type="text/javascript" src="CSSCompletions.js"></script> + <script type="text/javascript" src="CSSKeywordCompletions.js"></script> <script type="text/javascript" src="StylesSidebarPane.js"></script> <script type="text/javascript" src="PanelEnablerView.js"></script> <script type="text/javascript" src="WelcomeView.js"></script> @@ -121,6 +122,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="NetworkItemView.js"></script> <script type="text/javascript" src="ResourceView.js"></script> <script type="text/javascript" src="SourceFrame.js"></script> + <script type="text/javascript" src="ScriptFormatter.js"></script> <script type="text/javascript" src="DOMSyntaxHighlighter.js"></script> <script type="text/javascript" src="TextEditorModel.js"></script> <script type="text/javascript" src="TextEditorHighlighter.js"></script> @@ -142,7 +144,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="HeapSnapshotView.js"></script> <script type="text/javascript" src="DebuggerModel.js"></script> <script type="text/javascript" src="DOMAgent.js"></script> - <script type="text/javascript" src="InjectedScriptAccess.js"></script> <script type="text/javascript" src="TimelineAgent.js"></script> <script type="text/javascript" src="TimelinePanel.js"></script> <script type="text/javascript" src="TimelineOverviewPane.js"></script> diff --git a/Source/WebCore/inspector/front-end/inspector.js b/Source/WebCore/inspector/front-end/inspector.js index d8a93b1..77abe78 100644 --- a/Source/WebCore/inspector/front-end/inspector.js +++ b/Source/WebCore/inspector/front-end/inspector.js @@ -185,20 +185,9 @@ var WebInspector = { } }, - createJSBreakpointsSidebarPane: function() - { - var pane = new WebInspector.BreakpointsSidebarPane(WebInspector.UIString("Breakpoints")); - function breakpointAdded(event) - { - pane.addBreakpointItem(new WebInspector.BreakpointItem(event.data)); - } - WebInspector.debuggerModel.addEventListener(WebInspector.DebuggerModel.Events.BreakpointAdded, breakpointAdded); - return pane; - }, - createDOMBreakpointsSidebarPane: function() { - var pane = new WebInspector.BreakpointsSidebarPane(WebInspector.UIString("DOM Breakpoints")); + var pane = new WebInspector.NativeBreakpointsSidebarPane(WebInspector.UIString("DOM Breakpoints")); function breakpointAdded(event) { pane.addBreakpointItem(new WebInspector.BreakpointItem(event.data)); @@ -534,7 +523,7 @@ WebInspector.doLoadedDone = function() scripts: new WebInspector.ResourceCategory("scripts", WebInspector.UIString("Scripts"), "rgb(255,121,0)"), xhr: new WebInspector.ResourceCategory("xhr", WebInspector.UIString("XHR"), "rgb(231,231,10)"), fonts: new WebInspector.ResourceCategory("fonts", WebInspector.UIString("Fonts"), "rgb(255,82,62)"), - websockets: new WebInspector.ResourceCategory("websockets", WebInspector.UIString("WebSocket"), "rgb(186,186,186)"), // FIXME: Decide the color. + websockets: new WebInspector.ResourceCategory("websockets", WebInspector.UIString("WebSockets"), "rgb(186,186,186)"), // FIXME: Decide the color. other: new WebInspector.ResourceCategory("other", WebInspector.UIString("Other"), "rgb(186,186,186)") }; @@ -601,14 +590,6 @@ WebInspector.doLoadedDone = function() this.extensionServer.initExtensions(); - function populateInspectorState(inspectorState) - { - WebInspector.monitoringXHREnabled = inspectorState.monitoringXHREnabled; - if ("pauseOnExceptionsState" in inspectorState) - WebInspector.panels.scripts.updatePauseOnExceptionsState(inspectorState.pauseOnExceptionsState); - } - InspectorBackend.getInspectorState(populateInspectorState); - function onPopulateScriptObjects() { if (!WebInspector.currentPanel) diff --git a/Source/WebCore/inspector/front-end/utilities.js b/Source/WebCore/inspector/front-end/utilities.js index 4320ba8..5ed9a8c 100644 --- a/Source/WebCore/inspector/front-end/utilities.js +++ b/Source/WebCore/inspector/front-end/utilities.js @@ -745,6 +745,22 @@ Object.defineProperty(Array.prototype, "keySet", { value: function() return keys; }}); +Object.defineProperty(Array.prototype, "upperBound", { value: function(value) +{ + var first = 0; + var count = this.length; + while (count > 0) { + var step = count >> 1; + var middle = first + step; + if (value >= this[middle]) { + first = middle + 1; + count -= step + 1; + } else + count = step; + } + return first; +}}); + Array.diff = function(left, right) { var o = left; |