diff options
Diffstat (limited to 'WebCore/inspector')
49 files changed, 2033 insertions, 367 deletions
diff --git a/WebCore/inspector/CodeGeneratorInspector.pm b/WebCore/inspector/CodeGeneratorInspector.pm index be0948b..d76fbd3 100644 --- a/WebCore/inspector/CodeGeneratorInspector.pm +++ b/WebCore/inspector/CodeGeneratorInspector.pm @@ -120,7 +120,7 @@ $typeTransform{"boolean"} = { "defaultValue" => "false", "forward" => "", "header" => "", - "JSONType" => "Bool" + "JSONType" => "Boolean" }; $typeTransform{"void"} = { "forward" => "", @@ -211,7 +211,7 @@ sub GenerateInterface $backendJSStubName = $className . "BackendStub"; my @backendHead; push(@backendHead, " ${backendClassName}(InspectorController* inspectorController) : m_inspectorController(inspectorController) { }"); - push(@backendHead, " void reportProtocolError(const long callId, const String& method, const String& errorText) const;"); + 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); @@ -306,7 +306,7 @@ sub generateBackendFunction my $domainAccessor = $typeTransform{$domain}->{"domainAccessor"}; $backendTypes{$domain} = 1; push(@function, " if (!$domainAccessor)"); - push(@function, " protocolErrors->pushString(String::format(\"Error: %s handler is not available.\", \"$domain\"));"); + push(@function, " protocolErrors->pushString(String::format(\"Protocol Error: %s handler is not available.\", \"$domain\"));"); push(@function, ""); if (scalar(@inArgs)) { @@ -316,8 +316,7 @@ sub generateBackendFunction push(@function, ""); push(@function, " RefPtr<InspectorObject> argumentsContainer;"); push(@function, " if (!(argumentsContainer = requestMessageObject->getObject(\"arguments\"))) {"); - push(@function, " ASSERT_NOT_REACHED();"); - push(@function, " protocolErrors->pushString(String::format(\"Error: arguments object was not found.\"));"); + push(@function, " protocolErrors->pushString(String::format(\"Protocol Error: 'arguments' property with type 'object' was not found.\"));"); push(@function, " } else {"); push(@function, " InspectorObject::const_iterator argumentsEndIterator = argumentsContainer->end();"); @@ -330,12 +329,10 @@ sub generateBackendFunction push(@function, ""); push(@function, " InspectorObject::const_iterator ${name}ValueIterator = argumentsContainer->find(\"$name\");"); push(@function, " if (${name}ValueIterator == argumentsEndIterator) {"); - push(@function, " ASSERT_NOT_REACHED();"); - push(@function, " protocolErrors->pushString(String::format(\"Error: Argument '%s' with type '%s' was not found.\", \"$name\", \"$JSONType\"));"); + push(@function, " protocolErrors->pushString(String::format(\"Protocol Error: Argument '%s' with type '%s' was not found.\", \"$name\", \"$JSONType\"));"); push(@function, " } else {"); push(@function, " if (!${name}ValueIterator->second->as$JSONType(&$name)) {"); - push(@function, " ASSERT_NOT_REACHED();"); - push(@function, " protocolErrors->pushString(String::format(\"Error: Argument '%s' has wrong type. It should be '%s'.\", \"$name\", \"$JSONType\"));"); + push(@function, " protocolErrors->pushString(String::format(\"Protocol Error: Argument '%s' has wrong type. It should be '%s'.\", \"$name\", \"$JSONType\"));"); push(@function, " }"); push(@function, " }"); } @@ -351,13 +348,10 @@ sub generateBackendFunction push(@function, ""); push(@function, " // use InspectorFrontend as a marker of WebInspector availability"); - push(@function, " if (callId && m_inspectorController->hasFrontend()) {"); + push(@function, " if ((callId || protocolErrors->length()) && m_inspectorController->hasFrontend()) {"); push(@function, " RefPtr<InspectorObject> responseMessage = InspectorObject::create();"); push(@function, " responseMessage->setNumber(\"seq\", callId);"); - push(@function, " responseMessage->setString(\"type\", \"response\");"); - push(@function, " responseMessage->setString(\"domain\", \"$domain\");"); - push(@function, " responseMessage->setString(\"command\", \"$functionName\");"); - push(@function, " responseMessage->setBool(\"success\", !protocolErrors->length());"); + push(@function, " responseMessage->setBoolean(\"success\", !protocolErrors->length());"); push(@function, ""); push(@function, " if (protocolErrors->length())"); push(@function, " responseMessage->setArray(\"errors\", protocolErrors);"); @@ -381,14 +375,11 @@ sub generateBackendReportProtocolError { my $reportProtocolError = << "EOF"; -void ${backendClassName}::reportProtocolError(const long callId, const String& method, const String& errorText) const +void ${backendClassName}::reportProtocolError(const long callId, const String& errorText) const { RefPtr<InspectorObject> message = InspectorObject::create(); message->setNumber("seq", callId); - message->setString("type", "error"); - message->setString("domain", "inspectorProtocol"); - message->setString("command", method); - message->setBool("success", false); + message->setBoolean("success", false); RefPtr<InspectorArray> errors = InspectorArray::create(); errors->pushString(errorText); message->setArray("errors", errors); @@ -420,49 +411,42 @@ $mapEntries RefPtr<InspectorValue> parsedMessage = InspectorValue::parseJSON(message); if (!parsedMessage) { - ASSERT_NOT_REACHED(); - reportProtocolError(callId, "dispatch", "Error: Invalid message format. Message should be in JSON format."); + reportProtocolError(callId, "Protocol Error: Invalid message format. Message should be in JSON format."); return; } RefPtr<InspectorObject> messageObject = parsedMessage->asObject(); if (!messageObject) { - ASSERT_NOT_REACHED(); - reportProtocolError(callId, "dispatch", "Error: Invalid message format. The message should be a JSONified object."); + reportProtocolError(callId, "Protocol Error: Invalid message format. The message should be a JSONified object."); return; } - RefPtr<InspectorValue> callIdValue = messageObject->get("seq"); - if (!callIdValue) { - ASSERT_NOT_REACHED(); - reportProtocolError(callId, "dispatch", "Error: Invalid message format. 'seq' property was not found in the request."); + RefPtr<InspectorValue> commandValue = messageObject->get("command"); + if (!commandValue) { + reportProtocolError(callId, "Protocol Error: Invalid message format. 'command' property wasn't found."); return; } - if (!callIdValue->asNumber(&callId)) { - ASSERT_NOT_REACHED(); - reportProtocolError(callId, "dispatch", "Error: Invalid message format. the type of 'seq' property should be number."); + String command; + if (!commandValue->asString(&command)) { + reportProtocolError(callId, "Protocol Error: Invalid message format. The type of 'command' property should be string."); return; } - RefPtr<InspectorValue> commandValue = messageObject->get("command"); - if (!commandValue) { - ASSERT_NOT_REACHED(); - reportProtocolError(callId, "dispatch", "Error: Invalid message format. 'command' property wasn't found."); + RefPtr<InspectorValue> callIdValue = messageObject->get("seq"); + if (!callIdValue) { + reportProtocolError(callId, "Protocol Error: Invalid message format. 'seq' property was not found in the request."); return; } - String command; - if (!commandValue->asString(&command)) { - ASSERT_NOT_REACHED(); - reportProtocolError(callId, "dispatch", "Error: Invalid message format. The type of 'command' property should be string."); + if (!callIdValue->asNumber(&callId)) { + reportProtocolError(callId, "Protocol Error: Invalid message format. The type of 'seq' property should be number."); return; } HashMap<String, CallHandler>::iterator it = dispatchMap.find(command); if (it == dispatchMap.end()) { - ASSERT_NOT_REACHED(); - reportProtocolError(callId, "dispatch", String::format("Error: Invalid command was received. '%s' wasn't found.", command.utf8().data())); + reportProtocolError(callId, String::format("Protocol Error: Invalid command was received. '%s' wasn't found.", command.utf8().data())); return; } @@ -505,10 +489,9 @@ sub generateBackendStubJS foreach my $function (@backendFunctions) { my $name = $function->signature->name; my $domain = $function->signature->extendedAttributes->{"handler"}; - my $argumentNames = join(",", map("\"" . $_->name . "\": null", grep($_->direction eq "in", @{$function->parameters}))); + my $argumentNames = join(",", map("\"" . $_->name . "\": \"" . lc($typeTransform{$_->type}->{"JSONType"}) . "\"", grep($_->direction eq "in", @{$function->parameters}))); push(@JSStubs, " this._registerDelegate('{" . "\"seq\": 0, " . - "\"type\": \"request\", " . "\"domain\": \"$domain\", " . "\"command\": \"$name\", " . "\"arguments\": {$argumentNames}" . @@ -535,14 +518,27 @@ WebInspector.InspectorBackendStub.prototype = { { var args = Array.prototype.slice.call(arguments); var request = JSON.parse(args.shift()); + for (var key in request.arguments) { - if (key === "callId") - request.seq = args.shift(); - else - request.arguments[key] = args.shift(); + if (args.length === 0) { + console.error("Protocol Error: Invalid number of arguments for 'InspectorBackend.%s' call. It should have the next arguments '%s'.", request.command, JSON.stringify(request.arguments)); + return; + } + var value = args.shift(); + if (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; + } + request.arguments[key] = value; } - if (args.length === 1 && typeof args[0] === "function") + + if (args.length === 1) { + if (typeof args[0] !== "function") { + console.error("Protocol Error: Optional callback argument for 'InspectorBackend.%s' call should be a function but its type is '%s'.", request.command, typeof args[0]); + return; + } request.seq = WebInspector.Callback.wrap(args[0]); + } var message = JSON.stringify(request); InspectorFrontendHost.sendMessageToBackend(message); diff --git a/WebCore/inspector/Inspector.idl b/WebCore/inspector/Inspector.idl index a56ef14..ff1c2af 100644 --- a/WebCore/inspector/Inspector.idl +++ b/WebCore/inspector/Inspector.idl @@ -102,7 +102,7 @@ module core { // This method is going to be broken down into smaller parts. [handler=Controller] void populateScriptObjects(); - [handler=Controller] void getSettings(in long callId, out Object settings); + [handler=Controller] void getSettings(out Object settings); [handler=Controller] void storeLastActivePanel(in String panelName); [handler=Controller] void saveApplicationSettings(in String settings); @@ -116,7 +116,7 @@ module core { [handler=Controller] void enableResourceTracking(in boolean always); [handler=Controller] void disableResourceTracking(in boolean always); - [handler=Controller] void getResourceContent(in long callId, in unsigned long identifier, out String content); + [handler=Controller] void getResourceContent(in unsigned long identifier, out String content); [handler=Controller] void reloadPage(); [handler=Controller] void startTimelineProfiler(); @@ -126,7 +126,7 @@ module core { [handler=Backend] void enableDebugger(in boolean always); [handler=Controller] void disableDebugger(in boolean always); - [handler=Debug] void setBreakpoint(in long callId, in String sourceID, in unsigned int lineNumber, in boolean enabled, in String condition, out boolean success, out unsigned int actualLineNumber); + [handler=Debug] void setBreakpoint(in String sourceID, in unsigned int lineNumber, in boolean enabled, in String condition, out boolean success, out unsigned int actualLineNumber); [handler=Debug] void removeBreakpoint(in String sourceID, in unsigned long lineNumber); [handler=Debug] void activateBreakpoints(); [handler=Debug] void deactivateBreakpoints(); @@ -140,8 +140,8 @@ module core { [handler=Debug] void setPauseOnExceptionsState(in long pauseOnExceptionsState); - [handler=Debug] void editScriptSource(in long callId, in String sourceID, in String newContent, out boolean success, out String result, out Value newCallFrames); - [handler=Debug] void getScriptSource(in long callId, in String sourceID, out String scriptSource); + [handler=Debug] void editScriptSource(in String sourceID, in String newContent, out boolean success, out String result, out Value newCallFrames); + [handler=Debug] void getScriptSource(in String sourceID, out String scriptSource); [handler=Controller] void enableProfiler(in boolean always); [handler=Controller] void disableProfiler(in boolean always); @@ -149,34 +149,33 @@ module core { [handler=Profiler] void startProfiling(); [handler=Profiler] void stopProfiling(); - [handler=Profiler] void getProfileHeaders(in long callId, out Array headers); - [handler=Profiler] void getProfile(in long callId, in unsigned long uid, out Object profile); + [handler=Profiler] void getProfileHeaders(out Array headers); + [handler=Profiler] void getProfile(in String type, in unsigned long uid, out Object profile); - [handler=Profiler] void removeProfile(in unsigned long uid); + [handler=Profiler] void removeProfile(in String type, in unsigned long uid); [handler=Profiler] void clearProfiles(); - [handler=Backend] void takeHeapSnapshot(); - [handler=Backend] void getProfilerLogLines(in long callId, in long inPosition, out long outPosition, out String log); + [handler=Profiler] void takeHeapSnapshot(); #endif [handler=Backend] void setInjectedScriptSource(in String scriptSource); - [handler=Backend] void dispatchOnInjectedScript(in long callId, in long injectedScriptId, in String methodName, in String arguments, out Value result, out boolean isException); + [handler=Backend] void dispatchOnInjectedScript(in long injectedScriptId, in String methodName, in String arguments, out Value result, out boolean isException); [handler=Controller] void addScriptToEvaluateOnLoad(in String scriptSource); [handler=Controller] void removeAllScriptsToEvaluateOnLoad(); - [handler=DOM] void getChildNodes(in long callId, in long nodeId); - [handler=DOM] void setAttribute(in long callId, in long elementId, in String name, in String value, out boolean success); - [handler=DOM] void removeAttribute(in long callId, in long elementId, in String name, out boolean success); - [handler=DOM] void setTextNodeValue(in long callId, in long nodeId, in String value, out boolean success); - [handler=DOM] void getEventListenersForNode(in long callId, in long nodeId, out long outNodeId, out Array listenersArray); + [handler=DOM] void getChildNodes(in long nodeId); + [handler=DOM] void setAttribute(in long elementId, in String name, in String value, out boolean success); + [handler=DOM] void removeAttribute(in long elementId, in String name, out boolean success); + [handler=DOM] void setTextNodeValue(in long nodeId, in String value, out boolean success); + [handler=DOM] void getEventListenersForNode(in long nodeId, out long outNodeId, out Array listenersArray); [handler=DOM] void copyNode(in long nodeId); - [handler=DOM] void removeNode(in long callId, in long nodeId, out long outNodeId); - [handler=DOM] void changeTagName(in long callId, in long nodeId, in String newTagName, out long outNodeId); - [handler=DOM] void getOuterHTML(in long callId, in long nodeId, out String outerHTML); - [handler=DOM] void setOuterHTML(in long callId, in long nodeId, in String outerHTML, out long outNodeId); + [handler=DOM] void removeNode(in long nodeId, out long outNodeId); + [handler=DOM] void changeTagName(in long nodeId, in String newTagName, out long outNodeId); + [handler=DOM] void getOuterHTML(in long nodeId, out String outerHTML); + [handler=DOM] void setOuterHTML(in long nodeId, in String outerHTML, out long outNodeId); [handler=DOM] void addInspectedNode(in long nodeId); [handler=DOM] void performSearch(in String query, in boolean runSynchronously); [handler=DOM] void searchCanceled(); - [handler=DOM] void pushNodeByPathToFrontend(in long callId, in String path, out long nodeId); + [handler=DOM] void pushNodeByPathToFrontend(in String path, out long nodeId); [handler=DOM] void setDOMBreakpoint(in long nodeId, in long type); [handler=DOM] void removeDOMBreakpoint(in long nodeId, in long type); @@ -185,41 +184,41 @@ module core { [handler=Controller] void hideDOMNodeHighlight(); [handler=Controller] void openInInspectedWindow(in String url); - [handler=DOM] void getStyles(in long callId, in long nodeId, in boolean authOnly, out Value styles); - [handler=DOM] void getAllStyles(in long callId, out Array styles); - [handler=DOM] void getInlineStyle(in long callId, in long nodeId, out Value style); - [handler=DOM] void getComputedStyle(in long callId, in long nodeId, out Value style); - [handler=DOM] void getStyleSheet(in long callId, in long styleSheetId, out Object styleSheet); - [handler=DOM] void getRuleRanges(in long callId, in long styleSheetId, out Value ranges); - [handler=DOM] void applyStyleText(in long callId, in long styleId, in String styleText, in String propertyName, out boolean success, out Value style, out Array changedProperties); - [handler=DOM] void setStyleText(in long callId, in long styleId, in String styleText, out boolean success); - [handler=DOM] void setStyleProperty(in long callId, in long styleId, in String name, in String value, out boolean success); - [handler=DOM] void toggleStyleEnabled(in long callId, in long styleId, in String propertyName, in boolean disabled, out Value style); - [handler=DOM] void setRuleSelector(in long callId, in long ruleId, in String selector, in long selectedNodeId, out Value rule, out boolean selectorAffectsNode); - [handler=DOM] void addRule(in long callId, in String selector, in long selectedNodeId, out Value rule, out boolean selectorAffectsNode); - [handler=DOM] void getSupportedCSSProperties(in long callId, out Array cssProperties); - - [handler=Controller] void getCookies(in long callId, out Array cookies, out String cookiesString); + [handler=DOM] void getStyles(in long nodeId, in boolean authOnly, out Value styles); + [handler=DOM] void getAllStyles(out Array styles); + [handler=DOM] void getInlineStyle(in long nodeId, out Value style); + [handler=DOM] void getComputedStyle(in long nodeId, out Value style); + [handler=DOM] void getStyleSheet(in long styleSheetId, out Object styleSheet); + [handler=DOM] void getRuleRanges(in long styleSheetId, out Value ranges); + [handler=DOM] void applyStyleText(in long styleId, in String styleText, in String propertyName, out boolean success, out Value style, out Array changedProperties); + [handler=DOM] void setStyleText(in long styleId, in String styleText, out boolean success); + [handler=DOM] void setStyleProperty(in long styleId, in String name, in String value, out boolean success); + [handler=DOM] void toggleStyleEnabled(in long styleId, in String propertyName, in boolean disabled, out Value style); + [handler=DOM] void setRuleSelector(in long ruleId, in String selector, in long selectedNodeId, out Value rule, out boolean selectorAffectsNode); + [handler=DOM] void addRule(in String selector, in long selectedNodeId, out Value rule, out boolean selectorAffectsNode); + [handler=DOM] void getSupportedCSSProperties(out Array cssProperties); + + [handler=Controller] void getCookies(out Array cookies, out String cookiesString); [handler=Controller] void deleteCookie(in String cookieName, in String domain); #if defined(ENABLE_OFFLINE_WEB_APPLICATIONS) && ENABLE_OFFLINE_WEB_APPLICATIONS - [handler=ApplicationCache] void getApplicationCaches(in long callId, out Value applicationCaches); + [handler=ApplicationCache] void getApplicationCaches(out Value applicationCaches); #endif [handler=Backend] void releaseWrapperObjectGroup(in long injectedScriptId, in String objectGroup); [handler=Controller] void didEvaluateForTestInFrontend(in long testCallId, in String jsonResult); #if defined(ENABLE_DATABASE) && ENABLE_DATABASE - [handler=Backend] void getDatabaseTableNames(in long callId, in long databaseId, out Array tableNames); - [handler=Backend] void executeSQL(in long callId, in long databaseId, in String query, out boolean success, out long transactionId); + [handler=Backend] void getDatabaseTableNames(in long databaseId, out Array tableNames); + [handler=Backend] void executeSQL(in long databaseId, in String query, out boolean success, out long transactionId); [notify] void sqlTransactionSucceeded(out long transactionId, out Value columnNames, out Value values); [notify] void sqlTransactionFailed(out long transactionId, out Value sqlError); #endif #if defined(ENABLE_DOM_STORAGE) && ENABLE_DOM_STORAGE - [handler=Controller] void getDOMStorageEntries(in long callId, in long storageId, out Array entries); - [handler=Controller] void setDOMStorageItem(in long callId, in long storageId, in String key, in String value, out boolean success); - [handler=Controller] void removeDOMStorageItem(in long callId, in long storageId, in String key, out boolean success); + [handler=Controller] void getDOMStorageEntries(in long storageId, out Array entries); + [handler=Controller] void setDOMStorageItem(in long storageId, in String key, in String value, out boolean success); + [handler=Controller] void removeDOMStorageItem(in long storageId, in String key, out boolean success); #endif }; } diff --git a/WebCore/inspector/InspectorBackend.cpp b/WebCore/inspector/InspectorBackend.cpp index 99f40a9..791e3a6 100644 --- a/WebCore/inspector/InspectorBackend.cpp +++ b/WebCore/inspector/InspectorBackend.cpp @@ -68,17 +68,6 @@ void InspectorBackend::enableDebugger(bool always) m_inspectorController->enableDebuggerFromFrontend(always); } -void InspectorBackend::takeHeapSnapshot() -{ - ScriptProfiler::takeHeapSnapshot(); -} - -void InspectorBackend::getProfilerLogLines(long position, long* outPosition, String* data) -{ - // FIXME: we should make inspector dispatcher pluggable, so that embedders could contribute APIs instead of polluting the core one - // https://bugs.webkit.org/show_bug.cgi?id=43357 - *outPosition = ScriptProfiler::getProfilerLogLines(position, data); -} #endif void InspectorBackend::setInjectedScriptSource(const String& source) diff --git a/WebCore/inspector/InspectorBackend.h b/WebCore/inspector/InspectorBackend.h index 23b31a3..1fcec96 100644 --- a/WebCore/inspector/InspectorBackend.h +++ b/WebCore/inspector/InspectorBackend.h @@ -60,8 +60,6 @@ public: #if ENABLE(JAVASCRIPT_DEBUGGER) void enableDebugger(bool always); - void takeHeapSnapshot(); - void getProfilerLogLines(long position, long* outPosition, String* data); #endif void setInjectedScriptSource(const String& source); diff --git a/WebCore/inspector/InspectorController.cpp b/WebCore/inspector/InspectorController.cpp index f47b321..7fb052c 100644 --- a/WebCore/inspector/InspectorController.cpp +++ b/WebCore/inspector/InspectorController.cpp @@ -490,24 +490,6 @@ void InspectorController::connectFrontend() // Initialize Web Inspector title. m_frontend->inspectedURLChanged(m_inspectedPage->mainFrame()->loader()->url().string()); -#if ENABLE(JAVASCRIPT_DEBUGGER) - if (InspectorDebuggerAgent::isDebuggerAlwaysEnabled()) { - // FIXME (40364): This will force pushing script sources to frontend even if script - // panel is inactive. - enableDebuggerFromFrontend(false); - } else { - String debuggerEnabled = setting(debuggerEnabledSettingName); - if (debuggerEnabled == "true" || m_attachDebuggerWhenShown) - enableDebugger(); - } - m_profilerAgent->setFrontend(m_frontend.get()); - if (!ScriptProfiler::isProfilerAlwaysEnabled()) { - String profilerEnabledSetting = setting(profilerEnabledSettingName); - if (profilerEnabledSetting == "true") - enableProfiler(); - } -#endif - #if ENABLE(OFFLINE_WEB_APPLICATIONS) m_applicationCacheAgent = new InspectorApplicationCacheAgent(this, m_frontend.get()); #endif @@ -676,6 +658,22 @@ void InspectorController::populateScriptObjects() for (Vector<pair<long, String> >::iterator it = m_pendingEvaluateTestCommands.begin(); it != m_pendingEvaluateTestCommands.end(); ++it) m_frontend->evaluateForTestInFrontend((*it).first, (*it).second); m_pendingEvaluateTestCommands.clear(); + +#if ENABLE(JAVASCRIPT_DEBUGGER) + if (InspectorDebuggerAgent::isDebuggerAlwaysEnabled()) + enableDebuggerFromFrontend(false); + else { + String debuggerEnabled = setting(debuggerEnabledSettingName); + if (debuggerEnabled == "true" || m_attachDebuggerWhenShown) + enableDebugger(); + } + m_profilerAgent->setFrontend(m_frontend.get()); + if (!ScriptProfiler::isProfilerAlwaysEnabled()) { + String profilerEnabledSetting = setting(profilerEnabledSettingName); + if (profilerEnabledSetting == "true") + enableProfiler(); + } +#endif } void InspectorController::unbindAllResources() @@ -1339,9 +1337,9 @@ PassRefPtr<InspectorObject> InspectorController::buildObjectForCookie(const Cook value->setString("path", cookie.path); value->setNumber("expires", cookie.expires); value->setNumber("size", (cookie.name.length() + cookie.value.length())); - value->setBool("httpOnly", cookie.httpOnly); - value->setBool("secure", cookie.secure); - value->setBool("session", cookie.session); + value->setBoolean("httpOnly", cookie.httpOnly); + value->setBoolean("secure", cookie.secure); + value->setBoolean("session", cookie.session); return value; } diff --git a/WebCore/inspector/InspectorDOMAgent.cpp b/WebCore/inspector/InspectorDOMAgent.cpp index b8ae047..d2760e4 100644 --- a/WebCore/inspector/InspectorDOMAgent.cpp +++ b/WebCore/inspector/InspectorDOMAgent.cpp @@ -33,6 +33,7 @@ #if ENABLE(INSPECTOR) +#include "Attr.h" #include "CSSComputedStyleDeclaration.h" #include "CSSMutableStyleDeclaration.h" #include "CSSPropertyNames.h" @@ -538,6 +539,8 @@ void InspectorDOMAgent::setOuterHTML(long nodeId, const String& outerHTML, long* if (!node || !node->isHTMLElement()) return; + bool requiresTotalUpdate = node->nodeName() == "HTML" || node->nodeName() == "BODY" || node->nodeName() == "HEAD"; + bool childrenRequested = m_childrenRequested.contains(nodeId); Node* previousSibling = node->previousSibling(); Node* parentNode = node->parentNode(); @@ -548,8 +551,15 @@ void InspectorDOMAgent::setOuterHTML(long nodeId, const String& outerHTML, long* if (ec) return; - Node* newNode = previousSibling ? previousSibling->nextSibling() : parentNode->firstChild(); + if (requiresTotalUpdate) { + Document* document = mainFrameDocument(); + reset(); + setDocument(document); + *newId = 0; + return; + } + Node* newNode = previousSibling ? previousSibling->nextSibling() : parentNode->firstChild(); *newId = pushNodePathToFrontend(newNode); if (childrenRequested) pushChildNodesToFrontend(*newId); @@ -834,6 +844,10 @@ PassRefPtr<InspectorObject> InspectorDOMAgent::buildObjectForNode(Node* node, in value->setString("publicId", docType->publicId()); value->setString("systemId", docType->systemId()); value->setString("internalSubset", docType->internalSubset()); + } else if (node->nodeType() == Node::ATTRIBUTE_NODE) { + Attr* attribute = static_cast<Attr*>(node); + value->setString("name", attribute->name()); + value->setString("value", attribute->value()); } return value.release(); } @@ -880,8 +894,8 @@ PassRefPtr<InspectorObject> InspectorDOMAgent::buildObjectForEventListener(const RefPtr<EventListener> eventListener = registeredEventListener.listener; RefPtr<InspectorObject> value = InspectorObject::create(); value->setString("type", eventType); - value->setBool("useCapture", registeredEventListener.useCapture); - value->setBool("isAttribute", eventListener->isAttribute()); + value->setBoolean("useCapture", registeredEventListener.useCapture); + value->setBoolean("isAttribute", eventListener->isAttribute()); value->setNumber("nodeId", pushNodePathToFrontend(node)); value->setString("listenerBody", eventListenerHandlerBody(node->document(), eventListener.get())); String sourceName; @@ -1153,14 +1167,14 @@ void InspectorDOMAgent::getAllStyles(RefPtr<InspectorArray>* styles) void InspectorDOMAgent::getStyleSheet(long styleSheetId, RefPtr<InspectorObject>* styleSheetObject) { CSSStyleSheet* styleSheet = cssStore()->styleSheetForId(styleSheetId); - if (styleSheet && styleSheet->doc()) - *styleSheetObject = buildObjectForStyleSheet(styleSheet->doc(), styleSheet); + if (styleSheet && styleSheet->document()) + *styleSheetObject = buildObjectForStyleSheet(styleSheet->document(), styleSheet); } void InspectorDOMAgent::getRuleRanges(long styleSheetId, RefPtr<InspectorValue>* ruleRange) { CSSStyleSheet* styleSheet = cssStore()->styleSheetForId(styleSheetId); - if (styleSheet && styleSheet->doc()) { + if (styleSheet && styleSheet->document()) { HashMap<long, SourceRange> ruleRanges = cssStore()->getRuleRanges(styleSheet); if (!ruleRanges.size()) return; @@ -1460,7 +1474,7 @@ void InspectorDOMAgent::populateObjectWithStyleProperties(CSSStyleDeclaration* s String name = style->item(i); property->setString("name", name); property->setString("priority", style->getPropertyPriority(name)); - property->setBool("implicit", style->isPropertyImplicit(name)); + property->setBoolean("implicit", style->isPropertyImplicit(name)); String shorthand = style->getPropertyShorthand(name); property->setString("shorthand", shorthand); if (!shorthand.isEmpty() && !foundShorthands.contains(shorthand)) { @@ -1492,10 +1506,10 @@ PassRefPtr<InspectorObject> InspectorDOMAgent::buildObjectForStyleSheet(Document RefPtr<InspectorObject> result = InspectorObject::create(); long id = cssStore()->bindStyleSheet(styleSheet); result->setNumber("id", id); - result->setBool("disabled", styleSheet->disabled()); + result->setBoolean("disabled", styleSheet->disabled()); result->setString("href", styleSheet->href()); result->setString("title", styleSheet->title()); - result->setNumber("documentElementId", m_documentNodeToIdMap.get(styleSheet->doc())); + result->setNumber("documentElementId", m_documentNodeToIdMap.get(styleSheet->document())); RefPtr<InspectorArray> cssRules = InspectorArray::create(); PassRefPtr<CSSRuleList> cssRuleList = CSSRuleList::create(styleSheet, true); if (cssRuleList) { @@ -1526,9 +1540,9 @@ PassRefPtr<InspectorObject> InspectorDOMAgent::buildObjectForRule(Document* owne } bool isUserAgent = parentStyleSheet && !parentStyleSheet->ownerNode() && parentStyleSheet->href().isEmpty(); bool isUser = parentStyleSheet && parentStyleSheet->ownerNode() && parentStyleSheet->ownerNode()->nodeName() == "#document"; - result->setBool("isUserAgent", isUserAgent); - result->setBool("isUser", isUser); - result->setBool("isViaInspector", rule->parentStyleSheet() == cssStore()->inspectorStyleSheet(ownerDocument, false)); + result->setBoolean("isUserAgent", isUserAgent); + result->setBoolean("isUser", isUser); + result->setBoolean("isViaInspector", rule->parentStyleSheet() == cssStore()->inspectorStyleSheet(ownerDocument, false)); // Bind editable scripts only. bool bind = !isUserAgent && !isUser; diff --git a/WebCore/inspector/InspectorDOMStorageResource.cpp b/WebCore/inspector/InspectorDOMStorageResource.cpp index 72b4e10..c8d76ba 100644 --- a/WebCore/inspector/InspectorDOMStorageResource.cpp +++ b/WebCore/inspector/InspectorDOMStorageResource.cpp @@ -71,7 +71,7 @@ void InspectorDOMStorageResource::bind(InspectorFrontend* frontend) RefPtr<InspectorObject> jsonObject = InspectorObject::create(); jsonObject->setString("host", m_frame->document()->securityOrigin()->host()); - jsonObject->setBool("isLocalStorage", m_isLocalStorage); + jsonObject->setBoolean("isLocalStorage", m_isLocalStorage); jsonObject->setNumber("id", m_id); frontend->addDOMStorage(jsonObject); } diff --git a/WebCore/inspector/InspectorProfilerAgent.cpp b/WebCore/inspector/InspectorProfilerAgent.cpp index a73469a..9161c3b 100644 --- a/WebCore/inspector/InspectorProfilerAgent.cpp +++ b/WebCore/inspector/InspectorProfilerAgent.cpp @@ -39,6 +39,7 @@ #include "KURL.h" #include "Page.h" #include "ScriptDebugServer.h" +#include "ScriptHeapSnapshot.h" #include "ScriptProfile.h" #include "ScriptProfiler.h" #include <wtf/OwnPtr.h> @@ -51,6 +52,7 @@ namespace WebCore { static const char* const UserInitiatedProfileName = "org.webkit.profiles.user-initiated"; static const char* const CPUProfileType = "CPU"; +static const char* const HeapProfileType = "HEAP"; PassOwnPtr<InspectorProfilerAgent> InspectorProfilerAgent::create(InspectorController* inspectorController) { @@ -65,6 +67,7 @@ InspectorProfilerAgent::InspectorProfilerAgent(InspectorController* inspectorCon , m_recordingUserInitiatedProfile(false) , m_currentUserInitiatedProfileNumber(-1) , m_nextUserInitiatedProfileNumber(1) + , m_nextUserInitiatedHeapSnapshotNumber(1) { } @@ -104,6 +107,15 @@ PassRefPtr<InspectorObject> InspectorProfilerAgent::createProfileHeader(const Sc return header; } +PassRefPtr<InspectorObject> InspectorProfilerAgent::createSnapshotHeader(const ScriptHeapSnapshot& snapshot) +{ + RefPtr<InspectorObject> header = InspectorObject::create(); + header->setString("title", snapshot.title()); + header->setNumber("uid", snapshot.uid()); + header->setString("typeId", String(HeapProfileType)); + return header; +} + void InspectorProfilerAgent::disable() { if (!m_enabled) @@ -138,28 +150,46 @@ void InspectorProfilerAgent::getProfileHeaders(RefPtr<InspectorArray>* headers) ProfilesMap::iterator profilesEnd = m_profiles.end(); for (ProfilesMap::iterator it = m_profiles.begin(); it != profilesEnd; ++it) (*headers)->pushObject(createProfileHeader(*it->second)); -} - -void InspectorProfilerAgent::getProfile(unsigned uid, RefPtr<InspectorObject>* profileObject) -{ - ProfilesMap::iterator it = m_profiles.find(uid); - if (it != m_profiles.end()) { - *profileObject = createProfileHeader(*it->second); - (*profileObject)->setObject("head", it->second->buildInspectorObjectForHead()); + HeapSnapshotsMap::iterator snapshotsEnd = m_snapshots.end(); + for (HeapSnapshotsMap::iterator it = m_snapshots.begin(); it != snapshotsEnd; ++it) + (*headers)->pushObject(createSnapshotHeader(*it->second)); +} + +void InspectorProfilerAgent::getProfile(const String& type, unsigned uid, RefPtr<InspectorObject>* profileObject) +{ + if (type == CPUProfileType) { + ProfilesMap::iterator it = m_profiles.find(uid); + if (it != m_profiles.end()) { + *profileObject = createProfileHeader(*it->second); + (*profileObject)->setObject("head", it->second->buildInspectorObjectForHead()); + } + } else if (type == HeapProfileType) { + HeapSnapshotsMap::iterator it = m_snapshots.find(uid); + if (it != m_snapshots.end()) { + *profileObject = createSnapshotHeader(*it->second); + (*profileObject)->setObject("head", it->second->buildInspectorObjectForHead()); + } } } -void InspectorProfilerAgent::removeProfile(unsigned uid) +void InspectorProfilerAgent::removeProfile(const String& type, unsigned uid) { - if (m_profiles.contains(uid)) - m_profiles.remove(uid); + if (type == CPUProfileType) { + if (m_profiles.contains(uid)) + m_profiles.remove(uid); + } else if (type == HeapProfileType) { + if (m_snapshots.contains(uid)) + m_snapshots.remove(uid); + } } void InspectorProfilerAgent::resetState() { m_profiles.clear(); + m_snapshots.clear(); m_currentUserInitiatedProfileNumber = 1; m_nextUserInitiatedProfileNumber = 1; + m_nextUserInitiatedHeapSnapshotNumber = 1; if (m_frontend) m_frontend->resetProfilesPanel(); } @@ -199,6 +229,17 @@ void InspectorProfilerAgent::stopUserInitiatedProfiling() toggleRecordButton(false); } +void InspectorProfilerAgent::takeHeapSnapshot() +{ + String title = String::format("%s.%d", UserInitiatedProfileName, m_nextUserInitiatedHeapSnapshotNumber++); + RefPtr<ScriptHeapSnapshot> snapshot = ScriptProfiler::takeHeapSnapshot(title); + if (snapshot) { + m_snapshots.add(snapshot->uid(), snapshot); + if (m_frontend) + m_frontend->addProfileHeader(createSnapshotHeader(*snapshot)); + } +} + void InspectorProfilerAgent::toggleRecordButton(bool isProfiling) { if (m_frontend) diff --git a/WebCore/inspector/InspectorProfilerAgent.h b/WebCore/inspector/InspectorProfilerAgent.h index 9593eba..421efb0 100644 --- a/WebCore/inspector/InspectorProfilerAgent.h +++ b/WebCore/inspector/InspectorProfilerAgent.h @@ -44,6 +44,7 @@ class InspectorArray; class InspectorController; class InspectorFrontend; class InspectorObject; +class ScriptHeapSnapshot; class ScriptProfile; class InspectorProfilerAgent : public Noncopyable { @@ -60,22 +61,25 @@ public: bool enabled() { return m_enabled; } String getCurrentUserInitiatedProfileName(bool incrementProfileNumber = false); void getProfileHeaders(RefPtr<InspectorArray>* headers); - void getProfile(unsigned uid, RefPtr<InspectorObject>* profileObject); + void getProfile(const String& type, unsigned uid, RefPtr<InspectorObject>* profileObject); bool isRecordingUserInitiatedProfile() { return m_recordingUserInitiatedProfile; } - void removeProfile(unsigned uid); + void removeProfile(const String& type, unsigned uid); void resetState(); void setFrontend(InspectorFrontend* frontend) { m_frontend = frontend; } void startProfiling() { startUserInitiatedProfiling(); } void startUserInitiatedProfiling(); void stopProfiling() { stopUserInitiatedProfiling(); } void stopUserInitiatedProfiling(); + void takeHeapSnapshot(); void toggleRecordButton(bool isProfiling); private: typedef HashMap<unsigned int, RefPtr<ScriptProfile> > ProfilesMap; + typedef HashMap<unsigned int, RefPtr<ScriptHeapSnapshot> > HeapSnapshotsMap; InspectorProfilerAgent(InspectorController*); PassRefPtr<InspectorObject> createProfileHeader(const ScriptProfile& profile); + PassRefPtr<InspectorObject> createSnapshotHeader(const ScriptHeapSnapshot& snapshot); InspectorController* m_inspectorController; InspectorFrontend* m_frontend; @@ -83,7 +87,9 @@ private: bool m_recordingUserInitiatedProfile; int m_currentUserInitiatedProfileNumber; unsigned m_nextUserInitiatedProfileNumber; + unsigned m_nextUserInitiatedHeapSnapshotNumber; ProfilesMap m_profiles; + HeapSnapshotsMap m_snapshots; }; } // namespace WebCore diff --git a/WebCore/inspector/InspectorResource.cpp b/WebCore/inspector/InspectorResource.cpp index ed07339..131ce95 100644 --- a/WebCore/inspector/InspectorResource.cpp +++ b/WebCore/inspector/InspectorResource.cpp @@ -190,10 +190,10 @@ void InspectorResource::updateScriptObject(InspectorFrontend* frontend) jsonObject->setString("lastPathComponent", m_requestURL.lastPathComponent()); RefPtr<InspectorObject> requestHeaders = buildHeadersObject(m_requestHeaderFields); jsonObject->setObject("requestHeaders", requestHeaders); - jsonObject->setBool("mainResource", m_isMainResource); + jsonObject->setBoolean("mainResource", m_isMainResource); jsonObject->setString("requestMethod", m_requestMethod); jsonObject->setString("requestFormData", m_requestFormData); - jsonObject->setBool("didRequestChange", true); + jsonObject->setBoolean("didRequestChange", true); } if (m_changes.hasChange(ResponseChange)) { @@ -205,27 +205,27 @@ void InspectorResource::updateScriptObject(InspectorFrontend* frontend) RefPtr<InspectorObject> responseHeaders = buildHeadersObject(m_responseHeaderFields); jsonObject->setObject("responseHeaders", responseHeaders); jsonObject->setNumber("connectionID", m_connectionID); - jsonObject->setBool("connectionReused", m_connectionReused); - jsonObject->setBool("cached", m_cached); + jsonObject->setBoolean("connectionReused", m_connectionReused); + jsonObject->setBoolean("cached", m_cached); if (m_loadTiming && !m_cached) jsonObject->setObject("timing", buildObjectForTiming(m_loadTiming.get())); - jsonObject->setBool("didResponseChange", true); + jsonObject->setBoolean("didResponseChange", true); } if (m_changes.hasChange(TypeChange)) { jsonObject->setNumber("type", static_cast<int>(type())); - jsonObject->setBool("didTypeChange", true); + jsonObject->setBoolean("didTypeChange", true); } if (m_changes.hasChange(LengthChange)) { jsonObject->setNumber("resourceSize", m_length); - jsonObject->setBool("didLengthChange", true); + jsonObject->setBoolean("didLengthChange", true); } if (m_changes.hasChange(CompletionChange)) { - jsonObject->setBool("failed", m_failed); - jsonObject->setBool("finished", m_finished); - jsonObject->setBool("didCompletionChange", true); + jsonObject->setBoolean("failed", m_failed); + jsonObject->setBoolean("finished", m_finished); + jsonObject->setBoolean("didCompletionChange", true); } if (m_changes.hasChange(TimingChange)) { @@ -239,7 +239,7 @@ void InspectorResource::updateScriptObject(InspectorFrontend* frontend) jsonObject->setNumber("loadEventTime", m_loadEventTime); if (m_domContentEventTime > 0) jsonObject->setNumber("domContentEventTime", m_domContentEventTime); - jsonObject->setBool("didTimingChange", true); + jsonObject->setBoolean("didTimingChange", true); } if (m_changes.hasChange(RedirectsChange)) { diff --git a/WebCore/inspector/InspectorValues.cpp b/WebCore/inspector/InspectorValues.cpp index a7c43a5..c96e953 100644 --- a/WebCore/inspector/InspectorValues.cpp +++ b/WebCore/inspector/InspectorValues.cpp @@ -474,7 +474,7 @@ inline void doubleQuoteString(const String& str, Vector<UChar>* dst) } // anonymous namespace -bool InspectorValue::asBool(bool*) const +bool InspectorValue::asBoolean(bool*) const { return false; } @@ -555,7 +555,7 @@ void InspectorValue::writeJSON(Vector<UChar>* output) const output->append(nullString, 4); } -bool InspectorBasicValue::asBool(bool* output) const +bool InspectorBasicValue::asBoolean(bool* output) const { if (type() != TypeBoolean) return false; @@ -565,7 +565,7 @@ bool InspectorBasicValue::asBool(bool* output) const bool InspectorBasicValue::asNumber(double* output) const { - if (type() != TypeDouble) + if (type() != TypeNumber) return false; *output = m_doubleValue; return true; @@ -573,7 +573,7 @@ bool InspectorBasicValue::asNumber(double* output) const bool InspectorBasicValue::asNumber(long* output) const { - if (type() != TypeDouble) + if (type() != TypeNumber) return false; *output = static_cast<long>(m_doubleValue); return true; @@ -581,7 +581,7 @@ bool InspectorBasicValue::asNumber(long* output) const bool InspectorBasicValue::asNumber(unsigned long* output) const { - if (type() != TypeDouble) + if (type() != TypeNumber) return false; *output = static_cast<unsigned long>(m_doubleValue); return true; @@ -589,7 +589,7 @@ bool InspectorBasicValue::asNumber(unsigned long* output) const bool InspectorBasicValue::asNumber(unsigned int* output) const { - if (type() != TypeDouble) + if (type() != TypeNumber) return false; *output = static_cast<unsigned int>(m_doubleValue); return true; @@ -597,13 +597,13 @@ bool InspectorBasicValue::asNumber(unsigned int* output) const void InspectorBasicValue::writeJSON(Vector<UChar>* output) const { - ASSERT(type() == TypeBoolean || type() == TypeDouble); + ASSERT(type() == TypeBoolean || type() == TypeNumber); if (type() == TypeBoolean) { if (m_boolValue) output->append(trueString, 4); else output->append(falseString, 5); - } else if (type() == TypeDouble) { + } else if (type() == TypeNumber) { String value = String::format("%f", m_doubleValue); value.replace(',', '.'); output->append(value.characters(), value.length()); @@ -633,12 +633,12 @@ PassRefPtr<InspectorObject> InspectorObject::asObject() return this; } -bool InspectorObject::getBool(const String& name, bool* output) const +bool InspectorObject::getBoolean(const String& name, bool* output) const { RefPtr<InspectorValue> value = get(name); if (!value) return false; - return value->asBool(output); + return value->asBoolean(output); } bool InspectorObject::getNumber(const String& name, double* output) const diff --git a/WebCore/inspector/InspectorValues.h b/WebCore/inspector/InspectorValues.h index 473ad21..3dd9594 100644 --- a/WebCore/inspector/InspectorValues.h +++ b/WebCore/inspector/InspectorValues.h @@ -59,7 +59,7 @@ public: typedef enum { TypeNull = 0, TypeBoolean, - TypeDouble, + TypeNumber, TypeString, TypeObject, TypeArray @@ -67,7 +67,7 @@ public: Type type() const { return m_type; } - virtual bool asBool(bool* output) const; + virtual bool asBoolean(bool* output) const; virtual bool asNumber(double* output) const; virtual bool asNumber(long* output) const; virtual bool asNumber(unsigned long* output) const; @@ -109,7 +109,7 @@ public: return adoptRef(new InspectorBasicValue(value)); } - virtual bool asBool(bool* output) const; + virtual bool asBoolean(bool* output) const; virtual bool asNumber(double* output) const; virtual bool asNumber(long* output) const; virtual bool asNumber(unsigned long* output) const; @@ -119,8 +119,8 @@ public: private: explicit InspectorBasicValue(bool value) : InspectorValue(TypeBoolean), m_boolValue(value) { } - explicit InspectorBasicValue(int value) : InspectorValue(TypeDouble), m_doubleValue((double)value) { } - explicit InspectorBasicValue(double value) : InspectorValue(TypeDouble), m_doubleValue(value) { } + explicit InspectorBasicValue(int value) : InspectorValue(TypeNumber), m_doubleValue((double)value) { } + explicit InspectorBasicValue(double value) : InspectorValue(TypeNumber), m_doubleValue(value) { } union { bool m_boolValue; @@ -169,7 +169,7 @@ public: virtual bool asObject(RefPtr<InspectorObject>* output); virtual PassRefPtr<InspectorObject> asObject(); - void setBool(const String& name, bool); + void setBoolean(const String& name, bool); void setNumber(const String& name, double); void setString(const String& name, const String&); void setValue(const String& name, PassRefPtr<InspectorValue>); @@ -177,7 +177,7 @@ public: void setArray(const String& name, PassRefPtr<InspectorArray>); const_iterator find(const String& name) const; - bool getBool(const String& name, bool* output) const; + bool getBoolean(const String& name, bool* 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; @@ -208,7 +208,7 @@ public: virtual bool asArray(RefPtr<InspectorArray>* output); virtual PassRefPtr<InspectorArray> asArray(); - void pushBool(bool); + void pushBoolean(bool); void pushNumber(double); void pushString(const String&); void pushValue(PassRefPtr<InspectorValue>); @@ -230,7 +230,7 @@ inline InspectorObject::const_iterator InspectorObject::find(const String& name) return m_data.find(name); } -inline void InspectorObject::setBool(const String& name, bool value) +inline void InspectorObject::setBoolean(const String& name, bool value) { setValue(name, InspectorBasicValue::create(value)); } @@ -263,7 +263,7 @@ inline void InspectorObject::setArray(const String& name, PassRefPtr<InspectorAr m_order.append(name); } -inline void InspectorArray::pushBool(bool value) +inline void InspectorArray::pushBoolean(bool value) { m_data.append(InspectorBasicValue::create(value)); } diff --git a/WebCore/inspector/ScriptBreakpoint.cpp b/WebCore/inspector/ScriptBreakpoint.cpp index 24401f1..b7205a7 100644 --- a/WebCore/inspector/ScriptBreakpoint.cpp +++ b/WebCore/inspector/ScriptBreakpoint.cpp @@ -47,7 +47,7 @@ void ScriptBreakpoint::sourceBreakpointsFromInspectorObject(PassRefPtr<Inspector continue; bool enabled; RefPtr<InspectorValue> enabledValue = breakpoint->get("enabled"); - if (!enabledValue || !enabledValue->asBool(&enabled)) + if (!enabledValue || !enabledValue->asBoolean(&enabled)) continue; String condition; RefPtr<InspectorValue> conditionValue = breakpoint->get("condition"); @@ -62,7 +62,7 @@ PassRefPtr<InspectorObject> ScriptBreakpoint::inspectorObjectFromSourceBreakpoin RefPtr<InspectorObject> breakpoints = InspectorObject::create(); for (SourceBreakpoints::const_iterator it = sourceBreakpoints.begin(); it != sourceBreakpoints.end(); ++it) { RefPtr<InspectorObject> breakpoint = InspectorObject::create(); - breakpoint->setBool("enabled", it->second.enabled); + breakpoint->setBoolean("enabled", it->second.enabled); breakpoint->setString("condition", it->second.condition); breakpoints->setObject(String::number(it->first), breakpoint); } diff --git a/WebCore/inspector/TimelineRecordFactory.cpp b/WebCore/inspector/TimelineRecordFactory.cpp index e1c2bbb..713d6bc 100644 --- a/WebCore/inspector/TimelineRecordFactory.cpp +++ b/WebCore/inspector/TimelineRecordFactory.cpp @@ -87,7 +87,7 @@ PassRefPtr<InspectorObject> TimelineRecordFactory::createTimerInstallData(int ti RefPtr<InspectorObject> data = InspectorObject::create(); data->setNumber("timerId", timerId); data->setNumber("timeout", timeout); - data->setBool("singleShot", singleShot); + data->setBoolean("singleShot", singleShot); return data.release(); } @@ -134,7 +134,7 @@ PassRefPtr<InspectorObject> TimelineRecordFactory::createResourceSendRequestData data->setNumber("identifier", identifier); data->setString("url", request.url().string()); data->setString("requestMethod", request.httpMethod()); - data->setBool("isMainResource", isMainResource); + data->setBoolean("isMainResource", isMainResource); return data.release(); } @@ -152,7 +152,7 @@ PassRefPtr<InspectorObject> TimelineRecordFactory::createResourceFinishData(unsi { RefPtr<InspectorObject> data = InspectorObject::create(); data->setNumber("identifier", identifier); - data->setBool("didFail", didFail); + data->setBoolean("didFail", didFail); return data.release(); } diff --git a/WebCore/inspector/front-end/AuditFormatters.js b/WebCore/inspector/front-end/AuditFormatters.js new file mode 100755 index 0000000..de277ad --- /dev/null +++ b/WebCore/inspector/front-end/AuditFormatters.js @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2010 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.applyFormatters = function(value) +{ + var formatter; + var type = typeof value; + var args; + + switch (type) { + case "string": + case "boolean": + case "number": + formatter = WebInspector.AuditFormatters.text; + args = [ value.toString() ]; + break; + + case "object": + if (value instanceof Array) { + formatter = WebInspector.AuditFormatters.concat; + args = value; + } else if (value.type && value.arguments) { + formatter = WebInspector.AuditFormatters[value.type]; + args = value.arguments; + } + } + if (!formatter) + throw "Invalid value or formatter: " + type + JSON.stringify(value); + + return formatter.apply(null, args); +} + +WebInspector.AuditFormatters = { + text: function(text) + { + return document.createTextNode(text); + }, + + snippet: function(snippetText) + { + var div = document.createElement("div"); + div.innerText = snippetText; + div.className = "source-code"; + return div; + }, + + concat: function() + { + var parent = document.createElement("span"); + for (var arg = 0; arg < arguments.length; ++arg) + parent.appendChild(WebInspector.applyFormatters(arguments[arg])); + return parent; + }, + + url: function(url, displayText) + { + return WebInspector.linkifyURLAsNode(url, displayText || url, null, (url in WebInspector.resourceURLMap)); + } +}; diff --git a/WebCore/inspector/front-end/AuditLauncherView.js b/WebCore/inspector/front-end/AuditLauncherView.js index 33d3872..18daee6 100644 --- a/WebCore/inspector/front-end/AuditLauncherView.js +++ b/WebCore/inspector/front-end/AuditLauncherView.js @@ -28,10 +28,9 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.AuditLauncherView = function(categoriesById, runnerCallback) +WebInspector.AuditLauncherView = function(runnerCallback) { WebInspector.View.call(this); - this._categoriesById = categoriesById; this._runnerCallback = runnerCallback; this._categoryIdPrefix = "audit-category-item-"; this._auditRunning = false; @@ -41,27 +40,16 @@ WebInspector.AuditLauncherView = function(categoriesById, runnerCallback) this._contentElement = document.createElement("div"); this._contentElement.className = "audit-launcher-view-content"; this.element.appendChild(this._contentElement); + this._boundCategoryClickListener = this._categoryClicked.bind(this); this._resetResourceCount(); - function categorySortFunction(a, b) - { - var aTitle = a.displayName || ""; - var bTitle = b.displayName || ""; - return aTitle.localeCompare(bTitle); - } - var sortedCategories = []; - for (var id in this._categoriesById) - sortedCategories.push(this._categoriesById[id]); - sortedCategories.sort(categorySortFunction); + this._sortedCategories = []; - if (!sortedCategories.length) { - this._headerElement = document.createElement("h1"); - this._headerElement.className = "no-audits"; - this._headerElement.textContent = WebInspector.UIString("No audits to run"); - this._contentElement.appendChild(this._headerElement); - } else - this._createLauncherUI(sortedCategories); + this._headerElement = document.createElement("h1"); + this._headerElement.className = "no-audits"; + this._headerElement.textContent = WebInspector.UIString("No audits to run"); + this._contentElement.appendChild(this._headerElement); } WebInspector.AuditLauncherView.prototype = { @@ -133,6 +121,30 @@ WebInspector.AuditLauncherView.prototype = { this._resetResourceCount(); }, + addCategory: function(category) + { + if (!this._sortedCategories.length) + this._createLauncherUI(); + + var categoryElement = this._createCategoryElement(category.displayName, category.id); + category._checkboxElement = categoryElement.firstChild; + if (this._selectAllCheckboxElement.checked) { + category._checkboxElement.checked = true; + ++this._currentCategoriesCount; + } + + function compareCategories(a, b) + { + var aTitle = a.displayName || ""; + var bTitle = b.displayName || ""; + return aTitle.localeCompare(bTitle); + } + var insertBefore = insertionIndexForObjectInListSortedByFunction(category, this._sortedCategories, compareCategories); + this._categoriesElement.insertBefore(categoryElement, this._categoriesElement.children[insertBefore]); + this._sortedCategories.splice(insertBefore, 0, category); + this._updateButton(); + }, + _setAuditRunning: function(auditRunning) { if (this._auditRunning === auditRunning) @@ -146,10 +158,11 @@ WebInspector.AuditLauncherView.prototype = { { var catIds = []; var childNodes = this._categoriesElement.childNodes; - for (var id in this._categoriesById) { - if (this._categoriesById[id]._checkboxElement.checked) - catIds.push(id); + for (var category = 0; category < this._sortedCategories.length; ++category) { + if (this._sortedCategories[category]._checkboxElement.checked) + catIds.push(this._sortedCategories[category].id); } + this._setAuditRunning(true); this._runnerCallback(catIds, this._auditPresentStateElement.checked, this._setAuditRunning.bind(this, false)); }, @@ -159,14 +172,14 @@ WebInspector.AuditLauncherView.prototype = { var childNodes = this._categoriesElement.childNodes; for (var i = 0, length = childNodes.length; i < length; ++i) childNodes[i].firstChild.checked = checkCategories; - this._currentCategoriesCount = checkCategories ? this._totalCategoriesCount : 0; + this._currentCategoriesCount = checkCategories ? this._sortedCategories.length : 0; this._updateButton(); }, _categoryClicked: function(event) { this._currentCategoriesCount += event.target.checked ? 1 : -1; - this._selectAllCheckboxElement.checked = this._currentCategoriesCount === this._totalCategoriesCount; + this._selectAllCheckboxElement.checked = this._currentCategoriesCount === this._sortedCategories.length; this._updateButton(); }, @@ -177,16 +190,21 @@ WebInspector.AuditLauncherView.prototype = { var element = document.createElement("input"); element.type = "checkbox"; + element.addEventListener("click", this._boundCategoryClickListener, false); labelElement.appendChild(element); labelElement.appendChild(document.createTextNode(title)); return labelElement; }, - _createLauncherUI: function(sortedCategories) + _createLauncherUI: function() { this._headerElement = document.createElement("h1"); this._headerElement.textContent = WebInspector.UIString("Select audits to run"); + + for (var child = 0; child < this._contentElement.children.length; ++child) + this._contentElement.removeChild(this._contentElement.children[child]); + this._contentElement.appendChild(this._headerElement); function handleSelectAllClick(event) @@ -204,16 +222,6 @@ WebInspector.AuditLauncherView.prototype = { this._categoriesElement.className = "audit-categories-container"; this._contentElement.appendChild(this._categoriesElement); - var boundCategoryClickListener = this._categoryClicked.bind(this); - - for (var i = 0; i < sortedCategories.length; ++i) { - categoryElement = this._createCategoryElement(sortedCategories[i].displayName, sortedCategories[i].id); - categoryElement.firstChild.addEventListener("click", boundCategoryClickListener, false); - sortedCategories[i]._checkboxElement = categoryElement.firstChild; - this._categoriesElement.appendChild(categoryElement); - } - - this._totalCategoriesCount = this._categoriesElement.childNodes.length; this._currentCategoriesCount = 0; var flexibleSpaceElement = document.createElement("div"); diff --git a/WebCore/inspector/front-end/AuditResultView.js b/WebCore/inspector/front-end/AuditResultView.js index 2f4afbd..2636463 100644 --- a/WebCore/inspector/front-end/AuditResultView.js +++ b/WebCore/inspector/front-end/AuditResultView.js @@ -81,15 +81,22 @@ WebInspector.AuditCategoryResultPane = function(categoryResult) WebInspector.AuditCategoryResultPane.prototype = { _appendResult: function(parentTreeElement, result) { - var title = result.value; - if (result.violationCount) - title = String.sprintf("%s (%d)", title, result.violationCount); + var title = ""; + + if (typeof result.value === "string") { + title = result.value; + if (result.violationCount) + title = String.sprintf("%s (%d)", title, result.violationCount); + } var treeElement = new TreeElement(title, null, !!result.children); parentTreeElement.appendChild(treeElement); if (result.className) treeElement.listItemElement.addStyleClass(result.className); + if (typeof result.value !== "string") + treeElement.listItemElement.appendChild(WebInspector.applyFormatters(result.value)); + if (result.children) { for (var i = 0; i < result.children.length; ++i) this._appendResult(treeElement, result.children[i]); diff --git a/WebCore/inspector/front-end/AuditRules.js b/WebCore/inspector/front-end/AuditRules.js index e28a364..a72de56 100644 --- a/WebCore/inspector/front-end/AuditRules.js +++ b/WebCore/inspector/front-end/AuditRules.js @@ -371,7 +371,7 @@ WebInspector.AuditRules.UnusedCssRule.prototype = { return routineResult; } - InspectorBackend.getAllStyles(WebInspector.Callback.wrap(evalCallback)); + InspectorBackend.getAllStyles(evalCallback); } } @@ -693,7 +693,7 @@ WebInspector.AuditRules.ImageDimensionsRule.prototype = { return callback(null); var context = {imagesLeft: imageIds.length, urlToNoDimensionCount: {}}; for (var i = imageIds.length - 1; i >= 0; --i) - InspectorBackend.getStyles(WebInspector.Callback.wrap(imageStylesReady.bind(this, imageIds[i], context)), imageIds[i], true); + InspectorBackend.getStyles(imageIds[i], true, imageStylesReady.bind(this, imageIds[i], context)); } function pushImageNodes() diff --git a/WebCore/inspector/front-end/AuditsPanel.js b/WebCore/inspector/front-end/AuditsPanel.js index bc7f3b3..f6cbed0 100644 --- a/WebCore/inspector/front-end/AuditsPanel.js +++ b/WebCore/inspector/front-end/AuditsPanel.js @@ -32,8 +32,6 @@ WebInspector.AuditsPanel = function() { WebInspector.Panel.call(this, "audits"); - this._constructCategories(); - this.createSidebar(); this.auditsTreeElement = new WebInspector.SidebarSectionTreeElement("", {}, true); this.sidebarTree.appendChild(this.auditsTreeElement); @@ -54,7 +52,11 @@ WebInspector.AuditsPanel = function() this.viewsContainerElement.id = "audit-views"; this.element.appendChild(this.viewsContainerElement); - this._launcherView = new WebInspector.AuditLauncherView(this.categoriesById, this.initiateAudit.bind(this)); + this._constructCategories(); + + this._launcherView = new WebInspector.AuditLauncherView(this.initiateAudit.bind(this)); + for (id in this.categoriesById) + this._launcherView.addCategory(this.categoriesById[id]); } WebInspector.AuditsPanel.prototype = { @@ -104,6 +106,17 @@ WebInspector.AuditsPanel.prototype = { this._launcherView.resourceFinished(resource); }, + addCategory: function(category) + { + this.categoriesById[category.id] = category; + this._launcherView.addCategory(category); + }, + + getCategory: function(id) + { + return this.categoriesById[id]; + }, + _constructCategories: function() { this._auditCategoriesById = {}; @@ -147,7 +160,7 @@ WebInspector.AuditsPanel.prototype = { var category = categories[i]; var result = new WebInspector.AuditCategoryResult(category); results.push(result); - category.runRules(resources, ruleResultReadyCallback.bind(null, result)); + category.run(resources, ruleResultReadyCallback.bind(null, result)); } }, @@ -220,7 +233,7 @@ WebInspector.AuditsPanel.prototype = { { this.visibleView = this._launcherView; }, - + get visibleView() { return this._visibleView; @@ -311,7 +324,7 @@ WebInspector.AuditCategory.prototype = { this._rules.push(rule); }, - runRules: function(resources, callback) + run: function(resources, callback) { this._ensureInitialized(); for (var i = 0; i < this._rules.length; ++i) diff --git a/WebCore/inspector/front-end/BreakpointManager.js b/WebCore/inspector/front-end/BreakpointManager.js index 824bc31..8518618 100644 --- a/WebCore/inspector/front-end/BreakpointManager.js +++ b/WebCore/inspector/front-end/BreakpointManager.js @@ -123,8 +123,7 @@ WebInspector.BreakpointManager.prototype = { this._setBreakpoint(breakpoint.sourceID, breakpoint.url, line, breakpoint.enabled, breakpoint.condition); } } - var callbackId = WebInspector.Callback.wrap(didSetBreakpoint.bind(this)); - InspectorBackend.setBreakpoint(callbackId, breakpoint.sourceID, breakpoint.line, breakpoint.enabled, breakpoint.condition); + InspectorBackend.setBreakpoint(breakpoint.sourceID, breakpoint.line, breakpoint.enabled, breakpoint.condition, didSetBreakpoint.bind(this)); } } diff --git a/WebCore/inspector/front-end/BreakpointsSidebarPane.js b/WebCore/inspector/front-end/BreakpointsSidebarPane.js index ccf45b6..3a0860f 100644 --- a/WebCore/inspector/front-end/BreakpointsSidebarPane.js +++ b/WebCore/inspector/front-end/BreakpointsSidebarPane.js @@ -191,7 +191,7 @@ WebInspector.DOMBreakpointItem = function(breakpoint) var link = WebInspector.panels.elements.linkifyNodeReference(this._breakpoint.node); this._element.appendChild(link); - var type = WebInspector.DOMBreakpoint.Labels[this._breakpoint.type]; + var type = WebInspector.DOMBreakpoint.labelForType(this._breakpoint.type); var typeElement = document.createTextNode(" - " + type); this._element.appendChild(typeElement); } diff --git a/WebCore/inspector/front-end/CSSStyleModel.js b/WebCore/inspector/front-end/CSSStyleModel.js index 66a20ce..bda4064 100644 --- a/WebCore/inspector/front-end/CSSStyleModel.js +++ b/WebCore/inspector/front-end/CSSStyleModel.js @@ -35,12 +35,12 @@ WebInspector.CSSStyleModel = function() WebInspector.CSSStyleModel.prototype = { getStylesAsync: function(nodeId, authOnly, userCallback) { - InspectorBackend.getStyles(WebInspector.Callback.wrap(userCallback), nodeId, authOnly); + InspectorBackend.getStyles(nodeId, authOnly, userCallback); }, getComputedStyleAsync: function(nodeId, userCallback) { - InspectorBackend.getComputedStyle(WebInspector.Callback.wrap(userCallback), nodeId); + InspectorBackend.getComputedStyle(nodeId, userCallback); }, setRuleSelector: function(ruleId, newContent, nodeId, successCallback, failureCallback) @@ -53,7 +53,7 @@ WebInspector.CSSStyleModel.prototype = { successCallback(WebInspector.CSSStyleDeclaration.parseRule(newRulePayload), doesAffectSelectedNode); } - InspectorBackend.setRuleSelector(WebInspector.Callback.wrap(callback), ruleId, newContent, nodeId); + InspectorBackend.setRuleSelector(ruleId, newContent, nodeId, callback); }, addRule: function(nodeId, newContent, successCallback, failureCallback) @@ -70,7 +70,7 @@ WebInspector.CSSStyleModel.prototype = { } } - InspectorBackend.addRule(WebInspector.Callback.wrap(callback), newContent, nodeId); + InspectorBackend.addRule(newContent, nodeId, callback); }, toggleStyleEnabled: function(styleId, propertyName, disabled, userCallback) @@ -86,12 +86,12 @@ WebInspector.CSSStyleModel.prototype = { userCallback(newStyle); } - InspectorBackend.toggleStyleEnabled(WebInspector.Callback.wrap(callback), styleId, propertyName, disabled); + InspectorBackend.toggleStyleEnabled(styleId, propertyName, disabled, callback); }, setCSSText: function(styleId, cssText) { - InspectorBackend.setStyleText(WebInspector.Callback.wrap(null), styleId, cssText); + InspectorBackend.setStyleText(styleId, cssText); }, applyStyleText: function(styleId, styleText, propertyName, successCallback, failureCallback) @@ -106,6 +106,6 @@ WebInspector.CSSStyleModel.prototype = { } } - InspectorBackend.applyStyleText(WebInspector.Callback.wrap(callback), styleId, styleText, propertyName); + InspectorBackend.applyStyleText(styleId, styleText, propertyName, callback); } } diff --git a/WebCore/inspector/front-end/DOMAgent.js b/WebCore/inspector/front-end/DOMAgent.js index 0d79d51..5aaa0d3 100644 --- a/WebCore/inspector/front-end/DOMAgent.js +++ b/WebCore/inspector/front-end/DOMAgent.js @@ -72,8 +72,12 @@ WebInspector.DOMNode = function(doc, payload) { this.publicId = payload.publicId; this.systemId = payload.systemId; this.internalSubset = payload.internalSubset; - } else if (this.nodeType === Node.DOCUMENT_NODE) + } else if (this.nodeType === Node.DOCUMENT_NODE) { this.documentURL = payload.documentURL; + } else if (this.nodeType === Node.ATTRIBUTE_NODE) { + this.name = payload.name; + this.value = payload.value; + } } WebInspector.DOMNode.prototype = { @@ -306,26 +310,25 @@ WebInspector.DOMAgent.prototype = { function mycallback() { callback(parent.children); } - var callId = WebInspector.Callback.wrap(mycallback); - InspectorBackend.getChildNodes(callId, parent.id); + InspectorBackend.getChildNodes(parent.id, mycallback); }, setAttributeAsync: function(node, name, value, callback) { var mycallback = this._didApplyDomChange.bind(this, node, callback); - InspectorBackend.setAttribute(WebInspector.Callback.wrap(mycallback), node.id, name, value); + InspectorBackend.setAttribute(node.id, name, value, mycallback); }, removeAttributeAsync: function(node, name, callback) { var mycallback = this._didApplyDomChange.bind(this, node, callback); - InspectorBackend.removeAttribute(WebInspector.Callback.wrap(mycallback), node.id, name); + InspectorBackend.removeAttribute(node.id, name, mycallback); }, setTextNodeValueAsync: function(node, text, callback) { var mycallback = this._didApplyDomChange.bind(this, node, callback); - InspectorBackend.setTextNodeValue(WebInspector.Callback.wrap(mycallback), node.id, text); + InspectorBackend.setTextNodeValue(node.id, text, mycallback); }, _didApplyDomChange: function(node, callback, success) @@ -429,8 +432,7 @@ WebInspector.ApplicationCache.getApplicationCachesAsync = function(callback) callback(applicationCaches); } - var callId = WebInspector.Callback.wrap(mycallback); - InspectorBackend.getApplicationCaches(callId); + InspectorBackend.getApplicationCaches(mycallback); } WebInspector.Cookies = {} @@ -445,8 +447,7 @@ WebInspector.Cookies.getCookiesAsync = function(callback) callback(cookies, true); } - var callId = WebInspector.Callback.wrap(mycallback); - InspectorBackend.getCookies(callId); + InspectorBackend.getCookies(mycallback); } WebInspector.Cookies.buildCookiesFromString = function(rawCookieString) @@ -496,9 +497,7 @@ WebInspector.EventListeners.getEventListenersForNodeAsync = function(node, callb { if (!node) return; - - var callId = WebInspector.Callback.wrap(callback); - InspectorBackend.getEventListenersForNode(callId, node.id); + InspectorBackend.getEventListenersForNode(node.id, callback); } WebInspector.CSSStyleDeclaration = function(payload) @@ -697,6 +696,13 @@ WebInspector.DOMBreakpointManager.prototype = { this.dispatchEventToListeners("dom-breakpoint-added", breakpoint); }, + findBreakpoint: function(nodeId, type) + { + var nodeBreakpoints = this._breakpoints[nodeId]; + if (nodeBreakpoints && type in nodeBreakpoints) + return nodeBreakpoints[type]; + }, + removeBreakpointsForNode: function(node) { var nodeBreakpoints = this._breakpoints[node.id]; @@ -733,10 +739,27 @@ WebInspector.DOMBreakpoint.Types = { NodeRemoved: 2 }; -WebInspector.DOMBreakpoint.Labels = {}; -WebInspector.DOMBreakpoint.Labels[WebInspector.DOMBreakpoint.Types.SubtreeModified] = WebInspector.UIString("Subtree Modified"); -WebInspector.DOMBreakpoint.Labels[WebInspector.DOMBreakpoint.Types.AttributeModified] = WebInspector.UIString("Attribute Modified"); -WebInspector.DOMBreakpoint.Labels[WebInspector.DOMBreakpoint.Types.NodeRemoved] = WebInspector.UIString("Node Removed"); +WebInspector.DOMBreakpoint.labelForType = function(type) +{ + if (!WebInspector.DOMBreakpoint._labels) { + WebInspector.DOMBreakpoint._labels = {}; + WebInspector.DOMBreakpoint._labels[WebInspector.DOMBreakpoint.Types.SubtreeModified] = WebInspector.UIString("Subtree Modified"); + WebInspector.DOMBreakpoint._labels[WebInspector.DOMBreakpoint.Types.AttributeModified] = WebInspector.UIString("Attribute Modified"); + WebInspector.DOMBreakpoint._labels[WebInspector.DOMBreakpoint.Types.NodeRemoved] = WebInspector.UIString("Node Removed"); + } + return WebInspector.DOMBreakpoint._labels[type]; +} + +WebInspector.DOMBreakpoint.contextMenuLabelForType = function(type) +{ + if (!WebInspector.DOMBreakpoint._contextMenuLabels) { + WebInspector.DOMBreakpoint._contextMenuLabels = {}; + WebInspector.DOMBreakpoint._contextMenuLabels[WebInspector.DOMBreakpoint.Types.SubtreeModified] = WebInspector.UIString("Break on Subtree Modifications"); + WebInspector.DOMBreakpoint._contextMenuLabels[WebInspector.DOMBreakpoint.Types.AttributeModified] = WebInspector.UIString("Break on Attributes Modifications"); + WebInspector.DOMBreakpoint._contextMenuLabels[WebInspector.DOMBreakpoint.Types.NodeRemoved] = WebInspector.UIString("Break on Node Removal"); + } + return WebInspector.DOMBreakpoint._contextMenuLabels[type]; +} WebInspector.DOMBreakpoint.prototype = { get enabled() diff --git a/WebCore/inspector/front-end/DOMStorage.js b/WebCore/inspector/front-end/DOMStorage.js index 5c28e29..37be8f6 100644 --- a/WebCore/inspector/front-end/DOMStorage.js +++ b/WebCore/inspector/front-end/DOMStorage.js @@ -56,20 +56,17 @@ WebInspector.DOMStorage.prototype = { getEntries: function(callback) { - var callId = WebInspector.Callback.wrap(callback); - InspectorBackend.getDOMStorageEntries(callId, this._id); + InspectorBackend.getDOMStorageEntries(this._id, callback); }, setItem: function(key, value, callback) { - var callId = WebInspector.Callback.wrap(callback); - InspectorBackend.setDOMStorageItem(callId, this._id, key, value); + InspectorBackend.setDOMStorageItem(this._id, key, value, callback); }, removeItem: function(key, callback) { - var callId = WebInspector.Callback.wrap(callback); - InspectorBackend.removeDOMStorageItem(callId, this._id, key); + InspectorBackend.removeDOMStorageItem(this._id, key, callback); } } diff --git a/WebCore/inspector/front-end/Database.js b/WebCore/inspector/front-end/Database.js index 45b7a0e..ca3e968 100644 --- a/WebCore/inspector/front-end/Database.js +++ b/WebCore/inspector/front-end/Database.js @@ -84,8 +84,7 @@ WebInspector.Database.prototype = { { callback(names.sort()); } - var callId = WebInspector.Callback.wrap(sortingCallback); - InspectorBackend.getDatabaseTableNames(callId, this._id); + InspectorBackend.getDatabaseTableNames(this._id, sortingCallback); }, executeSql: function(query, onSuccess, onError) @@ -99,7 +98,7 @@ WebInspector.Database.prototype = { WebInspector.Database.successCallbacks[transactionId] = onSuccess; WebInspector.Database.errorCallbacks[transactionId] = onError; } - InspectorBackend.executeSQL(WebInspector.Callback.wrap(callback), this._id, query); + InspectorBackend.executeSQL(this._id, query, callback); } } diff --git a/WebCore/inspector/front-end/ElementsPanel.js b/WebCore/inspector/front-end/ElementsPanel.js index f18299a..e1bc637 100644 --- a/WebCore/inspector/front-end/ElementsPanel.js +++ b/WebCore/inspector/front-end/ElementsPanel.js @@ -58,7 +58,7 @@ WebInspector.ElementsPanel = function() if (this._focusedDOMNode) { InspectorBackend.addInspectedNode(this._focusedDOMNode.id); - WebInspector.extensionServer.notifyObjectSelected(this.name, "DOMNode"); + WebInspector.extensionServer.notifyObjectSelected(this.panel.name, "DOMNode"); } }; @@ -224,10 +224,9 @@ WebInspector.ElementsPanel.prototype = { selectNode.call(this, node); } - if (this._selectedPathOnReset) { - var callId = WebInspector.Callback.wrap(selectLastSelectedNode.bind(this)); - InspectorBackend.pushNodeByPathToFrontend(callId, this._selectedPathOnReset.join(",")); - } else + if (this._selectedPathOnReset) + InspectorBackend.pushNodeByPathToFrontend(this._selectedPathOnReset.join(","), selectLastSelectedNode.bind(this)); + else selectNode.call(this); delete this._selectedPathOnReset; }, diff --git a/WebCore/inspector/front-end/ElementsTreeOutline.js b/WebCore/inspector/front-end/ElementsTreeOutline.js index 7f48161..ba3b320 100644 --- a/WebCore/inspector/front-end/ElementsTreeOutline.js +++ b/WebCore/inspector/front-end/ElementsTreeOutline.js @@ -765,16 +765,16 @@ WebInspector.ElementsTreeElement.prototype = { if (Preferences.domBreakpointsEnabled) { // Add debbuging-related actions contextMenu.appendSeparator(); - - contextMenu.appendItem(WebInspector.UIString("Stop on Subtree Modifications"), - WebInspector.domBreakpointManager.setBreakpoint.bind(WebInspector.domBreakpointManager, this.representedObject, WebInspector.DOMBreakpoint.Types.SubtreeModified)); - contextMenu.appendItem(WebInspector.UIString("Stop on Attributes Modifications"), - WebInspector.domBreakpointManager.setBreakpoint.bind(WebInspector.domBreakpointManager, this.representedObject, WebInspector.DOMBreakpoint.Types.AttributeModified)); - contextMenu.appendItem(WebInspector.UIString("Stop on Node Removal"), - WebInspector.domBreakpointManager.setBreakpoint.bind(WebInspector.domBreakpointManager, this.representedObject, WebInspector.DOMBreakpoint.Types.NodeRemoved)); - - contextMenu.appendItem(WebInspector.UIString("Remove Breakpoints"), - WebInspector.domBreakpointManager.removeBreakpointsForNode.bind(WebInspector.domBreakpointManager, this.representedObject)); + for (var type in WebInspector.DOMBreakpoint.Types) { + var typeId = WebInspector.DOMBreakpoint.Types[type]; + var label = WebInspector.DOMBreakpoint.contextMenuLabelForType(typeId); + var breakpoint = WebInspector.domBreakpointManager.findBreakpoint(this.representedObject.id, typeId); + if (!breakpoint) + var handler = WebInspector.domBreakpointManager.setBreakpoint.bind(WebInspector.domBreakpointManager, this.representedObject, typeId); + else + var handler = breakpoint.remove.bind(breakpoint); + contextMenu.appendCheckboxItem(label, handler, !!breakpoint); + } } }, @@ -1125,8 +1125,7 @@ WebInspector.ElementsTreeElement.prototype = { moveToNextAttributeIfNeeded.call(newTreeItem); } - var callId = WebInspector.Callback.wrap(changeTagNameCallback); - InspectorBackend.changeTagName(callId, this.representedObject.id, newText); + InspectorBackend.changeTagName(this.representedObject.id, newText, changeTagNameCallback); }, _textNodeEditingCommitted: function(element, newText) @@ -1265,6 +1264,11 @@ WebInspector.ElementsTreeElement.prototype = { info.title = "Document Fragment"; break; + case Node.ATTRIBUTE_NODE: + var value = node.value || "\u200B"; // Zero width space to force showing an empty value. + info.title = this._attributeHTML(node.name, value); + break; + case Node.ELEMENT_NODE: var tagName = this.treeOutline.nodeNameToCorrectCase(node.nodeName).escapeHTML(); if (this._elementCloseTag) { @@ -1374,8 +1378,7 @@ WebInspector.ElementsTreeElement.prototype = { parentElement.adjustCollapsedRange(true); } - var callId = WebInspector.Callback.wrap(removeNodeCallback); - InspectorBackend.removeNode(callId, this.representedObject.id); + InspectorBackend.removeNode(this.representedObject.id, removeNodeCallback); }, _editAsHTML: function() @@ -1402,12 +1405,10 @@ WebInspector.ElementsTreeElement.prototype = { function commitChange(value) { - var setCallId = WebInspector.Callback.wrap(selectNode); - InspectorBackend.setOuterHTML(setCallId, node.id, value); + InspectorBackend.setOuterHTML(node.id, value, selectNode); } - var getCallId = WebInspector.Callback.wrap(this._startEditingAsHTML.bind(this, commitChange)); - InspectorBackend.getOuterHTML(getCallId, node.id); + InspectorBackend.getOuterHTML(node.id, this._startEditingAsHTML.bind(this, commitChange)); }, _copyHTML: function() diff --git a/WebCore/inspector/front-end/EventListenersSidebarPane.js b/WebCore/inspector/front-end/EventListenersSidebarPane.js index 2800d6e..34dea00 100644 --- a/WebCore/inspector/front-end/EventListenersSidebarPane.js +++ b/WebCore/inspector/front-end/EventListenersSidebarPane.js @@ -183,7 +183,7 @@ WebInspector.EventListenerBar = function(eventListener, nodeId) this._setFunctionSubtitle(); this.editable = false; this.element.className = "event-bar"; /* Changed from "section" */ - this.propertiesElement.className = "event-properties"; /* Changed from "properties" */ + this.propertiesElement.className = "event-properties source-code"; /* Changed from "properties" */ } WebInspector.EventListenerBar.prototype = { @@ -196,7 +196,7 @@ WebInspector.EventListenerBar.prototype = { properties.push(new WebInspector.RemoteObjectProperty("node", nodeObject)); for (var propertyName in this.eventListener) { - var value = WebInspector.RemoteObject.fromPrimitiveValue(value); + var value = WebInspector.RemoteObject.fromPrimitiveValue(this.eventListener[propertyName]); properties.push(new WebInspector.RemoteObjectProperty(propertyName, value)); } this.updateProperties(properties); diff --git a/WebCore/inspector/front-end/ExtensionAPI.js b/WebCore/inspector/front-end/ExtensionAPI.js index a89dcf1..64f5482 100644 --- a/WebCore/inspector/front-end/ExtensionAPI.js +++ b/WebCore/inspector/front-end/ExtensionAPI.js @@ -28,7 +28,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var injectedExtensionAPI = function(InjectedScriptHost, inspectedWindow, injectedScriptId) +WebInspector.injectedExtensionAPI = function(InjectedScriptHost, inspectedWindow, injectedScriptId) { // Here and below, all constructors are private to API implementation. @@ -37,19 +37,22 @@ var injectedExtensionAPI = function(InjectedScriptHost, inspectedWindow, injecte // by Foo consutrctor to re-bind publicly exported members to an instance // of Foo. -function EventSinkImpl(type) +function EventSinkImpl(type, customDispatch) { this._type = type; this._listeners = []; + this._customDispatch = customDispatch; } EventSinkImpl.prototype = { addListener: function(callback) { + if (typeof callback != "function") + throw new "addListener: callback is not a function"; if (this._listeners.length === 0) extensionServer.sendRequest({ command: "subscribe", type: this._type }); this._listeners.push(callback); - extensionServer.registerHandler("notify-" + this._type, bind(this._fire, this)); + extensionServer.registerHandler("notify-" + this._type, bind(this._dispatch, this)); }, removeListener: function(callback) @@ -66,26 +69,36 @@ EventSinkImpl.prototype = { extensionServer.sendRequest({ command: "unsubscribe", type: this._type }); }, - _fire: function(request) + _fire: function() { var listeners = this._listeners.slice(); for (var i = 0; i < listeners.length; ++i) - listeners[i].apply(null, request.arguments); + listeners[i].apply(null, arguments); + }, + + _dispatch: function(request) + { + if (this._customDispatch) + this._customDispatch.call(this, request); + else + this._fire.apply(this, request.arguments); } } -function EventSink(type) +function EventSink(type, customDispatch) { - var impl = new EventSinkImpl(type); + var impl = new EventSinkImpl(type, customDispatch); this.addListener = bind(impl.addListener, impl); this.removeListener = bind(impl.removeListener, impl); } function InspectorExtensionAPI() { + this.audits = new Audits(); this.inspectedWindow = new InspectedWindow(); this.panels = new Panels(); this.resources = new Resources(); + this.onReset = new EventSink("reset"); } @@ -125,7 +138,7 @@ function Panels() { return panels[name]; } - + for (var i = 0; i < wellKnownPanelNames.length; ++i) { var name = wellKnownPanelNames[i]; panels[name] = new Panel(name); @@ -151,7 +164,7 @@ Panels.prototype = { id: id, label: label, url: expandURL(pageURL), - icon: expandURL(iconURL) + icon: expandURL(iconURL) }; extensionServer.sendRequest(request, callback && bind(callbackWrapper, this)); } @@ -219,6 +232,124 @@ function ExtensionSidebarPane(id) this.setExpanded = bind(impl.setExpanded, impl); } +function Audits() +{ +} + +Audits.prototype = { + addCategory: function(displayName, ruleCount) + { + var id = "extension-audit-category-" + extensionServer.nextObjectId(); + extensionServer.sendRequest({ command: "addAuditCategory", id: id, displayName: displayName, ruleCount: ruleCount }); + return new AuditCategory(id); + } +} + +function AuditCategory(id) +{ + function customDispatch(request) + { + var auditResult = new AuditResult(request.arguments[0]); + try { + this._fire(auditResult); + } catch (e) { + console.error("Uncaught exception in extension audit event handler: " + e); + auditResult.done(); + } + } + var impl = new AuditCategoryImpl(id); + this.onAuditStarted = new EventSink("audit-started-" + id, customDispatch); +} + +function AuditCategoryImpl(id) +{ + this._id = id; +} + +function AuditResult(id) +{ + var impl = new AuditResultImpl(id); + + this.addResult = bind(impl.addResult, impl); + this.createResult = bind(impl.createResult, impl); + this.done = bind(impl.done, impl); + + var formatterTypes = [ + "url", + "snippet", + "text" + ]; + for (var i = 0; i < formatterTypes.length; ++i) + this[formatterTypes[i]] = bind(impl._nodeFactory, null, formatterTypes[i]); +} + +AuditResult.prototype = { + get Severity() + { + return private.audits.Severity; + } +} + +function AuditResultImpl(id) +{ + this._id = id; +} + +AuditResultImpl.prototype = { + addResult: function(displayName, description, severity, details) + { + // shorthand for specifying details directly in addResult(). + if (details && !(details instanceof AuditResultNode)) + details = details instanceof Array ? this.createNode.apply(this, details) : this.createNode(details); + + var request = { + command: "addAuditResult", + resultId: this._id, + displayName: displayName, + description: description, + severity: severity, + details: details + }; + extensionServer.sendRequest(request); + }, + + createResult: function() + { + var node = new AuditResultNode(); + node.contents = Array.prototype.slice.call(arguments); + return node; + }, + + done: function() + { + extensionServer.sendRequest({ command: "stopAuditCategoryRun", resultId: this._id }); + }, + + _nodeFactory: function(type) + { + return { + type: type, + arguments: Array.prototype.slice.call(arguments, 1) + }; + } +} + +function AuditResultNode(contents) +{ + this.contents = contents; + this.children = []; + this.expanded = false; +} + +AuditResultNode.prototype = { + addChild: function() + { + var node = AuditResultImpl.prototype.createResult.apply(null, arguments); + this.children.push(node); + return node; + } +}; + function InspectedWindow() { this.onLoaded = new EventSink("inspectedPageLoaded"); @@ -234,7 +365,13 @@ InspectedWindow.prototype = { evaluate: function(expression, callback) { - return extensionServer.sendRequest({ command: "evaluateOnInspectedPage", expression: expression }, callback); + function callbackWrapper(result) + { + if (result && !result.isException) + result.value = result.value === "undefined" ? undefined : JSON.parse(result.value); + callback(result); + } + return extensionServer.sendRequest({ command: "evaluateOnInspectedPage", expression: expression }, callback && callbackWrapper); } } diff --git a/WebCore/inspector/front-end/ExtensionAuditCategory.js b/WebCore/inspector/front-end/ExtensionAuditCategory.js new file mode 100644 index 0000000..5d155d7 --- /dev/null +++ b/WebCore/inspector/front-end/ExtensionAuditCategory.js @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2010 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.ExtensionAuditCategory = function(id, displayName, ruleCount) +{ + this._id = id; + this._displayName = displayName; + this._ruleCount = ruleCount; +} + +WebInspector.ExtensionAuditCategory.prototype = { + // AuditCategory interface + get id() + { + return this._id; + }, + + get displayName() + { + return this._displayName; + }, + + get ruleCount() + { + return this._ruleCount; + }, + + run: function(resources, callback) + { + new WebInspector.ExtensionAuditCategoryResults(this, callback); + } +} + +WebInspector.ExtensionAuditCategoryResults = function(category, callback) +{ + this._category = category; + this._pendingRules = category.ruleCount; + this._ruleCompletionCallback = callback; + + this.id = category.id + "-" + ++WebInspector.ExtensionAuditCategoryResults._lastId; + WebInspector.extensionServer.startAuditRun(category, this); +} + +WebInspector.ExtensionAuditCategoryResults.prototype = { + get complete() + { + return !this._pendingRules; + }, + + cancel: function() + { + while (!this.complete) + this._addResult(null); + }, + + addResult: function(displayName, description, severity, details) + { + var result = new WebInspector.AuditRuleResult(displayName); + result.addChild(description); + result.severity = severity; + if (details) + this._addNode(result, details); + this._addResult(result); + }, + + _addNode: function(parent, node) + { + var addedNode = parent.addChild(node.contents, node.expanded); + if (node.children) { + for (var i = 0; i < node.children.length; ++i) + this._addNode(addedNode, node.children[i]); + } + }, + + _addResult: function(result) + { + this._ruleCompletionCallback(result); + this._pendingRules--; + if (!this._pendingRules) + WebInspector.extensionServer.stopAuditRun(this); + } +} + +WebInspector.ExtensionAuditCategoryResults._lastId = 0; diff --git a/WebCore/inspector/front-end/ExtensionCommon.js b/WebCore/inspector/front-end/ExtensionCommon.js new file mode 100644 index 0000000..b04c18c --- /dev/null +++ b/WebCore/inspector/front-end/ExtensionCommon.js @@ -0,0 +1,46 @@ +/* + * Copyright (C) 2010 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.commonExtensionSymbols = function(private) +{ + + if (!private.audits) + private.audits = {}; + + private.audits.Severity = { + Info: "info", + Warning: "warning", + Severe: "severe" + }; +} + +WebInspector.extensionAPI = {}; + +WebInspector.commonExtensionSymbols(WebInspector.extensionAPI); diff --git a/WebCore/inspector/front-end/ExtensionServer.js b/WebCore/inspector/front-end/ExtensionServer.js index 95f373f..f410d8c 100644 --- a/WebCore/inspector/front-end/ExtensionServer.js +++ b/WebCore/inspector/front-end/ExtensionServer.js @@ -40,11 +40,15 @@ WebInspector.ExtensionServer = function() this._registerHandler("getResources", this._onGetResources.bind(this)); this._registerHandler("createPanel", this._onCreatePanel.bind(this)); this._registerHandler("createSidebarPane", this._onCreateSidebar.bind(this)); - this._registerHandler("log", this._onLog.bind(this)); + this._registerHandler("log", this._onLog.bind(this)); this._registerHandler("evaluateOnInspectedPage", this._onEvaluateOnInspectedPage.bind(this)); this._registerHandler("setSidebarHeight", this._onSetSidebarHeight.bind(this)); this._registerHandler("setSidebarExpanded", this._onSetSidebarExpansion.bind(this)); + this._registerHandler("addAuditCategory", this._onAddAuditCategory.bind(this)); + this._registerHandler("addAuditResult", this._onAddAuditResult.bind(this)); + this._registerHandler("stopAuditCategoryRun", this._onStopAuditCategoryRun.bind(this)); + window.addEventListener("message", this._onWindowMessage.bind(this), false); } @@ -84,6 +88,17 @@ WebInspector.ExtensionServer.prototype = { this._postNotification("reset"); }, + startAuditRun: function(category, auditRun) + { + this._clientObjects[auditRun.id] = auditRun; + this._postNotification("audit-started-" + category.id, auditRun.id); + }, + + stopAuditRun: function(auditRun) + { + delete this._clientObjects[auditRun.id]; + }, + _convertResource: function(resource) { return { @@ -100,7 +115,7 @@ WebInspector.ExtensionServer.prototype = { return; var message = { command: "notify-" + type, - arguments: Array.prototype.slice.call(arguments, 1) + arguments: Array.prototype.slice.call(arguments, 1) }; for (var i = 0; i < subscribers.length; ++i) subscribers[i].postMessage(message); @@ -195,7 +210,6 @@ WebInspector.ExtensionServer.prototype = { _onEvaluateOnInspectedPage: function(message, port) { - var escapedMessage = escape(message.expression); function callback(resultPayload) { var resultObject = WebInspector.RemoteObject.fromPayload(resultPayload); @@ -205,7 +219,10 @@ WebInspector.ExtensionServer.prototype = { result.value = resultObject.description; this._dispatchCallback(message.requestId, port, result); } - InjectedScriptAccess.getDefault().evaluate("(function() { var a = window.eval(unescape(\"" + escapedMessage + "\")); return JSON.stringify(a); })();", "", callback.bind(this)); + var evalExpression = "JSON.stringify(eval('" + + "with (window.console._commandLineAPI) with (window) {' + unescape('" + escape(message.expression) + + "') + '}'));"; + InjectedScriptAccess.getDefault().evaluate(evalExpression, callback.bind(this)); }, _onRevealAndSelect: function(message) @@ -248,6 +265,36 @@ WebInspector.ExtensionServer.prototype = { return response; }, + _onAddAuditCategory: function(request) + { + var category = new WebInspector.ExtensionAuditCategory(request.id, request.displayName, request.ruleCount); + if (WebInspector.panels.audits.getCategory(category.id)) + return this._status.E_EXISTS(category.id); + this._clientObjects[request.id] = category; + WebInspector.panels.audits.addCategory(category); + }, + + _onAddAuditResult: function(request) + { + var auditResult = this._clientObjects[request.resultId]; + if (!auditResult) + return this._status.E_NOTFOUND(request.resultId); + try { + auditResult.addResult(request.displayName, request.description, request.severity, request.details); + } catch (e) { + return e; + } + return this._status.OK(); + }, + + _onStopAuditCategoryRun: function(request) + { + var auditRun = this._clientObjects[request.resultId]; + if (!auditRun) + return this._status.E_NOTFOUND(request.resultId); + auditRun.cancel(); + }, + initExtensions: function() { InspectorExtensionRegistry.getExtensionsAsync(); @@ -255,7 +302,8 @@ WebInspector.ExtensionServer.prototype = { _addExtensions: function(extensions) { - InspectorFrontendHost.setExtensionAPI("(" + injectedExtensionAPI.toString() + ")"); // See ExtensionAPI.js for details. + // See ExtensionAPI.js and ExtensionCommon.js for details. + InspectorFrontendHost.setExtensionAPI(this._buildExtensionAPIInjectedScript()); for (var i = 0; i < extensions.length; ++i) { var extension = extensions[i]; try { @@ -271,6 +319,15 @@ WebInspector.ExtensionServer.prototype = { } }, + _buildExtensionAPIInjectedScript: function() + { + return "(function(){ " + + "var private = {};" + + "(" + WebInspector.commonExtensionSymbols.toString() + ")(private);" + + "(" + WebInspector.injectedExtensionAPI.toString() + ").apply(this, arguments);" + + "})"; + }, + _onWindowMessage: function(event) { if (event.data !== "registerExtension") @@ -300,12 +357,14 @@ WebInspector.ExtensionServer.prototype = { } } -WebInspector.ExtensionServer._statuses = +WebInspector.ExtensionServer._statuses = { OK: "", - E_NOTFOUND: "Object not found (%s)", - E_NOTSUPPORTED: "Object does not support requested operation (%s)", - E_EXISTS: "Object already exists (%s)" + E_EXISTS: "Object already exists: %s", + E_BADARG: "Invalid argument %s: %s", + E_BADARGTYPE: "Invalid type for argument %s: got %s, expected %s", + E_NOTFOUND: "Object not found: %s", + E_NOTSUPPORTED: "Object does not support requested operation: %s", } WebInspector.ExtensionStatus = function() @@ -319,7 +378,7 @@ WebInspector.ExtensionStatus = function() status.isError = true; console.log("Extension server error: " + String.vsprintf(description, details)); } - return status; + return status; } for (status in WebInspector.ExtensionServer._statuses) this[status] = makeStatus.bind(null, status); diff --git a/WebCore/inspector/front-end/HeapSnapshotView.js b/WebCore/inspector/front-end/HeapSnapshotView.js new file mode 100644 index 0000000..6bcc0ff --- /dev/null +++ b/WebCore/inspector/front-end/HeapSnapshotView.js @@ -0,0 +1,1008 @@ +/* + * Copyright (C) 2010 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.HeapSnapshotView = function(parent, profile) +{ + WebInspector.View.call(this); + + this.element.addStyleClass("heap-snapshot-view"); + + this.parent = parent; + this.parent.addEventListener("profile added", this._updateBaseOptions, this); + + this.showCountAsPercent = false; + this.showSizeAsPercent = false; + this.showCountDeltaAsPercent = false; + this.showSizeDeltaAsPercent = false; + + this.categories = { + code: new WebInspector.ResourceCategory("code", WebInspector.UIString("Code"), "rgb(255,121,0)"), + data: new WebInspector.ResourceCategory("data", WebInspector.UIString("Objects"), "rgb(47,102,236)") + }; + + var summaryContainer = document.createElement("div"); + summaryContainer.id = "heap-snapshot-summary-container"; + + this.countsSummaryBar = new WebInspector.SummaryBar(this.categories); + this.countsSummaryBar.element.className = "heap-snapshot-summary"; + this.countsSummaryBar.calculator = new WebInspector.HeapSummaryCountCalculator(); + var countsLabel = document.createElement("div"); + countsLabel.className = "heap-snapshot-summary-label"; + countsLabel.textContent = WebInspector.UIString("Count"); + this.countsSummaryBar.element.appendChild(countsLabel); + summaryContainer.appendChild(this.countsSummaryBar.element); + + this.sizesSummaryBar = new WebInspector.SummaryBar(this.categories); + this.sizesSummaryBar.element.className = "heap-snapshot-summary"; + this.sizesSummaryBar.calculator = new WebInspector.HeapSummarySizeCalculator(); + var sizesLabel = document.createElement("label"); + sizesLabel.className = "heap-snapshot-summary-label"; + sizesLabel.textContent = WebInspector.UIString("Size"); + this.sizesSummaryBar.element.appendChild(sizesLabel); + summaryContainer.appendChild(this.sizesSummaryBar.element); + + this.element.appendChild(summaryContainer); + + var columns = { + cons: { title: WebInspector.UIString("Constructor"), disclosure: true, sortable: true }, + count: { title: WebInspector.UIString("Count"), width: "54px", sortable: true }, + size: { title: WebInspector.UIString("Size"), width: "72px", sort: "descending", sortable: true }, + // \xb1 is a "plus-minus" sign. + countDelta: { title: WebInspector.UIString("\xb1 Count"), width: "72px", sortable: true }, + sizeDelta: { title: WebInspector.UIString("\xb1 Size"), width: "72px", sortable: true } + }; + + this.dataGrid = new WebInspector.DataGrid(columns); + this.dataGrid.addEventListener("sorting changed", this._sortData, this); + this.dataGrid.element.addEventListener("mousedown", this._mouseDownInDataGrid.bind(this), true); + this.element.appendChild(this.dataGrid.element); + + this.profile = profile; + + this.baseSelectElement = document.createElement("select"); + this.baseSelectElement.className = "status-bar-item"; + this.baseSelectElement.addEventListener("change", this._changeBase.bind(this), false); + this._updateBaseOptions(); + + this.percentButton = new WebInspector.StatusBarButton("", "percent-time-status-bar-item status-bar-item"); + this.percentButton.addEventListener("click", this._percentClicked.bind(this), false); + + this._loadProfile(this.profile, profileCallback.bind(this)); + + function profileCallback(profile) + { + var list = this._getProfiles(); + var profileIndex; + for (var i = 0; i < list.length; ++i) + if (list[i].uid === profile.uid) { + profileIndex = i; + break; + } + if (profileIndex > 0) + this.baseSelectElement.selectedIndex = profileIndex - 1; + else + this.baseSelectElement.selectedIndex = profileIndex; + this._resetDataGridList(resetCompleted.bind(this)); + } + + function resetCompleted() + { + this.refresh(); + this._updatePercentButton(); + } +} + +WebInspector.HeapSnapshotView.prototype = { + get statusBarItems() + { + return [this.baseSelectElement, this.percentButton.element]; + }, + + get profile() + { + return this._profile; + }, + + set profile(profile) + { + this._profile = profile; + }, + + show: function(parentElement) + { + WebInspector.View.prototype.show.call(this, parentElement); + this.dataGrid.updateWidths(); + }, + + hide: function() + { + WebInspector.View.prototype.hide.call(this); + this._currentSearchResultIndex = -1; + }, + + resize: function() + { + if (this.dataGrid) + this.dataGrid.updateWidths(); + }, + + refresh: function() + { + this.dataGrid.removeChildren(); + + var children = this.snapshotDataGridList.children; + var count = children.length; + for (var index = 0; index < count; ++index) + this.dataGrid.appendChild(children[index]); + + this._updateSummaryGraph(); + }, + + refreshShowAsPercents: function() + { + this._updatePercentButton(); + this.refreshVisibleData(); + }, + + _deleteSearchMatchedFlags: function(node) + { + delete node._searchMatchedConsColumn; + delete node._searchMatchedCountColumn; + delete node._searchMatchedSizeColumn; + delete node._searchMatchedCountDeltaColumn; + delete node._searchMatchedSizeDeltaColumn; + }, + + searchCanceled: function() + { + if (this._searchResults) { + for (var i = 0; i < this._searchResults.length; ++i) { + var profileNode = this._searchResults[i].profileNode; + this._deleteSearchMatchedFlags(profileNode); + profileNode.refresh(); + } + } + + delete this._searchFinishedCallback; + this._currentSearchResultIndex = -1; + this._searchResults = []; + }, + + performSearch: function(query, finishedCallback) + { + // Call searchCanceled since it will reset everything we need before doing a new search. + this.searchCanceled(); + + query = query.trim(); + + if (!query.length) + return; + + this._searchFinishedCallback = finishedCallback; + + var helper = WebInspector.HeapSnapshotView.SearchHelper; + + var operationAndNumber = helper.parseOperationAndNumber(query); + var operation = operationAndNumber[0]; + var queryNumber = operationAndNumber[1]; + + var percentUnits = helper.percents.test(query); + var megaBytesUnits = helper.megaBytes.test(query); + var kiloBytesUnits = helper.kiloBytes.test(query); + var bytesUnits = helper.bytes.test(query); + + var queryNumberBytes = (megaBytesUnits ? (queryNumber * 1024 * 1024) : (kiloBytesUnits ? (queryNumber * 1024) : queryNumber)); + + function matchesQuery(heapSnapshotDataGridNode) + { + WebInspector.HeapSnapshotView.prototype._deleteSearchMatchedFlags(heapSnapshotDataGridNode); + + if (percentUnits) { + heapSnapshotDataGridNode._searchMatchedCountColumn = operation(heapSnapshotDataGridNode.countPercent, queryNumber); + heapSnapshotDataGridNode._searchMatchedSizeColumn = operation(heapSnapshotDataGridNode.sizePercent, queryNumber); + heapSnapshotDataGridNode._searchMatchedCountDeltaColumn = operation(heapSnapshotDataGridNode.countDeltaPercent, queryNumber); + heapSnapshotDataGridNode._searchMatchedSizeDeltaColumn = operation(heapSnapshotDataGridNode.sizeDeltaPercent, queryNumber); + } else if (megaBytesUnits || kiloBytesUnits || bytesUnits) { + heapSnapshotDataGridNode._searchMatchedSizeColumn = operation(heapSnapshotDataGridNode.size, queryNumberBytes); + heapSnapshotDataGridNode._searchMatchedSizeDeltaColumn = operation(heapSnapshotDataGridNode.sizeDelta, queryNumberBytes); + } else { + heapSnapshotDataGridNode._searchMatchedCountColumn = operation(heapSnapshotDataGridNode.count, queryNumber); + heapSnapshotDataGridNode._searchMatchedCountDeltaColumn = operation(heapSnapshotDataGridNode.countDelta, queryNumber); + } + + if (heapSnapshotDataGridNode.constructorName.hasSubstring(query, true)) + heapSnapshotDataGridNode._searchMatchedConsColumn = true; + + if (heapSnapshotDataGridNode._searchMatchedConsColumn || + heapSnapshotDataGridNode._searchMatchedCountColumn || + heapSnapshotDataGridNode._searchMatchedSizeColumn || + heapSnapshotDataGridNode._searchMatchedCountDeltaColumn || + heapSnapshotDataGridNode._searchMatchedSizeDeltaColumn) { + heapSnapshotDataGridNode.refresh(); + return true; + } + + return false; + } + + var current = this.snapshotDataGridList.children[0]; + var depth = 0; + var info = {}; + + // The second and subsequent levels of heap snapshot nodes represent retainers, + // so recursive expansion will be infinite, since a graph is being traversed. + // So default to a recursion cap of 2 levels. + const maxDepth = 2; + + while (current) { + if (matchesQuery(current)) + this._searchResults.push({ profileNode: current }); + current = current.traverseNextNode(false, null, (depth >= maxDepth), info); + depth += info.depthChange; + } + + finishedCallback(this, this._searchResults.length); + }, + + // FIXME: move these methods to a superclass, inherit both views from it. + jumpToFirstSearchResult: WebInspector.CPUProfileView.prototype.jumpToFirstSearchResult, + jumpToLastSearchResult: WebInspector.CPUProfileView.prototype.jumpToLastSearchResult, + jumpToNextSearchResult: WebInspector.CPUProfileView.prototype.jumpToNextSearchResult, + jumpToPreviousSearchResult: WebInspector.CPUProfileView.prototype.jumpToPreviousSearchResult, + showingFirstSearchResult: WebInspector.CPUProfileView.prototype.showingFirstSearchResult, + showingLastSearchResult: WebInspector.CPUProfileView.prototype.showingLastSearchResult, + _jumpToSearchResult: WebInspector.CPUProfileView.prototype._jumpToSearchResult, + + refreshVisibleData: function() + { + var child = this.dataGrid.children[0]; + while (child) { + child.refresh(); + child = child.traverseNextNode(false, null, true); + } + this._updateSummaryGraph(); + }, + + _changeBase: function() + { + if (this.baseSnapshot.uid === this._getProfiles()[this.baseSelectElement.selectedIndex].uid) + return; + + this._resetDataGridList(resetCompleted.bind(this)); + + function resetCompleted() { + this.refresh(); + + if (!this.currentQuery || !this._searchFinishedCallback || !this._searchResults) + return; + + // The current search needs to be performed again. First negate out previous match + // count by calling the search finished callback with a negative number of matches. + // Then perform the search again with the same query and callback. + this._searchFinishedCallback(this, -this._searchResults.length); + this.performSearch(this.currentQuery, this._searchFinishedCallback); + } + }, + + _createSnapshotDataGridList: function() + { + if (this._snapshotDataGridList) + delete this._snapshotDataGridList; + + this._snapshotDataGridList = new WebInspector.HeapSnapshotDataGridList(this, this.baseSnapshot.entries, this.profile.entries); + return this._snapshotDataGridList; + }, + + _getProfiles: function() + { + return WebInspector.panels.profiles.getProfiles(WebInspector.HeapSnapshotProfileType.TypeId); + }, + + _loadProfile: function(profile, callback) + { + if (profile._loaded) { + callback(profile); + return; + } + + InspectorBackend.getProfile(profile.typeId, profile.uid, loadedCallback.bind(this)); + + function loadedCallback(loadedSnapshot) { + profile.children = loadedSnapshot.head.children; + profile.entries = loadedSnapshot.head.entries; + profile.lowlevels = loadedSnapshot.head.lowlevels; + this._prepareProfile(profile); + profile._loaded = true; + this.parent.updateProfile(profile); + callback(profile); + } + }, + + _mouseDownInDataGrid: function(event) + { + if (event.detail < 2) + return; + + var cell = event.target.enclosingNodeOrSelfWithNodeName("td"); + if (!cell || (!cell.hasStyleClass("count-column") && !cell.hasStyleClass("size-column") && !cell.hasStyleClass("countDelta-column") && !cell.hasStyleClass("sizeDelta-column"))) + return; + + if (cell.hasStyleClass("count-column")) + this.showCountAsPercent = !this.showCountAsPercent; + else if (cell.hasStyleClass("size-column")) + this.showSizeAsPercent = !this.showSizeAsPercent; + else if (cell.hasStyleClass("countDelta-column")) + this.showCountDeltaAsPercent = !this.showCountDeltaAsPercent; + else if (cell.hasStyleClass("sizeDelta-column")) + this.showSizeDeltaAsPercent = !this.showSizeDeltaAsPercent; + + this.refreshShowAsPercents(); + + event.preventDefault(); + event.stopPropagation(); + }, + + get _isShowingAsPercent() + { + return this.showCountAsPercent && this.showSizeAsPercent && this.showCountDeltaAsPercent && this.showSizeDeltaAsPercent; + }, + + _percentClicked: function(event) + { + var currentState = this._isShowingAsPercent; + this.showCountAsPercent = !currentState; + this.showSizeAsPercent = !currentState; + this.showCountDeltaAsPercent = !currentState; + this.showSizeDeltaAsPercent = !currentState; + this.refreshShowAsPercents(); + }, + + _prepareProfile: function(profile) + { + for (var profileEntry in profile.entries) + profile.entries[profileEntry].retainers = {}; + profile.clusters = {}; + + for (var addr in profile.children) { + var retainer = profile.children[addr]; + var retainerId = retainer.constructorName + ':' + addr; + for (var childAddr in retainer) { + if (childAddr === 'constructorName') continue; + var item = retainer[childAddr]; + var itemId = item.constructorName + ':' + childAddr; + if ((item.constructorName === 'Object' || item.constructorName === 'Array')) { + if (!(itemId in profile.clusters)) + profile.clusters[itemId] = { constructorName: itemId, retainers: {} }; + mergeRetainers(profile.clusters[itemId], item); + } + mergeRetainers(profile.entries[item.constructorName], item); + } + } + + function mergeRetainers(entry, item) + { + if (!(retainer.constructorName in entry.retainers)) + entry.retainers[retainer.constructorName] = { constructorName: retainer.constructorName, count: 0, clusters: {} }; + var retainerEntry = entry.retainers[retainer.constructorName]; + retainerEntry.count += item.count; + if (retainer.constructorName === 'Object' || retainer.constructorName === 'Array') + retainerEntry.clusters[retainerId] = true; + } + }, + + _resetDataGridList: function(callback) + { + this._loadProfile(this._getProfiles()[this.baseSelectElement.selectedIndex], profileLoaded.bind(this)); + + function profileLoaded(profile) + { + this.baseSnapshot = profile; + var lastComparator = WebInspector.HeapSnapshotDataGridList.propertyComparator("size", false); + if (this.snapshotDataGridList) + lastComparator = this.snapshotDataGridList.lastComparator; + this.snapshotDataGridList = this._createSnapshotDataGridList(); + this.snapshotDataGridList.sort(lastComparator, true); + callback(); + } + }, + + _sortData: function() + { + var sortAscending = this.dataGrid.sortOrder === "ascending"; + var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier; + var sortProperty = { + cons: ["cons", null], + count: ["count", null], + size: ["size", "count"], + countDelta: this.showCountDeltaAsPercent ? ["countDeltaPercent", null] : ["countDelta", null], + sizeDelta: this.showSizeDeltaAsPercent ? ["sizeDeltaPercent", "countDeltaPercent"] : ["sizeDelta", "sizeDeltaPercent"] + }[sortColumnIdentifier]; + + this.snapshotDataGridList.sort(WebInspector.HeapSnapshotDataGridList.propertyComparator(sortProperty[0], sortProperty[1], sortAscending)); + + this.refresh(); + }, + + _updateBaseOptions: function() + { + var list = this._getProfiles(); + // We're assuming that snapshots can only be added. + if (this.baseSelectElement.length === list.length) + return; + + for (var i = this.baseSelectElement.length, n = list.length; i < n; ++i) { + var baseOption = document.createElement("option"); + var title = list[i].title; + if (!title.indexOf(UserInitiatedProfileName)) + title = WebInspector.UIString("Snapshot %d", title.substring(UserInitiatedProfileName.length + 1)); + baseOption.label = WebInspector.UIString("Compared to %s", title); + this.baseSelectElement.appendChild(baseOption); + } + }, + + _updatePercentButton: function() + { + if (this._isShowingAsPercent) { + this.percentButton.title = WebInspector.UIString("Show absolute counts and sizes."); + this.percentButton.toggled = true; + } else { + this.percentButton.title = WebInspector.UIString("Show counts and sizes as percentages."); + this.percentButton.toggled = false; + } + }, + + _updateSummaryGraph: function() + { + this.countsSummaryBar.calculator.showAsPercent = this._isShowingAsPercent; + this.countsSummaryBar.update(this.profile.lowlevels); + + this.sizesSummaryBar.calculator.showAsPercent = this._isShowingAsPercent; + this.sizesSummaryBar.update(this.profile.lowlevels); + } +}; + +WebInspector.HeapSnapshotView.prototype.__proto__ = WebInspector.View.prototype; + +WebInspector.HeapSnapshotView.SearchHelper = { + // In comparators, we assume that a value from a node is passed as the first parameter. + operations: { + LESS: function (a, b) { return a !== null && a < b; }, + LESS_OR_EQUAL: function (a, b) { return a !== null && a <= b; }, + EQUAL: function (a, b) { return a !== null && a === b; }, + GREATER_OR_EQUAL: function (a, b) { return a !== null && a >= b; }, + GREATER: function (a, b) { return a !== null && a > b; } + }, + + operationParsers: { + LESS: /^<(\d+)/, + LESS_OR_EQUAL: /^<=(\d+)/, + GREATER_OR_EQUAL: /^>=(\d+)/, + GREATER: /^>(\d+)/ + }, + + parseOperationAndNumber: function(query) + { + var operations = WebInspector.HeapSnapshotView.SearchHelper.operations; + var parsers = WebInspector.HeapSnapshotView.SearchHelper.operationParsers; + for (var operation in parsers) { + var match = query.match(parsers[operation]); + if (match !== null) + return [operations[operation], parseFloat(match[1])]; + } + return [operations.EQUAL, parseFloat(query)]; + }, + + percents: /%$/, + + megaBytes: /MB$/i, + + kiloBytes: /KB$/i, + + bytes: /B$/i +} + +WebInspector.HeapSummaryCalculator = function(lowLevelField) +{ + this.total = 1; + this.lowLevelField = lowLevelField; +} + +WebInspector.HeapSummaryCalculator.prototype = { + computeSummaryValues: function(lowLevels) + { + var highLevels = { data: 0, code: 0 }; + this.total = 0; + for (var item in lowLevels) { + var highItem = this._highFromLow(item); + if (highItem) { + var value = lowLevels[item][this.lowLevelField]; + highLevels[highItem] += value; + this.total += value; + } + } + var result = { categoryValues: highLevels }; + if (!this.showAsPercent) + result.total = this.total; + return result; + }, + + formatValue: function(value) + { + if (this.showAsPercent) + return WebInspector.UIString("%.2f%%", value / this.total * 100.0); + else + return this._valueToString(value); + }, + + get showAsPercent() + { + return this._showAsPercent; + }, + + set showAsPercent(x) + { + this._showAsPercent = x; + } +} + +WebInspector.HeapSummaryCountCalculator = function() +{ + WebInspector.HeapSummaryCalculator.call(this, "count"); +} + +WebInspector.HeapSummaryCountCalculator.prototype = { + _highFromLow: function(type) + { + if (type === "CODE_TYPE" || type === "SHARED_FUNCTION_INFO_TYPE" || type === "SCRIPT_TYPE") return "code"; + if (type === "STRING_TYPE" || type === "HEAP_NUMBER_TYPE" || type.match(/^JS_/)) return "data"; + return null; + }, + + _valueToString: function(value) + { + return value.toString(); + } +} + +WebInspector.HeapSummaryCountCalculator.prototype.__proto__ = WebInspector.HeapSummaryCalculator.prototype; + +WebInspector.HeapSummarySizeCalculator = function() +{ + WebInspector.HeapSummaryCalculator.call(this, "size"); +} + +WebInspector.HeapSummarySizeCalculator.prototype = { + _highFromLow: function(type) + { + if (type === "CODE_TYPE" || type === "SHARED_FUNCTION_INFO_TYPE" || type === "SCRIPT_TYPE") + return "code"; + if (type === "STRING_TYPE" || type === "HEAP_NUMBER_TYPE" || type.match(/^JS_/) || type.match(/_ARRAY_TYPE$/)) + return "data"; + return null; + }, + + _valueToString: Number.bytesToString +} + +WebInspector.HeapSummarySizeCalculator.prototype.__proto__ = WebInspector.HeapSummaryCalculator.prototype; + +WebInspector.HeapSnapshotDataGridNodeWithRetainers = function(owningTree) +{ + this.tree = owningTree; + + WebInspector.DataGridNode.call(this, null, this._hasRetainers); + + this.addEventListener("populate", this._populate, this); +}; + +WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype = { + isEmptySet: function(set) + { + for (var x in set) + return false; + return true; + }, + + get _hasRetainers() + { + return !this.isEmptySet(this.retainers); + }, + + get _parent() + { + // For top-level nodes, return owning tree as a parent, not data grid. + return this.parent !== this.dataGrid ? this.parent : this.tree; + }, + + _populate: function(event) + { + function appendDiffEntry(baseItem, snapshotItem) + { + this.appendChild(new WebInspector.HeapSnapshotDataGridRetainerNode(this.snapshotView, baseItem, snapshotItem, this.tree)); + } + + this.produceDiff(this.baseRetainers, this.retainers, appendDiffEntry.bind(this)); + + if (this._parent) { + var currentComparator = this._parent.lastComparator; + if (currentComparator) + this.sort(currentComparator, true); + } + + this.removeEventListener("populate", this._populate, this); + }, + + produceDiff: function(baseEntries, currentEntries, callback) + { + for (var item in currentEntries) + callback(baseEntries[item], currentEntries[item]); + + for (item in baseEntries) { + if (!(item in currentEntries)) + callback(baseEntries[item], null); + } + }, + + sort: function(comparator, force) { + if (!force && this.lastComparator === comparator) + return; + + this.children.sort(comparator); + var childCount = this.children.length; + for (var childIndex = 0; childIndex < childCount; ++childIndex) + this.children[childIndex]._recalculateSiblings(childIndex); + for (var i = 0; i < this.children.length; ++i) { + var child = this.children[i]; + if (!force && (!child.expanded || child.lastComparator === comparator)) + continue; + child.sort(comparator, force); + } + this.lastComparator = comparator; + }, + + signForDelta: function(delta) { + if (delta === 0) + return ""; + if (delta > 0) + return "+"; + else + return "\u2212"; // Math minus sign, same width as plus. + }, + + showDeltaAsPercent: function(value) + { + if (value === Number.POSITIVE_INFINITY) + return WebInspector.UIString("new"); + else if (value === Number.NEGATIVE_INFINITY) + return WebInspector.UIString("deleted"); + if (value > 1000.0) + return WebInspector.UIString("%s >1000%%", this.signForDelta(value)); + return WebInspector.UIString("%s%.2f%%", this.signForDelta(value), Math.abs(value)); + }, + + getTotalCount: function() + { + if (!this._count) { + this._count = 0; + for (var i = 0, n = this.children.length; i < n; ++i) + this._count += this.children[i].count; + } + return this._count; + }, + + getTotalSize: function() + { + if (!this._size) { + this._size = 0; + for (var i = 0, n = this.children.length; i < n; ++i) + this._size += this.children[i].size; + } + return this._size; + }, + + get countPercent() + { + return this.count / this._parent.getTotalCount() * 100.0; + }, + + get sizePercent() + { + return this.size / this._parent.getTotalSize() * 100.0; + }, + + get countDeltaPercent() + { + if (this.baseCount > 0) { + if (this.count > 0) + return this.countDelta / this.baseCount * 100.0; + else + return Number.NEGATIVE_INFINITY; + } else + return Number.POSITIVE_INFINITY; + }, + + get sizeDeltaPercent() + { + if (this.baseSize > 0) { + if (this.size > 0) + return this.sizeDelta / this.baseSize * 100.0; + else + return Number.NEGATIVE_INFINITY; + } else + return Number.POSITIVE_INFINITY; + }, + + get data() + { + var data = {}; + + data["cons"] = this.constructorName; + + if (this.snapshotView.showCountAsPercent) + data["count"] = WebInspector.UIString("%.2f%%", this.countPercent); + else + data["count"] = this.count; + + if (this.size !== null) { + if (this.snapshotView.showSizeAsPercent) + data["size"] = WebInspector.UIString("%.2f%%", this.sizePercent); + else + data["size"] = Number.bytesToString(this.size); + } else + data["size"] = ""; + + if (this.snapshotView.showCountDeltaAsPercent) + data["countDelta"] = this.showDeltaAsPercent(this.countDeltaPercent); + else + data["countDelta"] = WebInspector.UIString("%s%d", this.signForDelta(this.countDelta), Math.abs(this.countDelta)); + + if (this.sizeDelta !== null) { + if (this.snapshotView.showSizeDeltaAsPercent) + data["sizeDelta"] = this.showDeltaAsPercent(this.sizeDeltaPercent); + else + data["sizeDelta"] = WebInspector.UIString("%s%s", this.signForDelta(this.sizeDelta), Number.bytesToString(Math.abs(this.sizeDelta))); + } else + data["sizeDelta"] = ""; + + return data; + }, + + createCell: function(columnIdentifier) + { + var cell = WebInspector.DataGridNode.prototype.createCell.call(this, columnIdentifier); + + if ((columnIdentifier === "cons" && this._searchMatchedConsColumn) || + (columnIdentifier === "count" && this._searchMatchedCountColumn) || + (columnIdentifier === "size" && this._searchMatchedSizeColumn) || + (columnIdentifier === "countDelta" && this._searchMatchedCountDeltaColumn) || + (columnIdentifier === "sizeDelta" && this._searchMatchedSizeDeltaColumn)) + cell.addStyleClass("highlight"); + + return cell; + } +}; + +WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.__proto__ = WebInspector.DataGridNode.prototype; + +WebInspector.HeapSnapshotDataGridNode = function(snapshotView, baseEntry, snapshotEntry, owningTree) +{ + this.snapshotView = snapshotView; + + if (!snapshotEntry) + snapshotEntry = { constructorName: baseEntry.constructorName, count: 0, size: 0, retainers: {} }; + this.constructorName = snapshotEntry.constructorName; + this.count = snapshotEntry.count; + this.size = snapshotEntry.size; + this.retainers = snapshotEntry.retainers; + + if (!baseEntry) + baseEntry = { count: 0, size: 0, retainers: {} }; + this.baseCount = baseEntry.count; + this.countDelta = this.count - this.baseCount; + this.baseSize = baseEntry.size; + this.sizeDelta = this.size - this.baseSize; + this.baseRetainers = baseEntry.retainers; + + WebInspector.HeapSnapshotDataGridNodeWithRetainers.call(this, owningTree); +}; + +WebInspector.HeapSnapshotDataGridNode.prototype.__proto__ = WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype; + +WebInspector.HeapSnapshotDataGridList = function(snapshotView, baseEntries, snapshotEntries) +{ + this.tree = this; + this.snapshotView = snapshotView; + this.children = []; + this.lastComparator = null; + this.populateChildren(baseEntries, snapshotEntries); +}; + +WebInspector.HeapSnapshotDataGridList.prototype = { + appendChild: function(child) + { + this.insertChild(child, this.children.length); + }, + + insertChild: function(child, index) + { + this.children.splice(index, 0, child); + }, + + removeChildren: function() + { + this.children = []; + }, + + populateChildren: function(baseEntries, snapshotEntries) + { + function appendListEntry(baseItem, snapshotItem) + { + this.appendChild(new WebInspector.HeapSnapshotDataGridNode(this.snapshotView, baseItem, snapshotItem, this)); + } + this.produceDiff(baseEntries, snapshotEntries, appendListEntry.bind(this)); + }, + + produceDiff: WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.produceDiff, + sort: WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.sort, + getTotalCount: WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.getTotalCount, + getTotalSize: WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype.getTotalSize +}; + +WebInspector.HeapSnapshotDataGridList.propertyComparators = [{}, {}]; + +WebInspector.HeapSnapshotDataGridList.propertyComparator = function(property, property2, isAscending) +{ + var propertyHash = property + "#" + property2; + var comparator = this.propertyComparators[(isAscending ? 1 : 0)][propertyHash]; + if (!comparator) { + comparator = function(lhs, rhs) { + var l = lhs[property], r = rhs[property]; + if ((l === null || r === null) && property2 !== null) + l = lhs[property2], r = rhs[property2]; + var result = l < r ? -1 : (l > r ? 1 : 0); + return isAscending ? result : -result; + }; + this.propertyComparators[(isAscending ? 1 : 0)][propertyHash] = comparator; + } + return comparator; +}; + +WebInspector.HeapSnapshotDataGridRetainerNode = function(snapshotView, baseEntry, snapshotEntry, owningTree) +{ + this.snapshotView = snapshotView; + + if (!snapshotEntry) + snapshotEntry = { constructorName: baseEntry.constructorName, count: 0, clusters: {} }; + this.constructorName = snapshotEntry.constructorName; + this.count = snapshotEntry.count; + this.retainers = this._calculateRetainers(this.snapshotView.profile, snapshotEntry.clusters); + + if (!baseEntry) + baseEntry = { count: 0, clusters: {} }; + this.baseCount = baseEntry.count; + this.countDelta = this.count - this.baseCount; + this.baseRetainers = this._calculateRetainers(this.snapshotView.baseSnapshot, baseEntry.clusters); + + this.size = null; + this.sizeDelta = null; + + WebInspector.HeapSnapshotDataGridNodeWithRetainers.call(this, owningTree); +} + +WebInspector.HeapSnapshotDataGridRetainerNode.prototype = { + get sizePercent() + { + return null; + }, + + get sizeDeltaPercent() + { + return null; + }, + + _calculateRetainers: function(snapshot, clusters) + { + var retainers = {}; + if (this.isEmptySet(clusters)) { + if (this.constructorName in snapshot.entries) + return snapshot.entries[this.constructorName].retainers; + } else { + // In case when an entry is retained by clusters, we need to gather up the list + // of retainers by merging retainers of every cluster. + // E.g. having such a tree: + // A + // Object:1 10 + // X 3 + // Y 4 + // Object:2 5 + // X 6 + // + // will result in a following retainers list: X 9, Y 4. + for (var clusterName in clusters) { + if (clusterName in snapshot.clusters) { + var clusterRetainers = snapshot.clusters[clusterName].retainers; + for (var clusterRetainer in clusterRetainers) { + var clusterRetainerEntry = clusterRetainers[clusterRetainer]; + if (!(clusterRetainer in retainers)) + retainers[clusterRetainer] = { constructorName: clusterRetainerEntry.constructorName, count: 0, clusters: {} }; + retainers[clusterRetainer].count += clusterRetainerEntry.count; + for (var clusterRetainerCluster in clusterRetainerEntry.clusters) + retainers[clusterRetainer].clusters[clusterRetainerCluster] = true; + } + } + } + } + return retainers; + } +}; + +WebInspector.HeapSnapshotDataGridRetainerNode.prototype.__proto__ = WebInspector.HeapSnapshotDataGridNodeWithRetainers.prototype; + + +WebInspector.HeapSnapshotProfileType = function() +{ + WebInspector.ProfileType.call(this, WebInspector.HeapSnapshotProfileType.TypeId, WebInspector.UIString("HEAP SNAPSHOTS")); +} + +WebInspector.HeapSnapshotProfileType.TypeId = "HEAP"; + +WebInspector.HeapSnapshotProfileType.prototype = { + get buttonTooltip() + { + return WebInspector.UIString("Take heap snapshot."); + }, + + get buttonStyle() + { + return "heap-snapshot-status-bar-item status-bar-item"; + }, + + buttonClicked: function() + { + InspectorBackend.takeHeapSnapshot(); + }, + + get welcomeMessage() + { + return WebInspector.UIString("Get a heap snapshot by pressing the %s button on the status bar."); + }, + + createSidebarTreeElementForProfile: function(profile) + { + return new WebInspector.ProfileSidebarTreeElement(profile, WebInspector.UIString("Snapshot %d"), "heap-snapshot-sidebar-tree-item"); + }, + + createView: function(profile) + { + return new WebInspector.HeapSnapshotView(WebInspector.panels.profiles, profile); + } +} + +WebInspector.HeapSnapshotProfileType.prototype.__proto__ = WebInspector.ProfileType.prototype; diff --git a/WebCore/inspector/front-end/InjectedScriptAccess.js b/WebCore/inspector/front-end/InjectedScriptAccess.js index ce264dd..cb3c2b8 100644 --- a/WebCore/inspector/front-end/InjectedScriptAccess.js +++ b/WebCore/inspector/front-end/InjectedScriptAccess.js @@ -76,9 +76,7 @@ InjectedScriptAccess._installHandler = function(methodName, async) else WebInspector.console.addMessage(WebInspector.ConsoleMessage.createTextMessage("Error dispatching: " + methodName)); } - var callId = WebInspector.Callback.wrap(myCallback); - - InspectorBackend.dispatchOnInjectedScript(callId, this._worldId, methodName, argsString); + InspectorBackend.dispatchOnInjectedScript(this._worldId, methodName, argsString, myCallback); }; } diff --git a/WebCore/inspector/front-end/MetricsSidebarPane.js b/WebCore/inspector/front-end/MetricsSidebarPane.js index ed5a7ec..18bc240 100644 --- a/WebCore/inspector/front-end/MetricsSidebarPane.js +++ b/WebCore/inspector/front-end/MetricsSidebarPane.js @@ -52,14 +52,14 @@ WebInspector.MetricsSidebarPane.prototype = { var style = WebInspector.CSSStyleDeclaration.parseStyle(stylePayload); self._update(style); }; - InspectorBackend.getComputedStyle(WebInspector.Callback.wrap(callback), node.id); + InspectorBackend.getComputedStyle(node.id, callback); var inlineStyleCallback = function(stylePayload) { if (!stylePayload) return; self._inlineStyleId = stylePayload.id; }; - InspectorBackend.getInlineStyle(WebInspector.Callback.wrap(inlineStyleCallback), node.id); + InspectorBackend.getInlineStyle(node.id, inlineStyleCallback); }, _update: function(style) @@ -210,7 +210,7 @@ WebInspector.MetricsSidebarPane.prototype = { self.update(); }; - InspectorBackend.setStyleProperty(WebInspector.Callback.wrap(callback), this._inlineStyleId, context.styleProperty, userInput); + InspectorBackend.setStyleProperty(this._inlineStyleId, context.styleProperty, userInput, callback); } } diff --git a/WebCore/inspector/front-end/ObjectPropertiesSection.js b/WebCore/inspector/front-end/ObjectPropertiesSection.js index aab9546..015039c 100644 --- a/WebCore/inspector/front-end/ObjectPropertiesSection.js +++ b/WebCore/inspector/front-end/ObjectPropertiesSection.js @@ -184,6 +184,8 @@ WebInspector.ObjectPropertyTreeElement.prototype = { this.valueElement.addStyleClass("dimmed"); if (this.property.value.isError()) this.valueElement.addStyleClass("error"); + if (this.property.value.type) + this.valueElement.addStyleClass("console-formatted-" + this.property.value.type); this.listItemElement.removeChildren(); diff --git a/WebCore/inspector/front-end/Panel.js b/WebCore/inspector/front-end/Panel.js index 8cbdebb..2a4104f 100644 --- a/WebCore/inspector/front-end/Panel.js +++ b/WebCore/inspector/front-end/Panel.js @@ -72,6 +72,11 @@ WebInspector.Panel.prototype = { return this._toolbarItem; }, + get name() + { + return this._panelName; + }, + show: function() { WebInspector.View.prototype.show.call(this); diff --git a/WebCore/inspector/front-end/ProfileView.js b/WebCore/inspector/front-end/ProfileView.js index 817f1f5..c325bf7 100644 --- a/WebCore/inspector/front-end/ProfileView.js +++ b/WebCore/inspector/front-end/ProfileView.js @@ -94,8 +94,7 @@ WebInspector.CPUProfileView = function(profile) self._updatePercentButton(); } - var callId = WebInspector.Callback.wrap(profileCallback); - InspectorBackend.getProfile(callId, this.profile.uid); + InspectorBackend.getProfile(this.profile.typeId, this.profile.uid, profileCallback); } WebInspector.CPUProfileView.prototype = { @@ -611,7 +610,7 @@ WebInspector.CPUProfileType.prototype = { createSidebarTreeElementForProfile: function(profile) { - return new WebInspector.ProfileSidebarTreeElement(profile); + return new WebInspector.ProfileSidebarTreeElement(profile, WebInspector.UIString("Profile %d"), "profile-sidebar-tree-item"); }, createView: function(profile) diff --git a/WebCore/inspector/front-end/ProfilesPanel.js b/WebCore/inspector/front-end/ProfilesPanel.js index e18274c..2bd76f9 100644 --- a/WebCore/inspector/front-end/ProfilesPanel.js +++ b/WebCore/inspector/front-end/ProfilesPanel.js @@ -158,8 +158,7 @@ WebInspector.ProfilesPanel.prototype = { show: function() { WebInspector.Panel.prototype.show.call(this); - if (!this._profilesWereRequested) - this._populateProfiles(); + this._populateProfiles(); }, profilerWasEnabled: function() @@ -321,6 +320,7 @@ WebInspector.ProfilesPanel.prototype = { this.welcomeView.hide(); if (!this.visibleView) this.showProfile(profile); + this.dispatchEventToListeners("profile added"); } }, @@ -345,7 +345,7 @@ WebInspector.ProfilesPanel.prototype = { sidebarParent.removeChild(profile._profilesTreeElement); if (!profile.isTemporary) - InspectorBackend.removeProfile(profile.uid); + InspectorBackend.removeProfile(profile.typeId, profile.uid); // No other item will be selected if there aren't any other profiles, so // make sure that view gets cleared when the last profile is removed. @@ -376,6 +376,27 @@ WebInspector.ProfilesPanel.prototype = { this.profileViewStatusBarItemsContainer.appendChild(statusBarItems[i]); }, + getProfiles: function(typeId) + { + var result = []; + var profilesCount = this._profiles.length; + for (var i = 0; i < profilesCount; ++i) + if (this._profiles[i].typeId === typeId) + result.push(this._profiles[i]); + return result; + }, + + updateProfile: function(profile) + { + var profilesCount = this._profiles.length; + for (var i = 0; i < profilesCount; ++i) + if (this._profiles[i].typeId === profile.typeId + && this._profiles[i].uid === profile.uid) { + this._profiles[i] = profile; + break; + } + }, + showView: function(view) { this.showProfile(view.profile); @@ -510,12 +531,8 @@ WebInspector.ProfilesPanel.prototype = { _populateProfiles: function() { - var sidebarTreeChildrenCount = this.sidebarTree.children.length; - for (var i = 0; i < sidebarTreeChildrenCount; ++i) { - var treeElement = this.sidebarTree.children[i]; - if (treeElement.children.length) - return; - } + if (!this._profilerEnabled || this._profilesWereRequested) + return; function populateCallback(profileHeaders) { profileHeaders.sort(function(a, b) { return a.uid - b.uid; }); @@ -524,8 +541,7 @@ WebInspector.ProfilesPanel.prototype = { WebInspector.addProfileHeader(profileHeaders[i]); } - var callId = WebInspector.Callback.wrap(populateCallback); - InspectorBackend.getProfileHeaders(callId); + InspectorBackend.getProfileHeaders(populateCallback); this._profilesWereRequested = true; }, @@ -541,14 +557,15 @@ WebInspector.ProfilesPanel.prototype = { WebInspector.ProfilesPanel.prototype.__proto__ = WebInspector.Panel.prototype; -WebInspector.ProfileSidebarTreeElement = function(profile) +WebInspector.ProfileSidebarTreeElement = function(profile, titleFormat, className) { this.profile = profile; + this._titleFormat = titleFormat; if (this.profile.title.indexOf(UserInitiatedProfileName) === 0) this._profileNumber = this.profile.title.substring(UserInitiatedProfileName.length + 1); - WebInspector.SidebarTreeElement.call(this, "profile-sidebar-tree-item", "", "", profile, false); + WebInspector.SidebarTreeElement.call(this, className, "", "", profile, false); this.refreshTitles(); } @@ -570,7 +587,7 @@ WebInspector.ProfileSidebarTreeElement.prototype = { if (this._mainTitle) return this._mainTitle; if (this.profile.title.indexOf(UserInitiatedProfileName) === 0) - return WebInspector.UIString("Profile %d", this._profileNumber); + return WebInspector.UIString(this._titleFormat, this._profileNumber); return this.profile.title; }, diff --git a/WebCore/inspector/front-end/ResourcesPanel.js b/WebCore/inspector/front-end/ResourcesPanel.js index ff0d1ab..27df5cf 100644 --- a/WebCore/inspector/front-end/ResourcesPanel.js +++ b/WebCore/inspector/front-end/ResourcesPanel.js @@ -883,7 +883,7 @@ WebInspector.ResourcesPanel.prototype.__proto__ = WebInspector.AbstractTimelineP WebInspector.getResourceContent = function(identifier, callback) { - InspectorBackend.getResourceContent(WebInspector.Callback.wrap(callback), identifier); + InspectorBackend.getResourceContent(identifier, callback); } WebInspector.ResourceTimeCalculator = function(startAtZero) diff --git a/WebCore/inspector/front-end/ScriptView.js b/WebCore/inspector/front-end/ScriptView.js index 74dc30a..d878e9b 100644 --- a/WebCore/inspector/front-end/ScriptView.js +++ b/WebCore/inspector/front-end/ScriptView.js @@ -56,10 +56,8 @@ WebInspector.ScriptView.prototype = { if (this.script.source) this._sourceFrameSetupFinished(); - else { - var callbackId = WebInspector.Callback.wrap(this._didGetScriptSource.bind(this)) - InspectorBackend.getScriptSource(callbackId, this.script.sourceID); - } + else + InspectorBackend.getScriptSource(this.script.sourceID, this._didGetScriptSource.bind(this)); }, _didGetScriptSource: function(source) diff --git a/WebCore/inspector/front-end/ScriptsPanel.js b/WebCore/inspector/front-end/ScriptsPanel.js index 7521ea9..75fd6f7 100644 --- a/WebCore/inspector/front-end/ScriptsPanel.js +++ b/WebCore/inspector/front-end/ScriptsPanel.js @@ -343,8 +343,7 @@ WebInspector.ScriptsPanel.prototype = { WebInspector.breakpointManager.setBreakpoint(sourceID, breakpoint.url, newLine, breakpoint.enabled, breakpoint.condition); } }; - var callbackId = WebInspector.Callback.wrap(mycallback.bind(this)) - InspectorBackend.editScriptSource(callbackId, sourceID, newContent); + InspectorBackend.editScriptSource(sourceID, newContent, mycallback.bind(this)); }, selectedCallFrameId: function() diff --git a/WebCore/inspector/front-end/Settings.js b/WebCore/inspector/front-end/Settings.js index 33a1b91..41d82f9 100644 --- a/WebCore/inspector/front-end/Settings.js +++ b/WebCore/inspector/front-end/Settings.js @@ -81,10 +81,10 @@ WebInspector.Settings.initialize = function() WebInspector.sessionSettings.dispatchEventToListeners("loaded"); } - InspectorBackend.getSettings(WebInspector.Callback.wrap(function(settings) { + InspectorBackend.getSettings(function(settings) { populateApplicationSettings(settings.application); populateSessionSettings(settings.session); - })); + }); } WebInspector.Settings.prototype = { diff --git a/WebCore/inspector/front-end/SourceCSSTokenizer.re2js b/WebCore/inspector/front-end/SourceCSSTokenizer.re2js index b4d3eef..f4628d2 100644 --- a/WebCore/inspector/front-end/SourceCSSTokenizer.re2js +++ b/WebCore/inspector/front-end/SourceCSSTokenizer.re2js @@ -48,7 +48,7 @@ WebInspector.SourceCSSTokenizer = function() this._valueKeywords = [ "above", "absolute", "activeborder", "activecaption", "afar", "after-white-space", "ahead", "alias", "all", "all-scroll", - "alternate", "always","amharic", "amharic-abegede", "antialiased", "appworkspace", "aqua", "arabic-indic", "armenian", + "alternate", "always","amharic", "amharic-abegede", "antialiased", "appworkspace", "aqua", "arabic-indic", "armenian", "asterisks", "auto", "avoid", "background", "backwards", "baseline", "below", "bidi-override", "binary", "bengali", "black", "blink", "block", "block-axis", "blue", "bold", "bolder", "border", "border-box", "both", "bottom", "break-all", "break-word", "button", "button-bevel", "buttonface", "buttonhighlight", "buttonshadow", "buttontext", "cambodian", "capitalize", "caps-lock-indicator", @@ -61,7 +61,7 @@ WebInspector.SourceCSSTokenizer = function() "ethiopic-abegede-ti-er", "ethiopic-abegede-ti-et", "ethiopic-halehame-aa-er", "ethiopic-halehame-aa-et", "ethiopic-halehame-am-et", "ethiopic-halehame-gez", "ethiopic-halehame-om-et", "ethiopic-halehame-sid-et", "ethiopic-halehame-so-et", "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig", "ew-resize", "expanded", - "extra-condensed", "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "forwards", "from", "fuchsia", "geometricPrecision", + "extra-condensed", "extra-expanded", "fantasy", "fast", "fill", "fixed", "flat", "footnotes", "forwards", "from", "fuchsia", "geometricPrecision", "georgian", "gray", "graytext", "green", "grey", "groove", "gujarati", "gurmukhi", "hand", "hangul", "hangul-consonant", "hebrew", "help", "hidden", "hide", "higher", "highlight", "highlighttext", "hiragana", "hiragana-iroha", "horizontal", "hsl", "hsla", "icon", "ignore", "inactiveborder", "inactivecaption", "inactivecaptiontext", "infinite", "infobackground", "infotext", "inherit", "initial", "inline", diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc index 4901857..b640936 100644 --- a/WebCore/inspector/front-end/WebKit.qrc +++ b/WebCore/inspector/front-end/WebKit.qrc @@ -4,6 +4,7 @@ <file>AbstractTimelinePanel.js</file> <file>ApplicationCacheItemsView.js</file> <file>AuditCategories.js</file> + <file>AuditFormatters.js</file> <file>AuditLauncherView.js</file> <file>AuditResultView.js</file> <file>AuditRules.js</file> @@ -35,11 +36,14 @@ <file>ElementsTreeOutline.js</file> <file>EventListenersSidebarPane.js</file> <file>ExtensionAPI.js</file> + <file>ExtensionAuditCategory.js</file> + <file>ExtensionCommon.js</file> <file>ExtensionPanel.js</file> <file>ExtensionRegistryStub.js</file> <file>ExtensionServer.js</file> <file>FontView.js</file> <file>HAREntry.js</file> + <file>HeapSnapshotView.js</file> <file>HelpScreen.js</file> <file>ImageView.js</file> <file>InjectedFakeWorker.js</file> diff --git a/WebCore/inspector/front-end/inspector.css b/WebCore/inspector/front-end/inspector.css index 4319816..a3ffa44 100644 --- a/WebCore/inspector/front-end/inspector.css +++ b/WebCore/inspector/front-end/inspector.css @@ -3910,6 +3910,115 @@ button.enable-toggle-status-bar-item .glyph { -webkit-mask-image: url(Images/reloadButtonGlyph.png); } +/* Heap Snapshot View Styles */ + +/* FIXME: move to a separate css file */ +.heap-snapshot-sidebar-tree-item .icon { + content: url(Images/profileIcon.png); +} + +.heap-snapshot-sidebar-tree-item.small .icon { + content: url(Images/profileSmallIcon.png); +} + +.heap-snapshot-view { + display: none; + overflow: hidden; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.heap-snapshot-view.visible { + display: block; +} + +.heap-snapshot-view .data-grid { + border: none; + max-height: 100%; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 93px; +} + +.heap-snapshot-view .data-grid th.count-column { + text-align: center; +} + +.heap-snapshot-view .data-grid td.count-column { + text-align: right; +} + +.heap-snapshot-view .data-grid th.size-column { + text-align: center; +} + +.heap-snapshot-view .data-grid td.size-column { + text-align: right; +} + +.heap-snapshot-view .data-grid th.countDelta-column { + text-align: center; +} + +.heap-snapshot-view .data-grid td.countDelta-column { + text-align: right; +} + +.heap-snapshot-view .data-grid th.sizeDelta-column { + text-align: center; +} + +.heap-snapshot-view .data-grid td.sizeDelta-column { + text-align: right; +} + +#heap-snapshot-summary-container { + position: absolute; + padding-top: 20px; + bottom: 0; + left: 0; + right: 0; + height: 93px; + margin-left: -1px; + border-left: 1px solid rgb(102, 102, 102); + background-color: rgb(101, 111, 130); + background-image: -webkit-gradient(linear, left top, left bottom, from(rgba(0, 0, 0, 0.5)), to(rgba(0, 0, 0, 0))); + background-repeat: repeat-x; + background-position: top; + text-align: center; + text-shadow: black 0 1px 1px; + white-space: nowrap; + color: white; + -webkit-background-size: 1px 6px; + -webkit-background-origin: padding; + -webkit-background-clip: padding; +} + +.heap-snapshot-summary { + display: inline-block; + width: 50%; + min-width: 300px; + position: relative; +} + +.heap-snapshot-summary canvas.summary-graph { + width: 225px; +} + +.heap-snapshot-summary-label { + font-size: 12px; + font-weight: bold; + position: absolute; + top: 1px; + width: 50%; + left: 25%; +} + .delete-storage-status-bar-item .glyph { -webkit-mask-image: url(Images/excludeButtonGlyph.png); } diff --git a/WebCore/inspector/front-end/inspector.html b/WebCore/inspector/front-end/inspector.html index 14e2cdc..3e4b6c1 100644 --- a/WebCore/inspector/front-end/inspector.html +++ b/WebCore/inspector/front-end/inspector.html @@ -98,6 +98,8 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="ProfilesPanel.js"></script> <script type="text/javascript" src="ConsolePanel.js"></script> <script type="text/javascript" src="ExtensionAPI.js"></script> + <script type="text/javascript" src="ExtensionAuditCategory.js"></script> + <script type="text/javascript" src="ExtensionCommon.js"></script> <script type="text/javascript" src="ExtensionServer.js"></script> <script type="text/javascript" src="ExtensionPanel.js"></script> <script type="text/javascript" src="AuditsPanel.js"></script> @@ -105,6 +107,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="AuditLauncherView.js"></script> <script type="text/javascript" src="AuditRules.js"></script> <script type="text/javascript" src="AuditCategories.js"></script> + <script type="text/javascript" src="AuditFormatters.js"></script> <script type="text/javascript" src="ResourceView.js"></script> <script type="text/javascript" src="SourceFrame.js"></script> <script type="text/javascript" src="DOMSyntaxHighlighter.js"></script> @@ -125,6 +128,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="BottomUpProfileDataGridTree.js"></script> <script type="text/javascript" src="TopDownProfileDataGridTree.js"></script> <script type="text/javascript" src="ProfileView.js"></script> + <script type="text/javascript" src="HeapSnapshotView.js"></script> <script type="text/javascript" src="DOMAgent.js"></script> <script type="text/javascript" src="InjectedScript.js"></script> <script type="text/javascript" src="InjectedScriptAccess.js"></script> diff --git a/WebCore/inspector/front-end/inspector.js b/WebCore/inspector/front-end/inspector.js index db89e20..0bff335 100644 --- a/WebCore/inspector/front-end/inspector.js +++ b/WebCore/inspector/front-end/inspector.js @@ -233,6 +233,8 @@ var WebInspector = { if (hiddenPanels.indexOf("profiles") === -1) { this.panels.profiles = new WebInspector.ProfilesPanel(); this.panels.profiles.registerProfileType(new WebInspector.CPUProfileType()); + if (Preferences.heapProfilerPresent) + this.panels.profiles.registerProfileType(new WebInspector.HeapSnapshotProfileType()); } if (hiddenPanels.indexOf("storage") === -1 && hiddenPanels.indexOf("databases") === -1) this.panels.storage = new WebInspector.StoragePanel(); @@ -583,7 +585,7 @@ WebInspector.doLoadedDone = function() InspectorBackend.populateScriptObjects(); // As a DOMAgent method, this needs to happen after the frontend has loaded and the agent is available. - InspectorBackend.getSupportedCSSProperties(WebInspector.Callback.wrap(WebInspector.CSSCompletions._load)); + InspectorBackend.getSupportedCSSProperties(WebInspector.CSSCompletions._load); } WebInspector.addPanelToolbarIcon = function(toolbarElement, panel, previousToolbarItem) @@ -632,27 +634,29 @@ WebInspector.dispatch = function(message) { WebInspector_syncDispatch = function(message) { var messageObject = (typeof message === "string") ? JSON.parse(message) : message; - if (messageObject.type === "response" && !messageObject.success) { - WebInspector.removeResponseCallbackEntry(messageObject.seq) - WebInspector.reportProtocolError(messageObject); - return; - } var arguments = []; if (messageObject.data) for (var key in messageObject.data) arguments.push(messageObject.data[key]); + if ("seq" in messageObject) { // just a response for some request + if (messageObject.success) + WebInspector.processResponse(messageObject.seq, arguments); + else { + WebInspector.removeResponseCallbackEntry(messageObject.seq) + WebInspector.reportProtocolError(messageObject); + } + return; + } + if (messageObject.type === "event") { - if (!messageObject.event in WebInspector) { - console.error("Attempted to dispatch unimplemented WebInspector method: %s", messageObject.event); + if (!(messageObject.event in WebInspector)) { + console.error("Protocol Error: Attempted to dispatch an unimplemented WebInspector method '%s'", messageObject.event); return; } WebInspector[messageObject.event].apply(WebInspector, arguments); } - - if (messageObject.type === "response") - WebInspector.processResponse(messageObject.seq, arguments); } WebInspector.dispatchMessageFromBackend = function(messageObject) @@ -662,7 +666,7 @@ WebInspector.dispatchMessageFromBackend = function(messageObject) WebInspector.reportProtocolError = function(messageObject) { - console.error("Error: InspectorBackend." + messageObject.command + " failed."); + console.error("Protocol Error: InspectorBackend request with seq = %d failed.", messageObject.seq); for (var error in messageObject.errors) console.error(" " + error); WebInspector.removeResponseCallbackEntry(messageObject.seq); @@ -1444,6 +1448,7 @@ WebInspector.failedToParseScriptSource = function(sourceURL, source, startingLin WebInspector.pausedScript = function(callFrames) { this.panels.scripts.debuggerPaused(callFrames); + InspectorFrontendHost.bringToFront(); } WebInspector.resumedScript = function() diff --git a/WebCore/inspector/front-end/utilities.js b/WebCore/inspector/front-end/utilities.js index 66cf284..e8adff6 100644 --- a/WebCore/inspector/front-end/utilities.js +++ b/WebCore/inspector/front-end/utilities.js @@ -732,12 +732,6 @@ Array.convert = function(list) function insertionIndexForObjectInListSortedByFunction(anObject, aList, aFunction) { - // indexOf returns (-lowerBound - 1). Taking (-result - 1) works out to lowerBound. - return (-indexOfObjectInListSortedByFunction(anObject, aList, aFunction) - 1); -} - -function indexOfObjectInListSortedByFunction(anObject, aList, aFunction) -{ var first = 0; var last = aList.length - 1; var floor = Math.floor; @@ -760,9 +754,7 @@ function indexOfObjectInListSortedByFunction(anObject, aList, aFunction) } } - // By returning 1 less than the negative lower search bound, we can reuse this function - // for both indexOf and insertionIndexFor, with some simple arithmetic. - return (-first - 1); + return first; } String.sprintf = function(format) |