diff options
Diffstat (limited to 'WebCore/inspector')
65 files changed, 2476 insertions, 1527 deletions
diff --git a/WebCore/inspector/CodeGeneratorInspector.pm b/WebCore/inspector/CodeGeneratorInspector.pm index 550b5b4..177ca3b 100644 --- a/WebCore/inspector/CodeGeneratorInspector.pm +++ b/WebCore/inspector/CodeGeneratorInspector.pm @@ -92,6 +92,7 @@ $typeTransform{"Value"} = { $typeTransform{"String"} = { "param" => "const String&", "variable" => "String", + "return" => "String", "defaultValue" => "\"\"", "forwardHeader" => "wtf/Forward.h", "header" => "PlatformString.h", @@ -266,6 +267,12 @@ sub generateFunctions push(@backendMethodsImpl, generateBackendDispatcher()); push(@backendMethodsImpl, generateBackendReportProtocolError()); + foreach my $type (keys %backendTypes) { + if ($typeTransform{$type}{"JSONType"}) { + push(@backendMethodsImpl, generateArgumentGetters($type)); + } + } + @backendStubJS = generateBackendStubJS($interface); } @@ -301,6 +308,14 @@ sub generateFrontendFunction } } +sub camelCase +{ + my $value = shift; + $value =~ s/\b(\w)/\U$1/g; # make a camel-case name for type name + $value =~ s/ //g; + return $value; +} + sub generateBackendFunction { my $function = shift; @@ -332,43 +347,31 @@ sub generateBackendFunction push(@function, " protocolErrors->pushString(\"Protocol Error: $domain handler is not available.\");"); push(@function, ""); - if (scalar(@inArgs)) { - # declare variables for all 'in' args; - push(@function, map(" " . $typeTransform{$_->type}->{"variable"} . " " . $_->name . " = " . $typeTransform{$_->type}->{"defaultValue"} . ";", @inArgs)); + # declare local variables for out arguments. + push(@function, map(" " . $typeTransform{$_->type}->{"variable"} . " " . $_->name . " = " . $typeTransform{$_->type}->{"defaultValue"} . ";", @outArgs)); - push(@function, ""); - push(@function, " RefPtr<InspectorObject> argumentsContainer;"); - push(@function, " if (!(argumentsContainer = requestMessageObject->getObject(\"arguments\"))) {"); - push(@function, " protocolErrors->pushString(\"Protocol Error: 'arguments' property with type 'object' was not found.\");"); - push(@function, " } else {"); - push(@function, " InspectorObject::const_iterator argumentsEndIterator = argumentsContainer->end();"); + my $indent = ""; + if (scalar(@inArgs)) { + push(@function, " if (RefPtr<InspectorObject> argumentsContainer = requestMessageObject->getObject(\"arguments\")) {"); foreach my $parameter (@inArgs) { my $name = $parameter->name; my $type = $parameter->type; - my $variableType = $typeTransform{$type}->{"variable"}; - my $JSONType = $typeTransform{$type}->{"JSONType"}; - - push(@function, ""); - push(@function, " InspectorObject::const_iterator ${name}ValueIterator = argumentsContainer->find(\"$name\");"); - push(@function, " if (${name}ValueIterator == argumentsEndIterator) {"); - push(@function, " protocolErrors->pushString(\"Protocol Error: Argument '$name' with type '$JSONType' was not found.\");"); - push(@function, " } else {"); - push(@function, " if (!${name}ValueIterator->second->as$JSONType(&$name)) {"); - push(@function, " protocolErrors->pushString(\"Protocol Error: Argument '$name' has wrong type. It should be '$JSONType'.\");"); - push(@function, " }"); - push(@function, " }"); + my $typeString = camelCase($parameter->type); + push(@function, " " . $typeTransform{$type}->{"variable"} . " $name = get$typeString(argumentsContainer.get(), \"$name\", protocolErrors.get());"); } - push(@function, " }"); + push(@function, ""); + $indent = " "; } - # declare local variables for out arguments. - push(@function, map(" " . $typeTransform{$_->type}->{"variable"} . " " . $_->name . " = " . $typeTransform{$_->type}->{"defaultValue"} . ";", @outArgs)); - my $args = join(", ", (map($_->name, @inArgs), map("&" . $_->name, @outArgs))); - push(@function, " if (!protocolErrors->length())"); - push(@function, " $domainAccessor->$functionName($args);"); - push(@function, ""); + push(@function, "$indent if (!protocolErrors->length())"); + push(@function, "$indent $domainAccessor->$functionName($args);"); + if (scalar(@inArgs)) { + push(@function, " } else {"); + push(@function, " protocolErrors->pushString(\"Protocol Error: 'arguments' property with type 'object' was not found.\");"); + push(@function, " }"); + } push(@function, " // use InspectorFrontend as a marker of WebInspector availability"); push(@function, " if ((callId || protocolErrors->length()) && m_inspectorController->hasFrontend()) {"); @@ -412,6 +415,39 @@ EOF return split("\n", $reportProtocolError); } +sub generateArgumentGetters +{ + my $type = shift; + my $json = $typeTransform{$type}{"JSONType"}; + my $variable = $typeTransform{$type}{"variable"}; + my $defaultValue = $typeTransform{$type}{"defaultValue"}; + my $return = $typeTransform{$type}{"return"} ? $typeTransform{$type}{"return"} : $typeTransform{$type}{"param"}; + + my $typeString = camelCase($type); + push(@backendConstantDeclarations, "$return get$typeString(InspectorObject* object, const String& name, InspectorArray* protocolErrors);"); + my $getterBody = << "EOF"; + +$return InspectorBackendDispatcher::get$typeString(InspectorObject* object, const String& name, InspectorArray* protocolErrors) +{ + ASSERT(object); + ASSERT(protocolErrors); + + $variable value = $defaultValue; + InspectorObject::const_iterator end = object->end(); + InspectorObject::const_iterator valueIterator = object->find(name); + + if (valueIterator == end) + protocolErrors->pushString(String::format("Protocol Error: Argument '\%s' with type '$json' was not found.", name.utf8().data())); + else { + if (!valueIterator->second->as$json(&value)) + protocolErrors->pushString(String::format("Protocol Error: Argument '\%s' has wrong type. It should be '$json'.", name.utf8().data())); + } + return value; +} +EOF + + return split("\n", $getterBody); +} sub generateBackendDispatcher { @@ -563,6 +599,9 @@ WebInspector.InspectorBackendStub.prototype = { request.seq = WebInspector.Callback.wrap(args[0]); } + if (window.dumpInspectorProtocolMessages) + console.log("frontend: " + JSON.stringify(request)); + var message = JSON.stringify(request); InspectorFrontendHost.sendMessageToBackend(message); } diff --git a/WebCore/inspector/ConsoleMessage.cpp b/WebCore/inspector/ConsoleMessage.cpp index a5e9ec6..f1534df 100644 --- a/WebCore/inspector/ConsoleMessage.cpp +++ b/WebCore/inspector/ConsoleMessage.cpp @@ -40,7 +40,6 @@ #include "ScriptArguments.h" #include "ScriptCallStack.h" #include "ScriptValue.h" -#include <wtf/PassOwnPtr.h> namespace WebCore { @@ -56,7 +55,7 @@ ConsoleMessage::ConsoleMessage(MessageSource s, MessageType t, MessageLevel l, c { } -ConsoleMessage::ConsoleMessage(MessageSource s, MessageType t, MessageLevel l, const String& m, PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack, unsigned g) +ConsoleMessage::ConsoleMessage(MessageSource s, MessageType t, MessageLevel l, const String& m, PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack, unsigned g) : m_source(s) , m_type(t) , m_level(l) diff --git a/WebCore/inspector/ConsoleMessage.h b/WebCore/inspector/ConsoleMessage.h index 4e88bec..351c584 100644 --- a/WebCore/inspector/ConsoleMessage.h +++ b/WebCore/inspector/ConsoleMessage.h @@ -49,7 +49,7 @@ class ScriptValue; class ConsoleMessage : public Noncopyable { public: ConsoleMessage(MessageSource, MessageType, MessageLevel, const String& m, unsigned li, const String& u, unsigned g); - ConsoleMessage(MessageSource, MessageType, MessageLevel, const String& m, PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack>, unsigned g); + ConsoleMessage(MessageSource, MessageType, MessageLevel, const String& m, PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack>, unsigned g); void addToFrontend(InspectorFrontend*, InjectedScriptHost*); void updateRepeatCountInConsole(InspectorFrontend* frontend); @@ -64,8 +64,8 @@ private: MessageType m_type; MessageLevel m_level; String m_message; - OwnPtr<ScriptArguments> m_arguments; - OwnPtr<ScriptCallStack> m_callStack; + RefPtr<ScriptArguments> m_arguments; + RefPtr<ScriptCallStack> m_callStack; unsigned m_line; String m_url; unsigned m_groupLevel; diff --git a/WebCore/inspector/InjectedScriptHost.idl b/WebCore/inspector/InjectedScriptHost.idl index 9b2ed6c..5fb57b4 100644 --- a/WebCore/inspector/InjectedScriptHost.idl +++ b/WebCore/inspector/InjectedScriptHost.idl @@ -38,6 +38,7 @@ module core { [Custom] DOMObject nodeForId(in long nodeId); [Custom] int pushNodePathToFrontend(in DOMObject node, in boolean withChildren, in boolean selectInUI); long inspectedNode(in unsigned long num); + [Custom] DOMObject internalConstructorName(in DOMObject object); #if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER [Custom] DOMObject currentCallFrame(); diff --git a/WebCore/inspector/Inspector.idl b/WebCore/inspector/Inspector.idl index 29a3ba0..c185d2d 100644 --- a/WebCore/inspector/Inspector.idl +++ b/WebCore/inspector/Inspector.idl @@ -58,10 +58,12 @@ module core { #if defined(ENABLE_JAVASCRIPT_DEBUGGER) && ENABLE_JAVASCRIPT_DEBUGGER [notify] void addProfileHeader(out Object header); + [notify] void addHeapSnapshotChunk(out unsigned long uid, out String chunk); [notify] void attachDebuggerWhenShown(); [notify] void debuggerWasEnabled(); [notify] void debuggerWasDisabled(); [notify] void failedToParseScriptSource(out String url, out String data, out int firstLine, out int errorLine, out String errorMessage); + [notify] void finishHeapSnapshot(out unsigned long uid); [notify] void parsedScriptSource(out String sourceID, out String url, out String data, out int firstLine, out int scriptWorldType); [notify] void pausedScript(out Object details); [notify] void profilerWasEnabled(); @@ -113,7 +115,7 @@ module core { [notify] void didFinishLoading(out long identifier, out double finishTime); [notify] void didFailLoading(out long identifier, out double time, out String localizedDescription); [notify] void didLoadResourceFromMemoryCache(out double time, out Object resource); - [notify] void setOverrideContent(out long identifier, out String sourceString, out String type); + [notify] void setInitialContent(out long identifier, out String sourceString, out String type); [notify] void didCommitLoadForFrame(out Object frame, out Object loader); [notify] void frameDetachedFromParent(out unsigned long frameId); @@ -213,10 +215,11 @@ module core { [handler=CSS] void getInlineStyleForNode2(in long nodeId, out Value style); [handler=CSS] void getAllStyles2(out Array styleSheetIds); [handler=CSS] void getStyleSheet2(in String styleSheetId, out Value styleSheet); - [handler=CSS] void setStyleSheetText2(in String styleSheetId, in String text); - [handler=CSS] void setPropertyText2(in String styleId, in long propertyIndex, in String text, in boolean overwrite, out Value style); - [handler=CSS] void toggleProperty2(in String styleId, in long propertyIndex, in boolean disable, out Value style); - [handler=CSS] void setRuleSelector2(in String ruleId, in String selector, out Value rule); + [handler=CSS] void getStyleSheetText2(in String styleSheetId, out String url, out String text); + [handler=CSS] void setStyleSheetText2(in String styleSheetId, in String text, out boolean success); + [handler=CSS] void setPropertyText2(in Object styleId, in long propertyIndex, in String text, in boolean overwrite, out Value style); + [handler=CSS] void toggleProperty2(in Object styleId, in long propertyIndex, in boolean disable, out Value style); + [handler=CSS] void setRuleSelector2(in Object ruleId, in String selector, out Value rule); [handler=CSS] void addRule2(in long contextNodeId, in String selector, out Value rule); [handler=CSS] void getSupportedCSSProperties(out Array cssProperties); [handler=CSS] void querySelectorAll(in long documentId, in String selector, out Array result); diff --git a/WebCore/inspector/InspectorCSSAgent.cpp b/WebCore/inspector/InspectorCSSAgent.cpp index 37bf2b3..31d951a 100644 --- a/WebCore/inspector/InspectorCSSAgent.cpp +++ b/WebCore/inspector/InspectorCSSAgent.cpp @@ -214,7 +214,7 @@ void InspectorCSSAgent::getStylesForNode2(long nodeId, RefPtr<InspectorValue>* r if (parentElement->style() && parentElement->style()->length()) { InspectorStyleSheetForInlineStyle* styleSheet = asInspectorStyleSheet(parentElement); if (styleSheet) - parentStyle->setObject("inlineStyle", styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId::createFromParts(styleSheet->id(), "0")))); + parentStyle->setObject("inlineStyle", styleSheet->buildObjectForStyle(styleSheet->styleForId(InspectorCSSId(styleSheet->id(), 0)))); } CSSStyleSelector* parentSelector = parentElement->ownerDocument()->styleSelector(); @@ -276,16 +276,29 @@ void InspectorCSSAgent::getStyleSheet2(const String& styleSheetId, RefPtr<Inspec *styleSheetObject = inspectorStyleSheet->buildObjectForStyleSheet(); } -void InspectorCSSAgent::setStyleSheetText2(const String& styleSheetId, const String& text) +void InspectorCSSAgent::getStyleSheetText2(const String& styleSheetId, String* url, String* result) { InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(styleSheetId); if (!inspectorStyleSheet) return; + *url = inspectorStyleSheet->finalURL(); + inspectorStyleSheet->text(result); +} + +void InspectorCSSAgent::setStyleSheetText2(const String& styleSheetId, const String& text, bool* success) +{ + InspectorStyleSheet* inspectorStyleSheet = styleSheetForId(styleSheetId); + if (!inspectorStyleSheet) { + *success = false; + return; + } - inspectorStyleSheet->setText(text); + *success = inspectorStyleSheet->setText(text); + if (*success) + inspectorStyleSheet->reparseStyleSheet(text); } -void InspectorCSSAgent::setPropertyText2(const String& fullStyleId, long propertyIndex, const String& text, bool overwrite, RefPtr<InspectorValue>* result) +void InspectorCSSAgent::setPropertyText2(const RefPtr<InspectorObject>& fullStyleId, long propertyIndex, const String& text, bool overwrite, RefPtr<InspectorValue>* result) { InspectorCSSId compoundId(fullStyleId); ASSERT(!compoundId.isEmpty()); @@ -299,7 +312,7 @@ void InspectorCSSAgent::setPropertyText2(const String& fullStyleId, long propert *result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId)); } -void InspectorCSSAgent::toggleProperty2(const String& fullStyleId, long propertyIndex, bool disable, RefPtr<InspectorValue>* result) +void InspectorCSSAgent::toggleProperty2(const RefPtr<InspectorObject>& fullStyleId, long propertyIndex, bool disable, RefPtr<InspectorValue>* result) { InspectorCSSId compoundId(fullStyleId); ASSERT(!compoundId.isEmpty()); @@ -313,7 +326,7 @@ void InspectorCSSAgent::toggleProperty2(const String& fullStyleId, long property *result = inspectorStyleSheet->buildObjectForStyle(inspectorStyleSheet->styleForId(compoundId)); } -void InspectorCSSAgent::setRuleSelector2(const String& fullRuleId, const String& selector, RefPtr<InspectorValue>* result) +void InspectorCSSAgent::setRuleSelector2(const RefPtr<InspectorObject>& fullRuleId, const String& selector, RefPtr<InspectorValue>* result) { InspectorCSSId compoundId(fullRuleId); ASSERT(!compoundId.isEmpty()); diff --git a/WebCore/inspector/InspectorCSSAgent.h b/WebCore/inspector/InspectorCSSAgent.h index 71ca580..2d2efb5 100644 --- a/WebCore/inspector/InspectorCSSAgent.h +++ b/WebCore/inspector/InspectorCSSAgent.h @@ -65,10 +65,11 @@ public: void getComputedStyleForNode2(long nodeId, RefPtr<InspectorValue>* style); void getAllStyles2(RefPtr<InspectorArray>* styles); void getStyleSheet2(const String& styleSheetId, RefPtr<InspectorValue>* result); - void setStyleSheetText2(const String& styleSheetId, const String& text); - void setPropertyText2(const String& styleId, long propertyIndex, const String& text, bool overwrite, RefPtr<InspectorValue>* result); - void toggleProperty2(const String& styleId, long propertyIndex, bool disable, RefPtr<InspectorValue>* result); - void setRuleSelector2(const String& ruleId, const String& selector, RefPtr<InspectorValue>* result); + void getStyleSheetText2(const String& styleSheetId, String* url, String* result); + void setStyleSheetText2(const String& styleSheetId, const String& text, bool* success); + void setPropertyText2(const RefPtr<InspectorObject>& styleId, long propertyIndex, const String& text, bool overwrite, RefPtr<InspectorValue>* result); + void toggleProperty2(const RefPtr<InspectorObject>& styleId, long propertyIndex, bool disable, RefPtr<InspectorValue>* result); + void setRuleSelector2(const RefPtr<InspectorObject>& ruleId, const String& selector, RefPtr<InspectorValue>* result); void addRule2(const long contextNodeId, const String& selector, RefPtr<InspectorValue>* result); void getSupportedCSSProperties(RefPtr<InspectorArray>* result); void querySelectorAll(const long nodeId, const String& selector, RefPtr<InspectorArray>* result); diff --git a/WebCore/inspector/InspectorController.cpp b/WebCore/inspector/InspectorController.cpp index c47699f..ed319f3 100644 --- a/WebCore/inspector/InspectorController.cpp +++ b/WebCore/inspector/InspectorController.cpp @@ -330,7 +330,7 @@ void InspectorController::setConsoleMessagesEnabled(bool enabled) m_consoleMessages[i]->addToFrontend(m_frontend.get(), m_injectedScriptHost.get()); } -void InspectorController::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack) +void InspectorController::addMessageToConsole(MessageSource source, MessageType type, MessageLevel level, const String& message, PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack) { if (!enabled()) return; @@ -381,7 +381,7 @@ void InspectorController::clearConsoleMessages() m_frontend->consoleMessagesCleared(); } -void InspectorController::startGroup(PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack> callStack, bool collapsed) +void InspectorController::startGroup(PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack> callStack, bool collapsed) { ++m_groupLevel; @@ -924,7 +924,7 @@ void InspectorController::resourceRetrievedByXMLHttpRequest(unsigned long identi addMessageToConsole(JSMessageSource, LogMessageType, LogMessageLevel, "XHR finished loading: \"" + url + "\".", sendLineNumber, sendURL); if (m_resourceAgent) - m_resourceAgent->setOverrideContent(identifier, sourceString, "XHR"); + m_resourceAgent->setInitialContent(identifier, sourceString, "XHR"); } void InspectorController::scriptImported(unsigned long identifier, const String& sourceString) @@ -933,7 +933,7 @@ void InspectorController::scriptImported(unsigned long identifier, const String& return; if (m_resourceAgent) - m_resourceAgent->setOverrideContent(identifier, sourceString, "Script"); + m_resourceAgent->setInitialContent(identifier, sourceString, "Script"); } void InspectorController::ensureSettingsLoaded() @@ -1537,21 +1537,18 @@ static void drawOutlinedQuad(GraphicsContext& context, const FloatQuad& quad, co // of outline (because inflating a quad is hard) { context.save(); - context.addPath(quadPath); context.clipOut(quadPath); - context.addPath(quadPath); context.setStrokeThickness(outlineThickness); context.setStrokeColor(outlineColor, ColorSpaceDeviceRGB); - context.strokePath(); + context.strokePath(quadPath); context.restore(); } // Now do the fill - context.addPath(quadPath); context.setFillColor(fillColor, ColorSpaceDeviceRGB); - context.fillPath(); + context.fillPath(quadPath); } static void drawOutlinedQuadWithClip(GraphicsContext& context, const FloatQuad& quad, const FloatQuad& clipQuad, const Color& fillColor) diff --git a/WebCore/inspector/InspectorController.h b/WebCore/inspector/InspectorController.h index ca5a9d9..5b407e0 100644 --- a/WebCore/inspector/InspectorController.h +++ b/WebCore/inspector/InspectorController.h @@ -146,7 +146,7 @@ public: void disconnectFrontend(); void setConsoleMessagesEnabled(bool enabled, bool* newState); - void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, PassOwnPtr<ScriptArguments> arguments, PassOwnPtr<ScriptCallStack>); + void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, PassRefPtr<ScriptArguments> arguments, PassRefPtr<ScriptCallStack>); void addMessageToConsole(MessageSource, MessageType, MessageLevel, const String& message, unsigned lineNumber, const String&); void clearConsoleMessages(); const Vector<OwnPtr<ConsoleMessage> >& consoleMessages() const { return m_consoleMessages; } @@ -230,7 +230,7 @@ public: void startTiming(const String& title); bool stopTiming(const String& title, double& elapsed); - void startGroup(PassOwnPtr<ScriptArguments>, PassOwnPtr<ScriptCallStack> callFrame, bool collapsed = false); + void startGroup(PassRefPtr<ScriptArguments>, PassRefPtr<ScriptCallStack> callFrame, bool collapsed = false); void endGroup(MessageSource source, unsigned lineNumber, const String& sourceURL); void markTimeline(const String& message); diff --git a/WebCore/inspector/InspectorDebuggerAgent.cpp b/WebCore/inspector/InspectorDebuggerAgent.cpp index ebd03e6..b3caa2e 100644 --- a/WebCore/inspector/InspectorDebuggerAgent.cpp +++ b/WebCore/inspector/InspectorDebuggerAgent.cpp @@ -30,7 +30,7 @@ #include "config.h" #include "InspectorDebuggerAgent.h" -#if ENABLE(JAVASCRIPT_DEBUGGER) +#if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) #include "InjectedScript.h" #include "InjectedScriptHost.h" #include "InspectorFrontend.h" @@ -335,4 +335,4 @@ void InspectorDebuggerAgent::breakProgram(DebuggerEventType type, PassRefPtr<Ins } // namespace WebCore -#endif // ENABLE(JAVASCRIPT_DEBUGGER) +#endif // ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) diff --git a/WebCore/inspector/InspectorDebuggerAgent.h b/WebCore/inspector/InspectorDebuggerAgent.h index 9501ac8..adc925a 100644 --- a/WebCore/inspector/InspectorDebuggerAgent.h +++ b/WebCore/inspector/InspectorDebuggerAgent.h @@ -30,7 +30,7 @@ #ifndef InspectorDebuggerAgent_h #define InspectorDebuggerAgent_h -#if ENABLE(JAVASCRIPT_DEBUGGER) +#if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) #include "ScriptBreakpoint.h" #include "ScriptDebugListener.h" #include "ScriptState.h" @@ -111,6 +111,6 @@ private: } // namespace WebCore -#endif // ENABLE(JAVASCRIPT_DEBUGGER) +#endif // ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) #endif // !defined(InspectorDebuggerAgent_h) diff --git a/WebCore/inspector/InspectorProfilerAgent.cpp b/WebCore/inspector/InspectorProfilerAgent.cpp index 3f107d6..6d5364f 100644 --- a/WebCore/inspector/InspectorProfilerAgent.cpp +++ b/WebCore/inspector/InspectorProfilerAgent.cpp @@ -30,7 +30,7 @@ #include "config.h" #include "InspectorProfilerAgent.h" -#if ENABLE(JAVASCRIPT_DEBUGGER) +#if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) #include "Console.h" #include "InspectorController.h" @@ -156,6 +156,21 @@ void InspectorProfilerAgent::getProfileHeaders(RefPtr<InspectorArray>* headers) (*headers)->pushObject(createSnapshotHeader(*it->second)); } +namespace { + +class OutputStream : public ScriptHeapSnapshot::OutputStream { +public: + OutputStream(InspectorFrontend* frontend, unsigned long uid) + : m_frontend(frontend), m_uid(uid) { } + void Write(const String& chunk) { m_frontend->addHeapSnapshotChunk(m_uid, chunk); } + void Close() { m_frontend->finishHeapSnapshot(m_uid); } +private: + InspectorFrontend* m_frontend; + unsigned long m_uid; +}; + +} // namespace + void InspectorProfilerAgent::getProfile(const String& type, unsigned uid, RefPtr<InspectorObject>* profileObject) { if (type == CPUProfileType) { @@ -167,8 +182,12 @@ void InspectorProfilerAgent::getProfile(const String& type, unsigned uid, RefPtr } 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()); + RefPtr<ScriptHeapSnapshot> snapshot = it->second; + *profileObject = createSnapshotHeader(*snapshot); + if (m_frontend) { + OutputStream stream(m_frontend, uid); + snapshot->writeJSON(&stream); + } } } } @@ -259,4 +278,4 @@ void InspectorProfilerAgent::toggleRecordButton(bool isProfiling) } // namespace WebCore -#endif // ENABLE(JAVASCRIPT_DEBUGGER) +#endif // ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) diff --git a/WebCore/inspector/InspectorProfilerAgent.h b/WebCore/inspector/InspectorProfilerAgent.h index c1f5db1..e67848d 100644 --- a/WebCore/inspector/InspectorProfilerAgent.h +++ b/WebCore/inspector/InspectorProfilerAgent.h @@ -30,7 +30,7 @@ #ifndef InspectorProfilerAgent_h #define InspectorProfilerAgent_h -#if ENABLE(JAVASCRIPT_DEBUGGER) +#if ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) #include "PlatformString.h" #include <wtf/Forward.h> @@ -92,6 +92,6 @@ private: } // namespace WebCore -#endif // ENABLE(JAVASCRIPT_DEBUGGER) +#endif // ENABLE(JAVASCRIPT_DEBUGGER) && ENABLE(INSPECTOR) #endif // !defined(InspectorProfilerAgent_h) diff --git a/WebCore/inspector/InspectorResourceAgent.cpp b/WebCore/inspector/InspectorResourceAgent.cpp index fcdebbc..9dab24a 100644 --- a/WebCore/inspector/InspectorResourceAgent.cpp +++ b/WebCore/inspector/InspectorResourceAgent.cpp @@ -193,11 +193,13 @@ static PassRefPtr<InspectorObject> buildObjectForResourceResponse(const Resource responseObject->setBoolean("wasCached", response.wasCached()); if (response.resourceLoadTiming()) responseObject->setObject("timing", buildObjectForTiming(*response.resourceLoadTiming())); - if (response.resourceRawHeaders()) { - RefPtr<InspectorObject> rawHeadersObject = InspectorObject::create(); - rawHeadersObject->setObject("requestHeaders", buildObjectForHeaders(response.resourceRawHeaders()->requestHeaders)); - rawHeadersObject->setObject("responseHeaders", buildObjectForHeaders(response.resourceRawHeaders()->responseHeaders)); - responseObject->setObject("rawHeaders", rawHeadersObject); + if (response.resourceLoadInfo()) { + RefPtr<InspectorObject> loadInfoObject = InspectorObject::create(); + loadInfoObject->setNumber("httpStatusCode", response.resourceLoadInfo()->httpStatusCode); + loadInfoObject->setString("httpStatusText", response.resourceLoadInfo()->httpStatusText); + loadInfoObject->setObject("requestHeaders", buildObjectForHeaders(response.resourceLoadInfo()->requestHeaders)); + loadInfoObject->setObject("responseHeaders", buildObjectForHeaders(response.resourceLoadInfo()->responseHeaders)); + responseObject->setObject("loadInfo", loadInfoObject); } return responseObject; } @@ -342,9 +344,9 @@ void InspectorResourceAgent::didLoadResourceFromMemoryCache(DocumentLoader* load m_frontend->didLoadResourceFromMemoryCache(currentTime(), buildObjectForCachedResource(loader, *resource)); } -void InspectorResourceAgent::setOverrideContent(unsigned long identifier, const String& sourceString, const String& type) +void InspectorResourceAgent::setInitialContent(unsigned long identifier, const String& sourceString, const String& type) { - m_frontend->setOverrideContent(identifier, sourceString, type); + m_frontend->setInitialContent(identifier, sourceString, type); } static PassRefPtr<InspectorObject> buildObjectForFrame(Frame* frame) diff --git a/WebCore/inspector/InspectorResourceAgent.h b/WebCore/inspector/InspectorResourceAgent.h index e3153bf..1e77d58 100644 --- a/WebCore/inspector/InspectorResourceAgent.h +++ b/WebCore/inspector/InspectorResourceAgent.h @@ -85,7 +85,7 @@ public: void didFinishLoading(unsigned long identifier, double finishTime); void didFailLoading(unsigned long identifier, const ResourceError&); void didLoadResourceFromMemoryCache(DocumentLoader*, const CachedResource*); - void setOverrideContent(unsigned long identifier, const String& sourceString, const String& type); + void setInitialContent(unsigned long identifier, const String& sourceString, const String& type); void didCommitLoad(DocumentLoader*); void frameDetachedFromParent(Frame*); diff --git a/WebCore/inspector/InspectorStyleSheet.cpp b/WebCore/inspector/InspectorStyleSheet.cpp index 2384795..eb1538f 100644 --- a/WebCore/inspector/InspectorStyleSheet.cpp +++ b/WebCore/inspector/InspectorStyleSheet.cpp @@ -27,6 +27,8 @@ #if ENABLE(INSPECTOR) +#include "CSSImportRule.h" +#include "CSSMediaRule.h" #include "CSSParser.h" #include "CSSPropertySourceData.h" #include "CSSRule.h" @@ -43,6 +45,7 @@ #include "InspectorValues.h" #include "Node.h" #include "StyleSheetList.h" +#include "WebKitCSSKeyframesRule.h" #include <wtf/OwnPtr.h> #include <wtf/PassOwnPtr.h> @@ -99,11 +102,40 @@ RefPtr<WebCore::CSSRuleSourceData> ParsedStyleSheet::ruleSourceDataAt(unsigned i namespace WebCore { +static PassRefPtr<CSSRuleList> asCSSRuleList(StyleBase* styleBase) +{ + if (!styleBase) + return 0; + + if (styleBase->isCSSStyleSheet()) + return CSSRuleList::create(static_cast<CSSStyleSheet*>(styleBase), true); + if (styleBase->isRule()) { + unsigned ruleType = static_cast<CSSRule*>(styleBase)->type(); + RefPtr<CSSRuleList> result = 0; + + switch (ruleType) { + case CSSRule::MEDIA_RULE: + result = static_cast<CSSMediaRule*>(styleBase)->cssRules(); + break; + case CSSRule::WEBKIT_KEYFRAMES_RULE: + result = static_cast<WebKitCSSKeyframesRule*>(styleBase)->cssRules(); + break; + case CSSRule::IMPORT_RULE: + case CSSRule::PAGE_RULE: + default: + return 0; + } + + return result.release(); + } + return 0; +} + PassRefPtr<InspectorObject> InspectorStyle::buildObjectForStyle() const { RefPtr<InspectorObject> result = InspectorObject::create(); if (!m_styleId.isEmpty()) - result->setString("styleId", m_styleId.asString()); + result->setValue("styleId", m_styleId.asInspectorValue()); RefPtr<InspectorObject> propertiesObject = InspectorObject::create(); propertiesObject->setString("width", m_style->getPropertyValue("width")); @@ -146,7 +178,9 @@ bool InspectorStyle::setPropertyText(unsigned index, const String& propertyText, p.parseDeclaration(tempMutableStyle.get(), propertyText + " -webkit-boguz-propertee: none", &sourceData); Vector<CSSPropertySourceData>& propertyData = sourceData->propertyData; unsigned propertyCount = propertyData.size(); - if (!propertyCount) + + // At least one property + the bogus property added just above should be present. + if (propertyCount < 2) return false; // Check for a proper propertyText termination (the parser could at least restore to the PROPERTY_NAME state). @@ -412,12 +446,27 @@ void InspectorStyle::populateObjectWithStyleProperties(InspectorObject* result) property->setNumber("startOffset", propertyEntry.range.start); property->setNumber("endOffset", propertyEntry.range.end); + // Parsed property overrides any property with the same name. Non-parsed property overrides + // previous non-parsed property with the same name (if any). + bool shouldInactivate = false; HashMap<String, RefPtr<InspectorObject> >::iterator activeIt = propertyNameToPreviousActiveProperty.find(name); if (activeIt != propertyNameToPreviousActiveProperty.end()) { + if (propertyEntry.parsedOk) + shouldInactivate = true; + else { + bool previousParsedOk; + bool success = activeIt->second->getBoolean("parsedOk", &previousParsedOk); + if (success && !previousParsedOk) + shouldInactivate = true; + } + } else + propertyNameToPreviousActiveProperty.set(name, property); + + if (shouldInactivate) { activeIt->second->setString("status", "inactive"); activeIt->second->setString("shorthandName", ""); + propertyNameToPreviousActiveProperty.set(name, property); } - propertyNameToPreviousActiveProperty.set(name, property); } else { property->setBoolean("implicit", m_style->isPropertyImplicit(name)); property->setString("status", "style"); @@ -529,17 +578,30 @@ InspectorStyleSheet::~InspectorStyleSheet() delete m_parsedStyleSheet; } +String InspectorStyleSheet::finalURL() const +{ + if (m_pageStyleSheet && !m_pageStyleSheet->finalURL().isEmpty()) + return m_pageStyleSheet->finalURL().string(); + return m_documentURL; +} + +void InspectorStyleSheet::reparseStyleSheet(const String& text) +{ + for (unsigned i = 0, size = m_pageStyleSheet->length(); i < size; ++i) + m_pageStyleSheet->remove(i); + m_pageStyleSheet->parseString(text, m_pageStyleSheet->useStrictParsing()); + m_pageStyleSheet->styleSheetChanged(); + m_inspectorStyles.clear(); +} + bool InspectorStyleSheet::setText(const String& text) { if (!m_parsedStyleSheet) return false; m_parsedStyleSheet->setText(text); - for (unsigned i = 0, size = m_pageStyleSheet->length(); i < size; ++i) - m_pageStyleSheet->remove(i); - m_inspectorStyles.clear(); + m_flatRules.clear(); - m_pageStyleSheet->parseString(text, m_pageStyleSheet->useStrictParsing()); return true; } @@ -584,7 +646,8 @@ CSSStyleRule* InspectorStyleSheet::addRule(const String& selector) styleSheetText += selector; styleSheetText += " {}"; - m_parsedStyleSheet->setText(styleSheetText); + // Using setText() as this operation changes the style sheet rule set. + setText(styleSheetText); return rule; } @@ -595,22 +658,9 @@ CSSStyleRule* InspectorStyleSheet::ruleForId(const InspectorCSSId& id) const return 0; ASSERT(!id.isEmpty()); - bool ok; - unsigned index = id.ordinal().toUInt(&ok); - if (!ok) - return 0; + ensureFlatRules(); + return id.ordinal() >= m_flatRules.size() ? 0 : m_flatRules.at(id.ordinal()); - unsigned currentIndex = 0; - for (unsigned i = 0, size = m_pageStyleSheet->length(); i < size; ++i) { - CSSStyleRule* rule = InspectorCSSAgent::asCSSStyleRule(m_pageStyleSheet->item(i)); - if (!rule) - continue; - if (index == currentIndex) - return rule; - - ++currentIndex; - } - return 0; } PassRefPtr<InspectorObject> InspectorStyleSheet::buildObjectForStyleSheet() @@ -621,7 +671,7 @@ PassRefPtr<InspectorObject> InspectorStyleSheet::buildObjectForStyleSheet() RefPtr<InspectorObject> result = InspectorObject::create(); result->setBoolean("disabled", styleSheet->disabled()); - result->setString("sourceURL", styleSheet->href()); + result->setString("sourceURL", finalURL()); result->setString("title", styleSheet->title()); RefPtr<CSSRuleList> cssRuleList = CSSRuleList::create(styleSheet, true); RefPtr<InspectorArray> cssRules = buildArrayForRuleList(cssRuleList.get()); @@ -647,13 +697,16 @@ PassRefPtr<InspectorObject> InspectorStyleSheet::buildObjectForRule(CSSStyleRule result->setString("selectorText", rule->selectorText()); // "sourceURL" is present only for regular rules, otherwise "origin" should be used in the frontend. if (!m_origin.length()) - result->setString("sourceURL", !styleSheet->href().isEmpty() ? styleSheet->href() : m_documentURL); + result->setString("sourceURL", finalURL()); result->setNumber("sourceLine", rule->sourceLine()); result->setString("origin", m_origin); result->setObject("style", buildObjectForStyle(rule->style())); - if (canBind()) - result->setString("ruleId", ruleId(rule).asString()); + if (canBind()) { + InspectorCSSId id(ruleId(rule)); + if (!id.isEmpty()) + result->setValue("ruleId", id.asInspectorValue()); + } RefPtr<CSSRuleSourceData> sourceData; if (ensureParsedDataReady()) @@ -674,7 +727,15 @@ PassRefPtr<InspectorObject> InspectorStyleSheet::buildObjectForStyle(CSSStyleDec if (ensureParsedDataReady()) sourceData = ruleSourceDataFor(style); - RefPtr<InspectorStyle> inspectorStyle = inspectorStyleForId(ruleOrStyleId(style)); + InspectorCSSId id = ruleOrStyleId(style); + if (id.isEmpty()) { + RefPtr<InspectorObject> bogusStyle = InspectorObject::create(); + bogusStyle->setArray("cssProperties", InspectorArray::create()); + bogusStyle->setObject("shorthandValues", InspectorObject::create()); + bogusStyle->setObject("properties", InspectorObject::create()); + return bogusStyle.release(); + } + RefPtr<InspectorStyle> inspectorStyle = inspectorStyleForId(id); RefPtr<InspectorObject> result = inspectorStyle->buildObjectForStyle(); // Style text cannot be retrieved without stylesheet, so set cssText here. @@ -715,6 +776,14 @@ bool InspectorStyleSheet::toggleProperty(const InspectorCSSId& id, unsigned prop return success; } +bool InspectorStyleSheet::text(String* result) const +{ + if (!ensureText()) + return false; + *result = m_parsedStyleSheet->text(); + return true; +} + CSSStyleDeclaration* InspectorStyleSheet::styleForId(const InspectorCSSId& id) const { CSSStyleRule* rule = ruleForId(id); @@ -752,55 +821,10 @@ InspectorCSSId InspectorStyleSheet::ruleOrStyleId(CSSStyleDeclaration* style) co { unsigned index = ruleIndexByStyle(style); if (index != UINT_MAX) - return InspectorCSSId::createFromParts(id(), String::number(index)); + return InspectorCSSId(id(), index); return InspectorCSSId(); } -void InspectorStyleSheet::fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData, const String& styleSheetText) -{ - Vector<CSSPropertySourceData>& propertyData = ruleData->styleSourceData->propertyData; - unsigned size = propertyData.size(); - if (!size) - return; - - unsigned styleStart = ruleData->styleSourceData->styleBodyRange.start; - const UChar* characters = styleSheetText.characters(); - CSSPropertySourceData* nextData = &(propertyData.at(0)); - for (unsigned i = 0; i < size; ++i) { - CSSPropertySourceData* currentData = nextData; - nextData = i < size - 1 ? &(propertyData.at(i + 1)) : 0; - - if (currentData->parsedOk) - continue; - if (currentData->range.end > 0 && characters[styleStart + currentData->range.end - 1] == ';') - continue; - - unsigned propertyEndInStyleSheet; - if (!nextData) - propertyEndInStyleSheet = ruleData->styleSourceData->styleBodyRange.end - 1; - else - propertyEndInStyleSheet = styleStart + nextData->range.start - 1; - - while (isHTMLSpace(characters[propertyEndInStyleSheet])) - --propertyEndInStyleSheet; - - // propertyEndInStyleSheet points at the last property text character. - unsigned newPropertyEnd = propertyEndInStyleSheet - styleStart + 1; // Exclusive of the last property text character. - if (currentData->range.end != newPropertyEnd) { - currentData->range.end = newPropertyEnd; - unsigned valueStartInStyleSheet = styleStart + currentData->range.start + currentData->name.length(); - while (valueStartInStyleSheet < propertyEndInStyleSheet && characters[valueStartInStyleSheet] != ':') - ++valueStartInStyleSheet; - if (valueStartInStyleSheet < propertyEndInStyleSheet) - ++valueStartInStyleSheet; // Shift past the ':'. - while (valueStartInStyleSheet < propertyEndInStyleSheet && isHTMLSpace(characters[valueStartInStyleSheet])) - ++valueStartInStyleSheet; - // Need to exclude the trailing ';' from the property value. - currentData->value = styleSheetText.substring(valueStartInStyleSheet, propertyEndInStyleSheet - valueStartInStyleSheet + (characters[propertyEndInStyleSheet] == ';' ? 0 : 1)); - } - } -} - Document* InspectorStyleSheet::ownerDocument() const { return m_pageStyleSheet->document(); @@ -813,12 +837,10 @@ RefPtr<CSSRuleSourceData> InspectorStyleSheet::ruleSourceDataFor(CSSStyleDeclara unsigned InspectorStyleSheet::ruleIndexByStyle(CSSStyleDeclaration* pageStyle) const { + ensureFlatRules(); unsigned index = 0; - for (unsigned i = 0, size = m_pageStyleSheet->length(); i < size; ++i) { - CSSStyleRule* rule = InspectorCSSAgent::asCSSStyleRule(m_pageStyleSheet->item(i)); - if (!rule) - continue; - if (rule->style() == pageStyle) + for (unsigned i = 0, size = m_flatRules.size(); i < size; ++i) { + if (m_flatRules.at(i)->style() == pageStyle) return index; ++index; @@ -828,15 +850,7 @@ unsigned InspectorStyleSheet::ruleIndexByStyle(CSSStyleDeclaration* pageStyle) c bool InspectorStyleSheet::ensureParsedDataReady() { - return ensureText() && ensureSourceData(pageStyleSheet()->ownerNode()); -} - -bool InspectorStyleSheet::text(String* result) const -{ - if (!ensureText()) - return false; - *result = m_parsedStyleSheet->text(); - return true; + return ensureText() && ensureSourceData(); } bool InspectorStyleSheet::ensureText() const @@ -850,11 +864,12 @@ bool InspectorStyleSheet::ensureText() const bool success = originalStyleSheetText(&text); if (success) m_parsedStyleSheet->setText(text); + // No need to clear m_flatRules here - it's empty. return success; } -bool InspectorStyleSheet::ensureSourceData(Node* ownerNode) +bool InspectorStyleSheet::ensureSourceData() { if (m_parsedStyleSheet->hasSourceData()) return true; @@ -862,17 +877,17 @@ bool InspectorStyleSheet::ensureSourceData(Node* ownerNode) if (!m_parsedStyleSheet->hasText()) return false; - RefPtr<CSSStyleSheet> newStyleSheet = CSSStyleSheet::create(ownerNode); + RefPtr<CSSStyleSheet> newStyleSheet = CSSStyleSheet::create(); CSSParser p; StyleRuleRangeMap ruleRangeMap; p.parseSheet(newStyleSheet.get(), m_parsedStyleSheet->text(), 0, &ruleRangeMap); OwnPtr<ParsedStyleSheet::SourceData> rangesVector(new ParsedStyleSheet::SourceData()); - for (unsigned i = 0, length = newStyleSheet->length(); i < length; ++i) { - CSSStyleRule* rule = InspectorCSSAgent::asCSSStyleRule(newStyleSheet->item(i)); - if (!rule) - continue; - StyleRuleRangeMap::iterator it = ruleRangeMap.find(rule); + Vector<CSSStyleRule*> rules; + RefPtr<CSSRuleList> ruleList = asCSSRuleList(newStyleSheet.get()); + collectFlatRules(ruleList, &rules); + for (unsigned i = 0, size = rules.size(); i < size; ++i) { + StyleRuleRangeMap::iterator it = ruleRangeMap.find(rules.at(i)); if (it != ruleRangeMap.end()) { fixUnparsedPropertyRanges(it->second.get(), m_parsedStyleSheet->text()); rangesVector->append(it->second); @@ -883,6 +898,13 @@ bool InspectorStyleSheet::ensureSourceData(Node* ownerNode) return m_parsedStyleSheet->hasSourceData(); } +void InspectorStyleSheet::ensureFlatRules() const +{ + // We are fine with redoing this for empty stylesheets as this will run fast. + if (m_flatRules.isEmpty()) + collectFlatRules(asCSSRuleList(pageStyleSheet()), &m_flatRules); +} + bool InspectorStyleSheet::setStyleText(CSSStyleDeclaration* style, const String& text) { if (!pageStyleSheet()) @@ -928,18 +950,6 @@ bool InspectorStyleSheet::styleSheetTextWithChangedStyle(CSSStyleDeclaration* st return true; } -CSSStyleRule* InspectorStyleSheet::findPageRuleWithStyle(CSSStyleDeclaration* style) -{ - for (unsigned i = 0, size = m_pageStyleSheet->length(); i < size; ++i) { - CSSStyleRule* rule = InspectorCSSAgent::asCSSStyleRule(m_pageStyleSheet->item(i)); - if (!rule) - continue; - if (rule->style() == style) - return rule; - } - return 0; -} - InspectorCSSId InspectorStyleSheet::ruleId(CSSStyleRule* rule) const { return ruleOrStyleId(rule->style()); @@ -951,12 +961,9 @@ void InspectorStyleSheet::revalidateStyle(CSSStyleDeclaration* pageStyle) return; m_isRevalidating = true; - CSSStyleSheet* parsedSheet = m_parsedStyleSheet->cssStyleSheet(); - for (unsigned i = 0, size = parsedSheet->length(); i < size; ++i) { - StyleBase* styleBase = parsedSheet->item(i); - CSSStyleRule* parsedRule = InspectorCSSAgent::asCSSStyleRule(styleBase); - if (!parsedRule) - continue; + ensureFlatRules(); + for (unsigned i = 0, size = m_flatRules.size(); i < size; ++i) { + CSSStyleRule* parsedRule = m_flatRules.at(i); if (parsedRule->style() == pageStyle) { if (parsedRule->style()->cssText() != pageStyle->cssText()) { // Clear the disabled properties for the invalid style here. @@ -982,6 +989,9 @@ bool InspectorStyleSheet::originalStyleSheetText(String* result) const bool InspectorStyleSheet::resourceStyleSheetText(String* result) const { + if (m_origin == "user" || m_origin == "user-agent") + return false; + if (!m_pageStyleSheet || !ownerDocument()) return false; @@ -1009,16 +1019,78 @@ PassRefPtr<InspectorArray> InspectorStyleSheet::buildArrayForRuleList(CSSRuleLis if (!ruleList) return result.release(); - for (unsigned i = 0, size = ruleList->length(); i < size; ++i) { - CSSStyleRule* rule = InspectorCSSAgent::asCSSStyleRule(ruleList->item(i)); - if (!rule) + RefPtr<CSSRuleList> refRuleList = ruleList; + Vector<CSSStyleRule*> rules; + collectFlatRules(refRuleList, &rules); + + for (unsigned i = 0, size = rules.size(); i < size; ++i) + result->pushObject(buildObjectForRule(rules.at(i))); + + return result.release(); +} + +void InspectorStyleSheet::fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData, const String& styleSheetText) +{ + Vector<CSSPropertySourceData>& propertyData = ruleData->styleSourceData->propertyData; + unsigned size = propertyData.size(); + if (!size) + return; + + unsigned styleStart = ruleData->styleSourceData->styleBodyRange.start; + const UChar* characters = styleSheetText.characters(); + CSSPropertySourceData* nextData = &(propertyData.at(0)); + for (unsigned i = 0; i < size; ++i) { + CSSPropertySourceData* currentData = nextData; + nextData = i < size - 1 ? &(propertyData.at(i + 1)) : 0; + + if (currentData->parsedOk) + continue; + if (currentData->range.end > 0 && characters[styleStart + currentData->range.end - 1] == ';') continue; - result->pushObject(buildObjectForRule(rule)); + unsigned propertyEndInStyleSheet; + if (!nextData) + propertyEndInStyleSheet = ruleData->styleSourceData->styleBodyRange.end - 1; + else + propertyEndInStyleSheet = styleStart + nextData->range.start - 1; + + while (isHTMLSpace(characters[propertyEndInStyleSheet])) + --propertyEndInStyleSheet; + + // propertyEndInStyleSheet points at the last property text character. + unsigned newPropertyEnd = propertyEndInStyleSheet - styleStart + 1; // Exclusive of the last property text character. + if (currentData->range.end != newPropertyEnd) { + currentData->range.end = newPropertyEnd; + unsigned valueStartInStyleSheet = styleStart + currentData->range.start + currentData->name.length(); + while (valueStartInStyleSheet < propertyEndInStyleSheet && characters[valueStartInStyleSheet] != ':') + ++valueStartInStyleSheet; + if (valueStartInStyleSheet < propertyEndInStyleSheet) + ++valueStartInStyleSheet; // Shift past the ':'. + while (valueStartInStyleSheet < propertyEndInStyleSheet && isHTMLSpace(characters[valueStartInStyleSheet])) + ++valueStartInStyleSheet; + // Need to exclude the trailing ';' from the property value. + currentData->value = styleSheetText.substring(valueStartInStyleSheet, propertyEndInStyleSheet - valueStartInStyleSheet + (characters[propertyEndInStyleSheet] == ';' ? 0 : 1)); + } } - return result.release(); } +void InspectorStyleSheet::collectFlatRules(PassRefPtr<CSSRuleList> ruleList, Vector<CSSStyleRule*>* result) +{ + if (!ruleList) + return; + + for (unsigned i = 0, size = ruleList->length(); i < size; ++i) { + CSSRule* rule = ruleList->item(i); + CSSStyleRule* styleRule = InspectorCSSAgent::asCSSStyleRule(rule); + if (styleRule) + result->append(styleRule); + else { + RefPtr<CSSRuleList> childRuleList = asCSSRuleList(rule); + if (childRuleList) + collectFlatRules(childRuleList, result); + } + } +} InspectorStyleSheetForInlineStyle::InspectorStyleSheetForInlineStyle(const String& id, Element* element, const String& origin) : InspectorStyleSheet(id, 0, origin, "") @@ -1026,7 +1098,13 @@ InspectorStyleSheetForInlineStyle::InspectorStyleSheetForInlineStyle(const Strin , m_ruleSourceData(0) { ASSERT(element); - m_inspectorStyle = InspectorStyle::create(InspectorCSSId::createFromParts(id, "0"), inlineStyle(), this); + m_inspectorStyle = InspectorStyle::create(InspectorCSSId(id, 0), inlineStyle(), this); +} + +bool InspectorStyleSheetForInlineStyle::text(String* result) const +{ + *result = m_element->getAttribute("style"); + return true; } bool InspectorStyleSheetForInlineStyle::setStyleText(CSSStyleDeclaration* style, const String& text) @@ -1038,12 +1116,6 @@ bool InspectorStyleSheetForInlineStyle::setStyleText(CSSStyleDeclaration* style, return !ec; } -bool InspectorStyleSheetForInlineStyle::text(String* result) const -{ - *result = m_element->getAttribute("style"); - return true; -} - Document* InspectorStyleSheetForInlineStyle::ownerDocument() const { return m_element->document(); @@ -1066,7 +1138,7 @@ bool InspectorStyleSheetForInlineStyle::ensureParsedDataReady() PassRefPtr<InspectorStyle> InspectorStyleSheetForInlineStyle::inspectorStyleForId(const InspectorCSSId& id) { - ASSERT_UNUSED(id, id.ordinal() == "0"); + ASSERT_UNUSED(id, !id.ordinal()); return m_inspectorStyle; } diff --git a/WebCore/inspector/InspectorStyleSheet.h b/WebCore/inspector/InspectorStyleSheet.h index e671834..b649bed 100644 --- a/WebCore/inspector/InspectorStyleSheet.h +++ b/WebCore/inspector/InspectorStyleSheet.h @@ -51,28 +51,43 @@ class Node; class InspectorCSSId { public: - static InspectorCSSId createFromParts(const String& styleSheetId, const String& ordinal) { return InspectorCSSId(styleSheetId + ":" + ordinal); } - InspectorCSSId() { } - explicit InspectorCSSId(const String& id) + + explicit InspectorCSSId(RefPtr<InspectorObject> value) + { + if (!value->getString("styleSheetId", &m_styleSheetId)) + return; + + RefPtr<InspectorValue> ordinalValue = value->get("ordinal"); + if (!ordinalValue || !ordinalValue->asNumber(&m_ordinal)) + m_styleSheetId = ""; + } + + InspectorCSSId(const String& styleSheetId, unsigned ordinal) + : m_styleSheetId(styleSheetId) + , m_ordinal(ordinal) { - id.split(':', m_idParts); - ASSERT(m_idParts.size() == 2); } - const String& styleSheetId() const { ASSERT(m_idParts.size() == 2); return m_idParts.at(0); } - const String& ordinal() const { ASSERT(m_idParts.size() == 2); return m_idParts.at(1); } - bool isEmpty() const { return m_idParts.isEmpty(); } - String asString() const + bool isEmpty() const { return m_styleSheetId.isEmpty(); } + + const String& styleSheetId() const { return m_styleSheetId; } + unsigned ordinal() const { return m_ordinal; } + + PassRefPtr<InspectorValue> asInspectorValue() const { if (isEmpty()) - return String(); + return InspectorValue::null(); - return m_idParts.at(0) + ":" + m_idParts.at(1); + RefPtr<InspectorObject> result = InspectorObject::create(); + result->setString("styleSheetId", m_styleSheetId); + result->setNumber("ordinal", m_ordinal); + return result.release(); } private: - Vector<String> m_idParts; + String m_styleSheetId; + unsigned m_ordinal; }; struct InspectorStyleProperty { @@ -156,8 +171,10 @@ public: InspectorStyleSheet(const String& id, CSSStyleSheet* pageStyleSheet, const String& origin, const String& documentURL); virtual ~InspectorStyleSheet(); - const String& id() const { return m_id; } + String id() const { return m_id; } + String finalURL() const; CSSStyleSheet* pageStyleSheet() const { return m_pageStyleSheet; } + void reparseStyleSheet(const String&); bool setText(const String&); bool setRuleSelector(const InspectorCSSId&, const String& selector); CSSStyleRule* addRule(const String& selector); @@ -168,13 +185,12 @@ public: bool setPropertyText(const InspectorCSSId&, unsigned propertyIndex, const String& text, bool overwrite); bool toggleProperty(const InspectorCSSId&, unsigned propertyIndex, bool disable); + virtual bool text(String* result) const; virtual CSSStyleDeclaration* styleForId(const InspectorCSSId&) const; protected: bool canBind() const { return m_origin != "userAgent" && m_origin != "user"; } InspectorCSSId ruleOrStyleId(CSSStyleDeclaration* style) const; - void fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData, const String& styleSheetText); - virtual bool text(String* result) const; virtual Document* ownerDocument() const; virtual RefPtr<CSSRuleSourceData> ruleSourceDataFor(CSSStyleDeclaration* style) const; virtual unsigned ruleIndexByStyle(CSSStyleDeclaration*) const; @@ -187,10 +203,12 @@ protected: virtual bool setStyleText(CSSStyleDeclaration*, const String&); private: + static void fixUnparsedPropertyRanges(CSSRuleSourceData* ruleData, const String& styleSheetText); + static void collectFlatRules(PassRefPtr<CSSRuleList>, Vector<CSSStyleRule*>* result); bool ensureText() const; - bool ensureSourceData(Node* ownerNode); + bool ensureSourceData(); + void ensureFlatRules() const; bool styleSheetTextWithChangedStyle(CSSStyleDeclaration*, const String& newStyleText, String* result); - CSSStyleRule* findPageRuleWithStyle(CSSStyleDeclaration*); InspectorCSSId ruleId(CSSStyleRule* rule) const; InspectorCSSId styleId(CSSStyleDeclaration* style) const { return ruleOrStyleId(style); } void revalidateStyle(CSSStyleDeclaration*); @@ -199,7 +217,6 @@ private: bool inlineStyleSheetText(String* result) const; PassRefPtr<InspectorArray> buildArrayForRuleList(CSSRuleList*); - String m_id; CSSStyleSheet* m_pageStyleSheet; String m_origin; @@ -207,6 +224,7 @@ private: bool m_isRevalidating; ParsedStyleSheet* m_parsedStyleSheet; InspectorStyleMap m_inspectorStyles; + mutable Vector<CSSStyleRule*> m_flatRules; friend class InspectorStyle; }; @@ -219,10 +237,10 @@ public: } InspectorStyleSheetForInlineStyle(const String& id, Element* element, const String& origin); - virtual CSSStyleDeclaration* styleForId(const InspectorCSSId& id) const { ASSERT_UNUSED(id, id.ordinal() == "0"); return inlineStyle(); } + virtual bool text(String* result) const; + virtual CSSStyleDeclaration* styleForId(const InspectorCSSId& id) const { ASSERT_UNUSED(id, !id.ordinal()); return inlineStyle(); } protected: - virtual bool text(String* result) const; virtual Document* ownerDocument() const; virtual RefPtr<CSSRuleSourceData> ruleSourceDataFor(CSSStyleDeclaration* style) const { ASSERT_UNUSED(style, style == inlineStyle()); return m_ruleSourceData; } virtual unsigned ruleIndexByStyle(CSSStyleDeclaration*) const { return 0; } diff --git a/WebCore/inspector/ScriptArguments.cpp b/WebCore/inspector/ScriptArguments.cpp index e30e135..b0fe554 100644 --- a/WebCore/inspector/ScriptArguments.cpp +++ b/WebCore/inspector/ScriptArguments.cpp @@ -35,6 +35,11 @@ namespace WebCore { +PassRefPtr<ScriptArguments> ScriptArguments::create(ScriptState* scriptState, Vector<ScriptValue>& arguments) +{ + return adoptRef(new ScriptArguments(scriptState, arguments)); +} + ScriptArguments::ScriptArguments(ScriptState* scriptState, Vector<ScriptValue>& arguments) : m_scriptState(scriptState) { diff --git a/WebCore/inspector/ScriptArguments.h b/WebCore/inspector/ScriptArguments.h index fdf05ab..26549b6 100644 --- a/WebCore/inspector/ScriptArguments.h +++ b/WebCore/inspector/ScriptArguments.h @@ -33,15 +33,18 @@ #include "PlatformString.h" #include "ScriptState.h" +#include <wtf/Forward.h> +#include <wtf/RefCounted.h> #include <wtf/Vector.h> namespace WebCore { class ScriptValue; -class ScriptArguments { +class ScriptArguments : public RefCounted<ScriptArguments> { public: - ScriptArguments(ScriptState*, Vector<ScriptValue>& arguments); + static PassRefPtr<ScriptArguments> create(ScriptState*, Vector<ScriptValue>& arguments); + ~ScriptArguments(); const ScriptValue& argumentAt(size_t) const; @@ -53,6 +56,8 @@ public: bool isEqual(ScriptArguments*) const; private: + ScriptArguments(ScriptState*, Vector<ScriptValue>& arguments); + ScriptStateProtectedPtr m_scriptState; Vector<ScriptValue> m_arguments; }; diff --git a/WebCore/inspector/ScriptBreakpoint.h b/WebCore/inspector/ScriptBreakpoint.h index b7c7a37..d8ac762 100644 --- a/WebCore/inspector/ScriptBreakpoint.h +++ b/WebCore/inspector/ScriptBreakpoint.h @@ -54,8 +54,10 @@ struct ScriptBreakpoint { bool enabled; String condition; +#if ENABLE(INSPECTOR) static void sourceBreakpointsFromInspectorObject(PassRefPtr<InspectorObject>, SourceBreakpoints*); static PassRefPtr<InspectorObject> inspectorObjectFromSourceBreakpoints(const SourceBreakpoints&); +#endif }; } // namespace WebCore diff --git a/WebCore/inspector/ScriptCallFrame.h b/WebCore/inspector/ScriptCallFrame.h index 60d77e1..2a1f257 100644 --- a/WebCore/inspector/ScriptCallFrame.h +++ b/WebCore/inspector/ScriptCallFrame.h @@ -32,7 +32,7 @@ #define ScriptCallFrame_h #include "PlatformString.h" -#include <wtf/PassRefPtr.h> +#include <wtf/Forward.h> namespace WebCore { diff --git a/WebCore/inspector/ScriptCallStack.cpp b/WebCore/inspector/ScriptCallStack.cpp index 31ec1c1..70229e5 100644 --- a/WebCore/inspector/ScriptCallStack.cpp +++ b/WebCore/inspector/ScriptCallStack.cpp @@ -35,6 +35,11 @@ namespace WebCore { +PassRefPtr<ScriptCallStack> ScriptCallStack::create(Vector<ScriptCallFrame>& frames) +{ + return adoptRef(new ScriptCallStack(frames)); +} + ScriptCallStack::ScriptCallStack(Vector<ScriptCallFrame>& frames) { m_frames.swap(frames); @@ -44,13 +49,13 @@ ScriptCallStack::~ScriptCallStack() { } -const ScriptCallFrame &ScriptCallStack::at(size_t index) +const ScriptCallFrame &ScriptCallStack::at(size_t index) const { ASSERT(m_frames.size() > index); return m_frames[index]; } -size_t ScriptCallStack::size() +size_t ScriptCallStack::size() const { return m_frames.size(); } diff --git a/WebCore/inspector/ScriptCallStack.h b/WebCore/inspector/ScriptCallStack.h index 54c6bba..36ea670 100644 --- a/WebCore/inspector/ScriptCallStack.h +++ b/WebCore/inspector/ScriptCallStack.h @@ -32,28 +32,32 @@ #define ScriptCallStack_h #include "ScriptCallFrame.h" -#include <wtf/Noncopyable.h> +#include <wtf/Forward.h> +#include <wtf/RefCounted.h> #include <wtf/Vector.h> namespace WebCore { class InspectorArray; -class ScriptCallStack : public Noncopyable { +class ScriptCallStack : public RefCounted<ScriptCallStack> { public: static const size_t maxCallStackSizeToCapture = 200; + + static PassRefPtr<ScriptCallStack> create(Vector<ScriptCallFrame>&); - ScriptCallStack(Vector<ScriptCallFrame>&); ~ScriptCallStack(); - const ScriptCallFrame &at(size_t); - size_t size(); + const ScriptCallFrame &at(size_t) const; + size_t size() const; static bool stackTrace(int, const RefPtr<InspectorArray>&); bool isEqual(ScriptCallStack*) const; PassRefPtr<InspectorArray> buildInspectorObject() const; private: + ScriptCallStack(Vector<ScriptCallFrame>&); + Vector<ScriptCallFrame> m_frames; }; diff --git a/WebCore/inspector/front-end/AuditRules.js b/WebCore/inspector/front-end/AuditRules.js index b78bc96..cd1b34f 100644 --- a/WebCore/inspector/front-end/AuditRules.js +++ b/WebCore/inspector/front-end/AuditRules.js @@ -326,7 +326,9 @@ WebInspector.AuditRules.UnusedCssRule.prototype = { if (!unusedRules.length) continue; - var url = styleSheet.sourceURL ? WebInspector.AuditRuleResult.linkifyDisplayName(styleSheet.sourceURL) : String.sprintf("Inline block #%d", ++inlineBlockOrdinal); + var resource = WebInspector.resourceManager.resourceForURL(styleSheet.sourceURL); + var isInlineBlock = resource && resource.type == WebInspector.Resource.Type.Document; + var url = !isInlineBlock ? WebInspector.AuditRuleResult.linkifyDisplayName(styleSheet.sourceURL) : String.sprintf("Inline block #%d", ++inlineBlockOrdinal); var pctUnused = Math.round(100 * unusedStylesheetSize / stylesheetSize); if (!summary) summary = result.addChild("", true); diff --git a/WebCore/inspector/front-end/CSSStyleModel.js b/WebCore/inspector/front-end/CSSStyleModel.js index c3429fd..23ed7a8 100644 --- a/WebCore/inspector/front-end/CSSStyleModel.js +++ b/WebCore/inspector/front-end/CSSStyleModel.js @@ -117,7 +117,9 @@ WebInspector.CSSStyleModel.prototype = { function checkAffectsCallback(nodeId, successCallback, rulePayload, selectedNodeIds) { var doesAffectSelectedNode = (selectedNodeIds.indexOf(nodeId) >= 0); - successCallback(WebInspector.CSSRule.parsePayload(rulePayload), doesAffectSelectedNode); + var rule = WebInspector.CSSRule.parsePayload(rulePayload); + successCallback(rule, doesAffectSelectedNode); + this._styleSheetChanged(rule.id.styleSheetId, true); } function callback(nodeId, successCallback, failureCallback, newSelector, rulePayload) @@ -125,10 +127,10 @@ WebInspector.CSSStyleModel.prototype = { if (!rulePayload) failureCallback(); else - InspectorBackend.querySelectorAll(nodeId, newSelector, checkAffectsCallback.bind(null, nodeId, successCallback, rulePayload)); + InspectorBackend.querySelectorAll(nodeId, newSelector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload)); } - InspectorBackend.setRuleSelector2(ruleId, newSelector, callback.bind(null, nodeId, successCallback, failureCallback)); + InspectorBackend.setRuleSelector2(ruleId, newSelector, callback.bind(this, nodeId, successCallback, failureCallback)); }, addRule: function(nodeId, selector, successCallback, failureCallback) @@ -136,7 +138,9 @@ WebInspector.CSSStyleModel.prototype = { function checkAffectsCallback(nodeId, successCallback, rulePayload, selectedNodeIds) { var doesAffectSelectedNode = (selectedNodeIds.indexOf(nodeId) >= 0); - successCallback(WebInspector.CSSRule.parsePayload(rulePayload), doesAffectSelectedNode); + var rule = WebInspector.CSSRule.parsePayload(rulePayload); + successCallback(rule, doesAffectSelectedNode); + this._styleSheetChanged(rule.id.styleSheetId, true); } function callback(successCallback, failureCallback, selector, rulePayload) @@ -145,10 +149,33 @@ WebInspector.CSSStyleModel.prototype = { // Invalid syntax for a selector failureCallback(); } else - InspectorBackend.querySelectorAll(nodeId, selector, checkAffectsCallback.bind(null, nodeId, successCallback, rulePayload)); + InspectorBackend.querySelectorAll(nodeId, selector, checkAffectsCallback.bind(this, nodeId, successCallback, rulePayload)); } - InspectorBackend.addRule2(nodeId, selector, callback.bind(null, successCallback, failureCallback, selector)); + InspectorBackend.addRule2(nodeId, selector, callback.bind(this, successCallback, failureCallback, selector)); + }, + + _styleSheetChanged: function(styleSheetId, majorChange) + { + if (!majorChange || !styleSheetId) + return; + + function callback(href, content) + { + var resource = WebInspector.resourceManager.resourceForURL(href); + if (resource && resource.type === WebInspector.Resource.Type.Stylesheet) + resource.setContent(content, this._onRevert.bind(this, styleSheetId)); + } + InspectorBackend.getStyleSheetText2(styleSheetId, callback.bind(this)); + }, + + _onRevert: function(styleSheetId, contentToRevertTo) + { + function callback(success) + { + this._styleSheetChanged(styleSheetId, true); + } + InspectorBackend.setStyleSheetText2(styleSheetId, contentToRevertTo, callback.bind(this)); } } @@ -312,8 +339,10 @@ WebInspector.CSSStyleDeclaration.prototype = { if (!payload) userCallback(null); - else + else { userCallback(WebInspector.CSSStyleDeclaration.parsePayload(payload)); + WebInspector.cssModel._styleSheetChanged(this.id.styleSheetId, true); + } } InspectorBackend.setPropertyText2(this.id, index, name + ": " + value + ";", false, callback.bind(null, userCallback)); @@ -422,9 +451,9 @@ WebInspector.CSSProperty.prototype = { }, // Replaces "propertyName: propertyValue [!important];" in the stylesheet by an arbitrary propertyText. - setText: function(propertyText, userCallback) + setText: function(propertyText, majorChange, userCallback) { - function callback(userCallback, stylePayload) + function callback(stylePayload) { if (stylePayload) this.text = propertyText; @@ -436,6 +465,7 @@ WebInspector.CSSProperty.prototype = { else { var style = WebInspector.CSSStyleDeclaration.parsePayload(stylePayload); userCallback(style); + WebInspector.cssModel._styleSheetChanged(style.id.styleSheetId, majorChange); } } @@ -443,7 +473,7 @@ WebInspector.CSSProperty.prototype = { throw "No ownerStyle for property"; // An index past all the properties adds a new property to the style. - InspectorBackend.setPropertyText2(this.ownerStyle.id, this.index, propertyText, this.index < this.ownerStyle.pastLastSourcePropertyIndex(), callback.bind(this, userCallback)); + InspectorBackend.setPropertyText2(this.ownerStyle.id, this.index, propertyText, this.index < this.ownerStyle.pastLastSourcePropertyIndex(), callback.bind(this)); }, setValue: function(newValue, userCallback) @@ -459,7 +489,7 @@ WebInspector.CSSProperty.prototype = { if (disabled === this.disabled && userCallback) userCallback(this.ownerStyle); - function callback(userCallback, stylePayload) + function callback(stylePayload) { if (!userCallback) return; @@ -468,10 +498,11 @@ WebInspector.CSSProperty.prototype = { else { var style = WebInspector.CSSStyleDeclaration.parsePayload(stylePayload); userCallback(style); + WebInspector.cssModel._styleSheetChanged(this.ownerStyle.id.styleSheetId, false); } } - InspectorBackend.toggleProperty2(this.ownerStyle.id, this.index, disabled, callback.bind(this, userCallback)); + InspectorBackend.toggleProperty2(this.ownerStyle.id, this.index, disabled, callback.bind(this)); } } @@ -495,14 +526,14 @@ WebInspector.CSSStyleSheet = function(payload) WebInspector.CSSStyleSheet.createForId = function(styleSheetId, userCallback) { - function callback(userCallback, styleSheetPayload) + function callback(styleSheetPayload) { if (!styleSheetPayload) userCallback(null); else userCallback(new WebInspector.CSSStyleSheet(styleSheetPayload)); } - InspectorBackend.getStyleSheet2(styleSheetId, callback.bind(this, userCallback)); + InspectorBackend.getStyleSheet2(styleSheetId, callback.bind(this)); } WebInspector.CSSStyleSheet.prototype = { @@ -513,14 +544,16 @@ WebInspector.CSSStyleSheet.prototype = { setText: function(newText, userCallback) { - function callback(userCallback, styleSheetPayload) + function callback(styleSheetPayload) { if (!styleSheetPayload) userCallback(null); - else + else { userCallback(new WebInspector.CSSStyleSheet(styleSheetPayload)); + WebInspector.cssModel._styleSheetChanged(this.id, true); + } } - InspectorBackend.setStyleSheetText2(this.id, newText, callback.bind(this, userCallback)); + InspectorBackend.setStyleSheetText2(this.id, newText, callback.bind(this)); } } diff --git a/WebCore/inspector/front-end/Color.js b/WebCore/inspector/front-end/Color.js index 11d6bad..5e7314c 100644 --- a/WebCore/inspector/front-end/Color.js +++ b/WebCore/inspector/front-end/Color.js @@ -143,6 +143,8 @@ WebInspector.Color.prototype = { format = this.format; switch (format) { + case "original": + return this.value; case "rgb": return "rgb(" + this.rgb.join(", ") + ")"; case "rgba": @@ -324,7 +326,7 @@ WebInspector.Color.prototype = { throw "unknown color name"; } else if (match[4]) { // hsl this.format = "hsl"; - var hsl = match[4].replace(/%g/, "").split(/\s*,\s*/); + var hsl = match[4].replace(/%/g, "").split(/\s*,\s*/); this.hsl = hsl; this.rgb = this._hslToRGB(hsl); this.hex = this._rgbToHex(this.rgb); diff --git a/WebCore/inspector/front-end/CookieItemsView.js b/WebCore/inspector/front-end/CookieItemsView.js index b2da875..75c7f84 100644 --- a/WebCore/inspector/front-end/CookieItemsView.js +++ b/WebCore/inspector/front-end/CookieItemsView.js @@ -27,149 +27,19 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.CookiesTable = function() -{ - WebInspector.View.call(this); - - this.element.addStyleClass("table"); -} - -WebInspector.CookiesTable.prototype = { - resize: function() - { - if (!this._dataGrid) - return; - - if (this._autoSizingDone) - this._dataGrid.updateWidths(); - else { - this._autoSizingDone = true; - this._dataGrid.autoSizeColumns(4, 45, 1); - } - }, - - _createDataGrid: function(expandable) - { - var columns = { 0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {} }; - columns[0].title = WebInspector.UIString("Name"); - columns[0].sortable = true; - columns[0].disclosure = expandable; - columns[1].title = WebInspector.UIString("Value"); - columns[1].sortable = true; - columns[2].title = WebInspector.UIString("Domain"); - columns[2].sortable = true; - columns[3].title = WebInspector.UIString("Path"); - columns[3].sortable = true; - columns[4].title = WebInspector.UIString("Expires"); - columns[4].sortable = true; - columns[5].title = WebInspector.UIString("Size"); - columns[5].aligned = "right"; - columns[5].sortable = true; - columns[6].title = WebInspector.UIString("HTTP"); - columns[6].aligned = "centered"; - columns[6].sortable = true; - columns[7].title = WebInspector.UIString("Secure"); - columns[7].aligned = "centered"; - columns[7].sortable = true; - - var deleteCallback = this._deleteCookieCallback ? this._deleteCookieCallback.bind(this) : null; - this._dataGrid = new WebInspector.DataGrid(columns, null, deleteCallback); - this._dataGrid.addEventListener("sorting changed", this._populateDataGrid, this); - this.element.appendChild(this._dataGrid.element); - }, - - _populateCookies: function(parentNode, cookies) - { - var selectedCookie = this._dataGrid.selectedNode ? this._dataGrid.selectedNode.cookie : null; - parentNode.removeChildren(); - if (!cookies) - return; - this._sortCookies(cookies); - var totalSize = 0; - for (var i = 0; i < cookies.length; ++i) { - var cookieNode = this._createGridNode(cookies[i]); - parentNode.appendChild(cookieNode); - if (selectedCookie === cookies[i]) - cookieNode.selected = true; - } - }, - - _sortCookies: function(cookies) - { - var sortDirection = this._dataGrid.sortOrder === "ascending" ? 1 : -1; - - function localeCompare(field, cookie1, cookie2) - { - return sortDirection * (cookie1[field] + "").localeCompare(cookie2[field] + "") - } - - function numberCompare(field, cookie1, cookie2) - { - return sortDirection * (cookie1[field] - cookie2[field]); - } - - function expiresCompare(cookie1, cookie2) - { - if (cookie1.session !== cookie2.session) - return sortDirection * (cookie1.session ? 1 : -1); - - if (cookie1.session) - return 0; - - return sortDirection * (cookie1.expires - cookie2.expires); - } - - var comparator; - switch (parseInt(this._dataGrid.sortColumnIdentifier)) { - case 0: comparator = localeCompare.bind(this, "name"); break; - case 1: comparator = localeCompare.bind(this, "value"); break; - case 2: comparator = localeCompare.bind(this, "domain"); break; - case 3: comparator = localeCompare.bind(this, "path"); break; - case 4: comparator = expiresCompare; break; - case 5: comparator = numberCompare.bind(this, "size"); break; - case 6: comparator = localeCompare.bind(this, "httpOnly"); break; - case 7: comparator = localeCompare.bind(this, "secure"); break; - default: localeCompare.bind(this, "name"); - } - - cookies.sort(comparator); - }, - - _createGridNode: function(cookie) - { - var data = {}; - data[0] = cookie.name; - data[1] = cookie.value; - data[2] = cookie.domain || ""; - data[3] = cookie.path || ""; - data[4] = cookie.type === WebInspector.Cookie.Type.Request ? "" : - (cookie.session ? WebInspector.UIString("Session") : new Date(cookie.expires).toGMTString()); - data[5] = cookie.size; - data[6] = (cookie.httpOnly ? "\u2713" : ""); // Checkmark - data[7] = (cookie.secure ? "\u2713" : ""); // Checkmark - - var node = new WebInspector.DataGridNode(data); - node.cookie = cookie; - node.selectable = true; - return node; - } -}; - -WebInspector.CookiesTable.prototype.__proto__ = WebInspector.View.prototype; - WebInspector.CookieItemsView = function(treeElement, cookieDomain) { - WebInspector.CookiesTable.call(this); + WebInspector.View.call(this); this.element.addStyleClass("storage-view"); - this.deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item"); - this.deleteButton.visible = false; - this.deleteButton.addEventListener("click", this._deleteButtonClicked.bind(this), false); + this._deleteButton = new WebInspector.StatusBarButton(WebInspector.UIString("Delete"), "delete-storage-status-bar-item"); + this._deleteButton.visible = false; + this._deleteButton.addEventListener("click", this._deleteButtonClicked.bind(this), false); + + this._refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item"); + this._refreshButton.addEventListener("click", this._refreshButtonClicked.bind(this), false); - this.refreshButton = new WebInspector.StatusBarButton(WebInspector.UIString("Refresh"), "refresh-storage-status-bar-item"); - this.refreshButton.addEventListener("click", this._refreshButtonClicked.bind(this), false); - this._treeElement = treeElement; this._cookieDomain = cookieDomain; @@ -182,7 +52,7 @@ WebInspector.CookieItemsView = function(treeElement, cookieDomain) WebInspector.CookieItemsView.prototype = { get statusBarItems() { - return [this.refreshButton.element, this.deleteButton.element]; + return [this._refreshButton.element, this._deleteButton.element]; }, show: function(parentElement) @@ -194,7 +64,13 @@ WebInspector.CookieItemsView.prototype = { hide: function() { WebInspector.View.prototype.hide.call(this); - this.deleteButton.visible = false; + this._deleteButton.visible = false; + }, + + resize: function() + { + if (this._cookiesTable) + this._cookiesTable.updateWidths(); }, _update: function() @@ -204,47 +80,35 @@ WebInspector.CookieItemsView.prototype = { _updateWithCookies: function(allCookies, isAdvanced) { - if (isAdvanced) - this._filterCookiesForDomain(allCookies); - else - this._cookies = allCookies; + this._cookies = isAdvanced ? this._filterCookiesForDomain(allCookies) : allCookies; + if (!this._cookies.length) { // Nothing to show. this._emptyMsgElement.removeStyleClass("hidden"); - this.deleteButton.visible = false; - if (this._dataGrid) - this._dataGrid.element.addStyleClass("hidden"); + this._deleteButton.visible = false; + if (this._cookiesTable) + this._cookiesTable.element.addStyleClass("hidden"); return; } - if (!this._dataGrid) { - if (isAdvanced) { - this._createDataGrid(); - this._populateDataGrid(); - this._dataGrid.autoSizeColumns(6, 33); - this._treeElement.subtitle = String.sprintf(WebInspector.UIString("%d cookies (%s)"), this._cookies.length, - Number.bytesToString(this._totalSize, WebInspector.UIString)); - } else { - this._createSimpleDataGrid(); - this._populateSimpleDataGrid(); - this._dataGrid.autoSizeColumns(20, 80); - } - } else { - if (isAdvanced) - this._populateDataGrid(); - else - this._populateSimpleDataGrid(); + if (!this._cookiesTable) { + this._cookiesTable = isAdvanced ? new WebInspector.CookiesTable(this._cookieDomain, false, this._deleteCookie.bind(this)) : new WebInspector.SimpleCookiesTable(); + this.element.appendChild(this._cookiesTable.element); } - this._dataGrid.element.removeStyleClass("hidden"); + this._cookiesTable.setCookies(this._cookies); + this._cookiesTable.element.removeStyleClass("hidden"); this._emptyMsgElement.addStyleClass("hidden"); - if (isAdvanced) - this.deleteButton.visible = true; + if (isAdvanced) { + this._treeElement.subtitle = String.sprintf(WebInspector.UIString("%d cookies (%s)"), this._cookies.length, + Number.bytesToString(this._totalSize, WebInspector.UIString)); + this._deleteButton.visible = true; + } }, _filterCookiesForDomain: function(allCookies) { - this._cookies = []; + var cookies = []; var resourceURLsForDocumentURL = []; this._totalSize = 0; @@ -265,34 +129,52 @@ WebInspector.CookieItemsView.prototype = { this._totalSize += size; if (!pushed) { pushed = true; - this._cookies.push(allCookies[i]); + cookies.push(allCookies[i]); } } } } + return cookies; }, - _populateDataGrid: function() + _deleteCookie: function(cookie) { - this._populateCookies(this._dataGrid, this._cookies); + InspectorBackend.deleteCookie(cookie.name, this._cookieDomain); + this._update(); }, - _createSimpleDataGrid: function() + _deleteButtonClicked: function() { - var columns = {}; - columns[0] = {}; - columns[1] = {}; - columns[0].title = WebInspector.UIString("Name"); - columns[1].title = WebInspector.UIString("Value"); - - this._dataGrid = new WebInspector.DataGrid(columns); - this.element.appendChild(this._dataGrid.element); - this._dataGrid.updateWidths(); + if (this._cookiesTable.selectedCookie) + this._deleteCookie(this._cookiesTable.selectedCookie); }, - _populateSimpleDataGrid: function() + _refreshButtonClicked: function(event) + { + this._update(); + } +} + +WebInspector.CookieItemsView.prototype.__proto__ = WebInspector.View.prototype; + +WebInspector.SimpleCookiesTable = function() +{ + this.element = document.createElement("div"); + var columns = {}; + columns[0] = {}; + columns[1] = {}; + columns[0].title = WebInspector.UIString("Name"); + columns[1].title = WebInspector.UIString("Value"); + + this._dataGrid = new WebInspector.DataGrid(columns); + this._dataGrid.autoSizeColumns(20, 80); + this.element.appendChild(this._dataGrid.element); + this._dataGrid.updateWidths(); +} + +WebInspector.SimpleCookiesTable.prototype = { + setCookies: function(cookies) { - var cookies = this._cookies; this._dataGrid.removeChildren(); var addedCookies = {}; for (var i = 0; i < cookies.length; ++i) { @@ -310,26 +192,9 @@ WebInspector.CookieItemsView.prototype = { this._dataGrid.children[0].selected = true; }, - _deleteButtonClicked: function(event) - { - if (!this._dataGrid || !this._dataGrid.selectedNode) - return; - - this._deleteCookieCallback(this._dataGrid.selectedNode); - }, - - _deleteCookieCallback: function(node) - { - var cookie = node.cookie; - InspectorBackend.deleteCookie(cookie.name, this._cookieDomain); - this._update(); - }, - - _refreshButtonClicked: function(event) + resize: function() { - this._update(); + if (this._dataGrid) + this._dataGrid.updateWidths(); } } - -WebInspector.CookieItemsView.prototype.__proto__ = WebInspector.CookiesTable.prototype; - diff --git a/WebCore/inspector/front-end/CookiesTable.js b/WebCore/inspector/front-end/CookiesTable.js new file mode 100644 index 0000000..2382a8e --- /dev/null +++ b/WebCore/inspector/front-end/CookiesTable.js @@ -0,0 +1,205 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * Copyright (C) 2009 Joseph Pecoraro + * 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.CookiesTable = function(cookieDomain, expandable, deleteCallback) +{ + this._cookieDomain = cookieDomain; + + var columns = { 0: {}, 1: {}, 2: {}, 3: {}, 4: {}, 5: {}, 6: {}, 7: {} }; + columns[0].title = WebInspector.UIString("Name"); + columns[0].sortable = true; + columns[0].disclosure = expandable; + columns[0].width = "24%"; + columns[1].title = WebInspector.UIString("Value"); + columns[1].sortable = true; + columns[1].width = "34%"; + columns[2].title = WebInspector.UIString("Domain"); + columns[2].sortable = true; + columns[2].width = "7%"; + columns[3].title = WebInspector.UIString("Path"); + columns[3].sortable = true; + columns[3].width = "7%"; + columns[4].title = WebInspector.UIString("Expires"); + columns[4].sortable = true; + columns[4].width = "7%"; + columns[5].title = WebInspector.UIString("Size"); + columns[5].aligned = "right"; + columns[5].sortable = true; + columns[5].width = "7%"; + columns[6].title = WebInspector.UIString("HTTP"); + columns[6].aligned = "centered"; + columns[6].sortable = true; + columns[6].width = "7%"; + columns[7].title = WebInspector.UIString("Secure"); + columns[7].aligned = "centered"; + columns[7].sortable = true; + columns[7].width = "7%"; + + this._dataGrid = new WebInspector.DataGrid(columns, null, deleteCallback ? this._onDeleteFromGrid.bind(this) : null); + this._dataGrid.addEventListener("sorting changed", this._rebuildTable, this); + + this.element = this._dataGrid.element; + this._data = []; + this._deleteCallback = deleteCallback; +} + +WebInspector.CookiesTable.prototype = { + updateWidths: function() + { + if (this._dataGrid) + this._dataGrid.updateWidths(); + }, + + setCookies: function(cookies) + { + this._data = [{cookies: cookies}]; + this._rebuildTable(); + }, + + addCookiesFolder: function(folderName, cookies) + { + this._data.push({cookies: cookies, folderName: folderName}); + this._rebuildTable(); + }, + + get selectedCookie() + { + var node = this._dataGrid.selectedNode; + return node ? node.cookie : null; + }, + + _rebuildTable: function() + { + this._dataGrid.removeChildren(); + for (var i = 0; i < this._data.length; ++i) { + var item = this._data[i]; + if (item.folderName) { + var groupData = [ item.folderName, "", "", "", "", this._totalSize(item.cookies), "", "" ]; + var groupNode = new WebInspector.DataGridNode(groupData); + groupNode.selectable = true; + this._dataGrid.appendChild(groupNode); + groupNode.element.addStyleClass("row-group"); + this._populateNode(groupNode, item.cookies); + groupNode.expand(); + } else + this._populateNode(this._dataGrid, item.cookies); + } + }, + + _populateNode: function(parentNode, cookies) + { + var selectedCookie = this.selectedCookie; + parentNode.removeChildren(); + if (!cookies) + return; + + this._sortCookies(cookies); + for (var i = 0; i < cookies.length; ++i) { + var cookieNode = this._createGridNode(cookies[i]); + parentNode.appendChild(cookieNode); + if (selectedCookie === cookies[i]) + cookieNode.selected = true; + } + }, + + _totalSize: function(cookies) + { + var totalSize = 0; + for (var i = 0; cookies && i < cookies.length; ++i) + totalSize += cookies[i].size; + return totalSize; + }, + + _sortCookies: function(cookies) + { + var sortDirection = this._dataGrid.sortOrder === "ascending" ? 1 : -1; + + function localeCompare(field, cookie1, cookie2) + { + return sortDirection * (cookie1[field] + "").localeCompare(cookie2[field] + "") + } + + function numberCompare(field, cookie1, cookie2) + { + return sortDirection * (cookie1[field] - cookie2[field]); + } + + function expiresCompare(cookie1, cookie2) + { + if (cookie1.session !== cookie2.session) + return sortDirection * (cookie1.session ? 1 : -1); + + if (cookie1.session) + return 0; + + return sortDirection * (cookie1.expires - cookie2.expires); + } + + var comparator; + switch (parseInt(this._dataGrid.sortColumnIdentifier)) { + case 0: comparator = localeCompare.bind(this, "name"); break; + case 1: comparator = localeCompare.bind(this, "value"); break; + case 2: comparator = localeCompare.bind(this, "domain"); break; + case 3: comparator = localeCompare.bind(this, "path"); break; + case 4: comparator = expiresCompare; break; + case 5: comparator = numberCompare.bind(this, "size"); break; + case 6: comparator = localeCompare.bind(this, "httpOnly"); break; + case 7: comparator = localeCompare.bind(this, "secure"); break; + default: localeCompare.bind(this, "name"); + } + + cookies.sort(comparator); + }, + + _createGridNode: function(cookie) + { + var data = {}; + data[0] = cookie.name; + data[1] = cookie.value; + data[2] = cookie.domain || ""; + data[3] = cookie.path || ""; + data[4] = cookie.type === WebInspector.Cookie.Type.Request ? "" : + (cookie.session ? WebInspector.UIString("Session") : new Date(cookie.expires).toGMTString()); + data[5] = cookie.size; + const checkmark = "\u2713"; + data[6] = (cookie.httpOnly ? checkmark : ""); + data[7] = (cookie.secure ? checkmark : ""); + + var node = new WebInspector.DataGridNode(data); + node.cookie = cookie; + node.selectable = true; + return node; + }, + + _onDeleteFromGrid: function(node) + { + this._deleteCallback(node.cookie); + } +} diff --git a/WebCore/inspector/front-end/ElementsPanel.js b/WebCore/inspector/front-end/ElementsPanel.js index 76c22c5..61ba33e 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.panel.name, "DOMNode"); + WebInspector.extensionServer.notifyObjectSelected(this.panel.name); } }; diff --git a/WebCore/inspector/front-end/ExtensionAPI.js b/WebCore/inspector/front-end/ExtensionAPI.js index e526cf5..0234994 100644 --- a/WebCore/inspector/front-end/ExtensionAPI.js +++ b/WebCore/inspector/front-end/ExtensionAPI.js @@ -104,109 +104,130 @@ InspectorExtensionAPI.prototype = { function Resources() { - this.onFinished = new EventSink("resource-finished"); + function resourceDispatch(request) + { + var resource = request.arguments[1]; + resource.__proto__ = new Resource(request.arguments[0]); + this._fire(resource); + } + this.onFinished = new EventSink("resource-finished", resourceDispatch); } Resources.prototype = { - getAll: function(callback) - { - return extensionServer.sendRequest({ command: "getResources" }, callback); - }, - - get: function(id, callback) + getHAR: function(callback) { - return extensionServer.sendRequest({ command: "getResources", id: id }, callback); - }, + function callbackWrapper(result) + { + var entries = (result && result.entries) || []; + for (var i = 0; i < entries.length; ++i) { + entries[i].__proto__ = new Resource(entries[i]._resourceId); + delete entries[i]._resourceId; + } + callback(result); + } + return extensionServer.sendRequest({ command: "getHAR" }, callback && callbackWrapper); + } +} - getPageTimings: function(callback) - { - return extensionServer.sendRequest({ command: "getPageTimings" }, callback); - }, +function ResourceImpl(id) +{ + this._id = id; +} - getContent: function(ids, callback) +ResourceImpl.prototype = { + getContent: function(callback) { - return extensionServer.sendRequest({ command: "getResourceContent", ids: ids }, callback); + function callbackWrapper(response) + { + callback(response.content, response.encoding); + } + extensionServer.sendRequest({ command: "getResourceContent", id: this._id }, callback && callbackWrapper); } -} - -var wellKnownPanelNames = [ - "elements", - "scripts" -]; +}; function Panels() { - var panels = []; + var panels = { + elements: new ElementsPanel() + }; + function panelGetter(name) { return panels[name]; } - - for (var i = 0; i < wellKnownPanelNames.length; ++i) { - var name = wellKnownPanelNames[i]; - panels[name] = new Panel(name); - this.__defineGetter__(name, bind(panelGetter, null, name)); - } + for (var panel in panels) + this.__defineGetter__(panel, bind(panelGetter, null, panel)); } Panels.prototype = { - create: function(label, pageURL, iconURL, callback) + create: function(title, iconURL, pageURL, callback) { var id = "extension-panel-" + extensionServer.nextObjectId(); - function callbackWrapper(result) - { - if (result.isError) - callback(result); - else { - panel = new ExtensionPanel(id); - callback(panel); - } - } var request = { command: "createPanel", id: id, - label: label, - url: expandURL(pageURL), - icon: expandURL(iconURL) + title: title, + icon: expandURL(iconURL), + url: expandURL(pageURL) }; - extensionServer.sendRequest(request, callback && bind(callbackWrapper, this)); + extensionServer.sendRequest(request, callback && bind(callback, this, new ExtensionPanel(id))); } } function PanelImpl(id) { this._id = id; - this.onSelectionChanged = new EventSink("panel-objectSelected-" + id); } -PanelImpl.prototype = { +function PanelWithSidebarImpl(id) +{ + PanelImpl.call(this, id); +} + +PanelWithSidebarImpl.prototype = { createSidebarPane: function(title, url, callback) { var id = "extension-sidebar-" + extensionServer.nextObjectId(); - function callbackWrapper(result) + var request = { + command: "createSidebarPane", + panel: this._id, + id: id, + title: title, + url: expandURL(url) + }; + function callbackWrapper() { - if (result.isError) - callback(result); - else - callback(new ExtensionSidebarPane(id)); + callback(new ExtensionSidebarPane(id)); } - extensionServer.sendRequest({ command: "createSidebarPane", panel: this._id, id: id, title: title, url: expandURL(url) }, callback && callbackWrapper); + extensionServer.sendRequest(request, callback && callbackWrapper); }, createWatchExpressionSidebarPane: function(title, callback) { var id = "watch-sidebar-" + extensionServer.nextObjectId(); - function callbackWrapper(result) + var request = { + command: "createWatchExpressionSidebarPane", + panel: this._id, + id: id, + title: title + }; + function callbackWrapper() { - if (result.isError) - callback(result); - else - callback(new WatchExpressionSidebarPane(id)); + callback(new WatchExpressionSidebarPane(id)); } - extensionServer.sendRequest({ command: "createWatchExpressionSidebarPane", panel: this._id, id: id, title: title }, callback && callbackWrapper); + extensionServer.sendRequest(request, callback && callbackWrapper); } } +PanelWithSidebarImpl.prototype.__proto__ = PanelImpl.prototype; + +function ElementsPanel() +{ + var id = "elements"; + PanelWithSidebar.call(this, id); + this.onSelectionChanged = new EventSink("panel-objectSelected-" + id); +} + function ExtensionPanel(id) { Panel.call(this, id); @@ -222,11 +243,6 @@ ExtensionSidebarPaneImpl.prototype = { setHeight: function(height) { extensionServer.sendRequest({ command: "setSidebarHeight", id: this._id, height: height }); - }, - - setExpanded: function(expanded) - { - extensionServer.sendRequest({ command: "setSidebarExpanded", id: this._id, expanded: expanded }); } } @@ -261,17 +277,17 @@ function Audits() } Audits.prototype = { - addCategory: function(displayName, ruleCount) + addCategory: function(displayName, resultCount) { var id = "extension-audit-category-" + extensionServer.nextObjectId(); - extensionServer.sendRequest({ command: "addAuditCategory", id: id, displayName: displayName, ruleCount: ruleCount }); + extensionServer.sendRequest({ command: "addAuditCategory", id: id, displayName: displayName, resultCount: resultCount }); return new AuditCategory(id); } } function AuditCategoryImpl(id) { - function customDispatch(request) + function auditResultDispatch(request) { var auditResult = new AuditResult(request.arguments[0]); try { @@ -282,7 +298,7 @@ function AuditCategoryImpl(id) } } this._id = id; - this.onAuditStarted = new EventSink("audit-started-" + id, customDispatch); + this.onAuditStarted = new EventSink("audit-started-" + id, auditResultDispatch); } function AuditResultImpl(id) @@ -330,7 +346,7 @@ AuditResultImpl.prototype = { get Severity() { - return private.audits.Severity; + return apiPrivate.audits.Severity; }, _nodeFactory: function(type) @@ -360,9 +376,9 @@ AuditResultNode.prototype = { function InspectedWindow() { + this.onDOMContentLoaded = new EventSink("inspectedPageDOMContentLoaded"); this.onLoaded = new EventSink("inspectedPageLoaded"); this.onNavigated = new EventSink("inspectedURLChanged"); - this.onDOMContentLoaded = new EventSink("DOMContentLoaded"); } InspectedWindow.prototype = { @@ -371,13 +387,14 @@ InspectedWindow.prototype = { return extensionServer.sendRequest({ command: "reload" }); }, - evaluate: function(expression, callback) + eval: function(expression, callback) { function callbackWrapper(result) { - if (result && !result.isException) - result.value = result.value === "undefined" ? undefined : JSON.parse(result.value); - callback(result); + var value = result.value; + if (!result.isException) + value = value === "undefined" ? undefined : JSON.parse(value); + callback(value, result.isException); } return extensionServer.sendRequest({ command: "evaluateOnInspectedPage", expression: expression }, callback && callbackWrapper); } @@ -481,12 +498,14 @@ function declareInterfaceClass(implConstructor) } } +var AuditCategory = declareInterfaceClass(AuditCategoryImpl); +var AuditResult = declareInterfaceClass(AuditResultImpl); var EventSink = declareInterfaceClass(EventSinkImpl); -var Panel = declareInterfaceClass(PanelImpl); var ExtensionSidebarPane = declareInterfaceClass(ExtensionSidebarPaneImpl); +var Panel = declareInterfaceClass(PanelImpl); +var PanelWithSidebar = declareInterfaceClass(PanelWithSidebarImpl); +var Resource = declareInterfaceClass(ResourceImpl); var WatchExpressionSidebarPane = declareInterfaceClass(WatchExpressionSidebarPaneImpl); -var AuditCategory = declareInterfaceClass(AuditCategoryImpl); -var AuditResult = declareInterfaceClass(AuditResultImpl); var extensionServer = new ExtensionServerClient(); diff --git a/WebCore/inspector/front-end/ExtensionCommon.js b/WebCore/inspector/front-end/ExtensionCommon.js index b04c18c..8034001 100644 --- a/WebCore/inspector/front-end/ExtensionCommon.js +++ b/WebCore/inspector/front-end/ExtensionCommon.js @@ -28,13 +28,13 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -WebInspector.commonExtensionSymbols = function(private) +WebInspector.commonExtensionSymbols = function(apiPrivate) { - if (!private.audits) - private.audits = {}; + if (!apiPrivate.audits) + apiPrivate.audits = {}; - private.audits.Severity = { + apiPrivate.audits.Severity = { Info: "info", Warning: "warning", Severe: "severe" diff --git a/WebCore/inspector/front-end/ExtensionServer.js b/WebCore/inspector/front-end/ExtensionServer.js index 7229785..1050c6f 100644 --- a/WebCore/inspector/front-end/ExtensionServer.js +++ b/WebCore/inspector/front-end/ExtensionServer.js @@ -35,23 +35,22 @@ WebInspector.ExtensionServer = function() this._subscribers = {}; this._status = new WebInspector.ExtensionStatus(); - this._registerHandler("subscribe", this._onSubscribe.bind(this)); - this._registerHandler("unsubscribe", this._onUnsubscribe.bind(this)); - this._registerHandler("getResources", this._onGetResources.bind(this)); - this._registerHandler("getResourceContent", this._onGetResourceContent.bind(this)); - this._registerHandler("getPageTimings", this._onGetPageTimings.bind(this)); + this._registerHandler("addAuditCategory", this._onAddAuditCategory.bind(this)); + this._registerHandler("addAuditResult", this._onAddAuditResult.bind(this)); this._registerHandler("createPanel", this._onCreatePanel.bind(this)); this._registerHandler("createSidebarPane", this._onCreateSidebar.bind(this)); this._registerHandler("createWatchExpressionSidebarPane", this._onCreateWatchExpressionSidebarPane.bind(this)); - this._registerHandler("log", this._onLog.bind(this)); this._registerHandler("evaluateOnInspectedPage", this._onEvaluateOnInspectedPage.bind(this)); + this._registerHandler("getHAR", this._onGetHAR.bind(this)); + this._registerHandler("getResourceContent", this._onGetResourceContent.bind(this)); + this._registerHandler("log", this._onLog.bind(this)); + this._registerHandler("reload", this._onReload.bind(this)); this._registerHandler("setSidebarHeight", this._onSetSidebarHeight.bind(this)); - this._registerHandler("setSidebarExpanded", this._onSetSidebarExpansion.bind(this)); this._registerHandler("setWatchSidebarContent", this._onSetWatchSidebarContent.bind(this)); - - this._registerHandler("addAuditCategory", this._onAddAuditCategory.bind(this)); - this._registerHandler("addAuditResult", this._onAddAuditResult.bind(this)); this._registerHandler("stopAuditCategoryRun", this._onStopAuditCategoryRun.bind(this)); + this._registerHandler("subscribe", this._onSubscribe.bind(this)); + this._registerHandler("unsubscribe", this._onUnsubscribe.bind(this)); + window.addEventListener("message", this._onWindowMessage.bind(this), false); } @@ -62,14 +61,14 @@ WebInspector.ExtensionServer.prototype = { this._postNotification("panel-shown-" + panelName); }, - notifyObjectSelected: function(panelId, objectType, objectId) + notifyObjectSelected: function(panelId, objectId) { - this._postNotification("panel-objectSelected-" + panelId, objectType, objectId); + this._postNotification("panel-objectSelected-" + panelId, objectId); }, notifyResourceFinished: function(resource) { - this._postNotification("resource-finished", this._convertResource(resource)); + this._postNotification("resource-finished", resource.identifier, (new WebInspector.HAREntry(resource)).build()); }, notifySearchAction: function(panelId, action, searchString) @@ -77,9 +76,14 @@ WebInspector.ExtensionServer.prototype = { this._postNotification("panel-search-" + panelId, action, searchString); }, - notifyInspectedPageLoaded: function() + notifyPageLoaded: function(milliseconds) + { + this._postNotification("inspectedPageLoaded", milliseconds); + }, + + notifyPageDOMContentLoaded: function(milliseconds) { - this._postNotification("inspectedPageLoaded"); + this._postNotification("inspectedPageDOMContentLoaded", milliseconds); }, notifyInspectedURLChanged: function() @@ -108,15 +112,6 @@ WebInspector.ExtensionServer.prototype = { delete this._clientObjects[auditRun.id]; }, - _convertResource: function(resource) - { - return { - id: resource.identifier, - type: WebInspector.Resource.Type.toString(resource.type), - har: (new WebInspector.HAREntry(resource)).build(), - }; - }, - _postNotification: function(type, details) { var subscribers = this._subscribers[type]; @@ -156,7 +151,7 @@ WebInspector.ExtensionServer.prototype = { // shouldn't be hit unless someone is bypassing the API. if (id in this._clientObjects || id in WebInspector.panels) return this._status.E_EXISTS(id); - var panel = new WebInspector.ExtensionPanel(id, message.label, message.icon); + var panel = new WebInspector.ExtensionPanel(id, message.title, message.icon); this._clientObjects[id] = panel; var toolbarElement = document.getElementById("toolbar"); @@ -216,17 +211,6 @@ WebInspector.ExtensionServer.prototype = { sidebar.bodyElement.firstChild.style.height = message.height; }, - _onSetSidebarExpansion: function(message) - { - var sidebar = this._clientObjects[message.id]; - if (!sidebar) - return this._status.E_NOTFOUND(message.id); - if (message.expanded) - sidebar.expand(); - else - sidebar.collapse(); - }, - _onSetWatchSidebarContent: function(message) { var sidebar = this._clientObjects[message.id]; @@ -243,6 +227,12 @@ WebInspector.ExtensionServer.prototype = { WebInspector.log(message.message); }, + _onReload: function() + { + InspectorBackend.reloadPage(); + return this._status.OK(); + }, + _onEvaluateOnInspectedPage: function(message, port) { function callback(resultPayload) @@ -286,66 +276,32 @@ WebInspector.ExtensionServer.prototype = { port.postMessage({ command: "callback", requestId: requestId, result: result }); }, - _onGetResources: function(request) + _onGetHAR: function(request) { - function resourceWrapper(id) - { - return WebInspector.extensionServer._convertResource(WebInspector.networkResources[id]); - } - - var response; - if (request.id) - response = WebInspector.networkResources[request.id] ? resourceWrapper(request.id) : this._status.E_NOTFOUND(request.id); - else - response = Object.keys(WebInspector.networkResources).map(resourceWrapper); - return response; + var harLog = new WebInspector.HARLog(); + harLog.includeResourceIds = true; + return harLog.build(); }, _onGetResourceContent: function(message, port) { - var ids; - var response = []; - - function onContentAvailable(id, content, encoded) + function onContentAvailable(content, encoded) { - var resourceContent = { - id: id, + var response = { encoding: encoded ? "base64" : "", content: content }; - response.push(resourceContent); - if (response.length === ids.length) - this._dispatchCallback(message.requestId, port, response); - } - - if (typeof message.ids === "number") - ids = [ message.ids ]; - else if (message.ids instanceof Array) - ids = message.ids; - else - return this._status.E_BADARGTYPE("message.ids", "Array", typeof message.ids); - - for (var i = 0; i < ids.length; ++i) { - var id = ids[i]; - var resource = WebInspector.networkResources[id]; - - if (!resource) - response.push(this._status.E_NOTFOUND(id)); - else - resource.requestContent(onContentAvailable.bind(this, id)); - } - if (response.length === ids.length) this._dispatchCallback(message.requestId, port, response); - }, - - _onGetPageTimings: function() - { - return (new WebInspector.HARLog()).buildMainResourceTimings(); + } + var resource = WebInspector.networkResources[message.id]; + if (!resource) + return this._status.E_NOTFOUND(message.id); + resource.requestContent(onContentAvailable.bind(this)); }, _onAddAuditCategory: function(request) { - var category = new WebInspector.ExtensionAuditCategory(request.id, request.displayName, request.ruleCount); + var category = new WebInspector.ExtensionAuditCategory(request.id, request.displayName, request.resultCount); if (WebInspector.panels.audits.getCategory(category.id)) return this._status.E_EXISTS(category.id); this._clientObjects[request.id] = category; @@ -409,8 +365,8 @@ WebInspector.ExtensionServer.prototype = { } var platformAPI = WebInspector.buildPlatformExtensionAPI ? WebInspector.buildPlatformExtensionAPI() : ""; return "(function(){ " + - "var private = {};" + - "(" + WebInspector.commonExtensionSymbols.toString() + ")(private);" + + "var apiPrivate = {};" + + "(" + WebInspector.commonExtensionSymbols.toString() + ")(apiPrivate);" + "(" + WebInspector.injectedExtensionAPI.toString() + ").apply(this, arguments);" + "webInspector.resources.Types = " + JSON.stringify(resourceTypes) + ";" + platformAPI + diff --git a/WebCore/inspector/front-end/FileSystemView.js b/WebCore/inspector/front-end/FileSystemView.js index 0c6636b..8cd0107 100644 --- a/WebCore/inspector/front-end/FileSystemView.js +++ b/WebCore/inspector/front-end/FileSystemView.js @@ -125,12 +125,12 @@ WebInspector.FileSystemView.prototype = { }, _selectFileSystemTab: function() { - this._tabbedPane.selectTabById("persistent"); + this._tabbedPane.selectTab("persistent"); }, selectTemporaryFileSystemTab: function() { - this._tabbedPane.selectTabById("temp"); + this._tabbedPane.selectTab("temp"); }, _revealPersistentFolderInOS: function() diff --git a/WebCore/inspector/front-end/FontView.js b/WebCore/inspector/front-end/FontView.js index 78a7e70..82559ef 100644 --- a/WebCore/inspector/front-end/FontView.js +++ b/WebCore/inspector/front-end/FontView.js @@ -34,12 +34,12 @@ WebInspector.FontView = function(resource) } WebInspector.FontView.prototype = { - hasContentTab: function() + hasContent: function() { return true; }, - contentTabSelected: function() + _createContentIfNeeded: function() { if (this.fontPreviewElement) return; @@ -51,7 +51,7 @@ WebInspector.FontView.prototype = { document.head.appendChild(this.fontStyleElement); this.fontPreviewElement = document.createElement("div"); - this.contentElement.appendChild(this.fontPreviewElement); + this.element.appendChild(this.fontPreviewElement); this.fontPreviewElement.style.setProperty("font-family", uniqueFontName, null); this.fontPreviewElement.innerHTML = "ABCDEFGHIJKLM<br>NOPQRSTUVWXYZ<br>abcdefghijklm<br>nopqrstuvwxyz<br>1234567890"; @@ -63,6 +63,7 @@ WebInspector.FontView.prototype = { show: function(parentElement) { WebInspector.ResourceView.prototype.show.call(this, parentElement); + this._createContentIfNeeded(); this.updateFontPreviewSize(); }, @@ -86,7 +87,7 @@ WebInspector.FontView.prototype = { const width = this.fontPreviewElement.offsetWidth; // Subtract some padding. This should match the padding in the CSS plus room for the scrollbar. - const containerWidth = this.contentElement.offsetWidth - 50; + const containerWidth = this.element.offsetWidth - 50; if (!height || !width || !containerWidth) { this.fontPreviewElement.style.removeProperty("font-size"); diff --git a/WebCore/inspector/front-end/HAREntry.js b/WebCore/inspector/front-end/HAREntry.js index f3bfb06..6dfbd1b 100644 --- a/WebCore/inspector/front-end/HAREntry.js +++ b/WebCore/inspector/front-end/HAREntry.js @@ -189,6 +189,7 @@ WebInspector.HAREntry._toMilliseconds = function(time) WebInspector.HARLog = function() { + this.includeResourceIds = false; } WebInspector.HARLog.prototype = { @@ -203,7 +204,7 @@ WebInspector.HARLog.prototype = { version: webKitVersion ? webKitVersion[1] : "n/a" }, pages: this._buildPages(), - entries: Object.keys(WebInspector.networkResources).map(this._convertResource) + entries: Object.keys(WebInspector.networkResources).map(this._convertResource.bind(this)) } }, @@ -229,7 +230,10 @@ WebInspector.HARLog.prototype = { _convertResource: function(id) { - return (new WebInspector.HAREntry(WebInspector.networkResources[id])).build(); + var entry = (new WebInspector.HAREntry(WebInspector.networkResources[id])).build(); + if (this.includeResourceIds) + entry._resourceId = id; + return entry; }, _pageEventTime: function(time) diff --git a/WebCore/inspector/front-end/HeapSnapshotView.js b/WebCore/inspector/front-end/HeapSnapshotView.js index 6bcc0ff..d09f91d 100644 --- a/WebCore/inspector/front-end/HeapSnapshotView.js +++ b/WebCore/inspector/front-end/HeapSnapshotView.js @@ -27,6 +27,154 @@ * (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.HeapSnapshotEdgesIterator = function(snapshot, edges) +{ + this._snapshot = snapshot; + this._edges = edges; + this._edgeIndex = 0; +} + +WebInspector.HeapSnapshotEdgesIterator.prototype = { + get done() + { + return this._edgeIndex >= this._edges.length; + }, + + get isElement() + { + return this._getType() === this._snapshot._edgeElementType; + }, + + get isHidden() + { + return this._getType() === this._snapshot._edgeHiddenType; + }, + + get name() + { + return this.isElement || this.isHidden ? this._getNameOrIndex() : this._snapshot._strings[this._getNameOrIndex()]; + }, + + next: function() + { + this._edgeIndex += this._snapshot._edgeFieldsCount; + }, + + get node() + { + return new WebInspector.HeapSnapshotNodeWrapper(this._snapshot, this.nodeIndex); + }, + + get nodeIndex() + { + return this._edges[this._edgeIndex + this._snapshot._edgeToNodeOffset]; + }, + + _getNameOrIndex: function() + { + return this._edges[this._edgeIndex + this._snapshot._edgeNameOffset]; + }, + + _getType: function() + { + return this._edges[this._edgeIndex + this._snapshot._edgeTypeOffset]; + } +}; + +WebInspector.HeapSnapshotNodeWrapper = function(snapshot, nodeIndex) +{ + this._snapshot = snapshot; + this._nodes = snapshot._nodes; + this._nodeIndex = nodeIndex; +} + +WebInspector.HeapSnapshotNodeWrapper.prototype = { + get edges() + { + return new WebInspector.HeapSnapshotEdgesIterator(this._snapshot, this._getEdges()); + }, + + get edgesCount() + { + return this._nodes[this._nodeIndex + this._snapshot._edgesCountOffset]; + }, + + get instancesCount() + { + return this._nodes[this._nodeIndex + this._snapshot._nodeInstancesCountOffset]; + }, + + get isHidden() + { + return this._getType() === this._snapshot._nodeHiddenType; + }, + + get name() + { + return this._snapshot._strings[this._getName()]; + }, + + get selfSize() + { + return this._nodes[this._nodeIndex + this._snapshot._nodeSelfSizeOffset]; + }, + + _getName: function() + { + return this._nodes[this._nodeIndex + this._snapshot._nodeNameOffset]; + }, + + _getEdges: function() + { + var firstEdgeIndex = this._nodeIndex + this._snapshot._firstEdgeOffset; + return this._nodes.slice(firstEdgeIndex, firstEdgeIndex + this.edgesCount * this._snapshot._edgeFieldsCount); + }, + + _getType: function() + { + return this._nodes[this._nodeIndex + this._snapshot._nodeTypeOffset]; + } +}; + +WebInspector.HeapSnapshot = function(profile) +{ + this._profile = profile; + this._nodes = profile.nodes; + this._strings = profile.strings; + + this._init(); +} + +WebInspector.HeapSnapshot.prototype = { + _init: function() + { + this._metaNodeIndex = 0; + this._rootNodeIndex = 1; + var meta = this._nodes[this._metaNodeIndex]; + this._nodeTypeOffset = meta.fields.indexOf("type"); + this._nodeNameOffset = meta.fields.indexOf("name"); + this._nodeIdOffset = meta.fields.indexOf("id"); + this._nodeInstancesCountOffset = this._nodeIdOffset; + this._nodeSelfSizeOffset = meta.fields.indexOf("self_size"); + this._edgesCountOffset = meta.fields.indexOf("children_count"); + this._firstEdgeOffset = meta.fields.indexOf("children"); + this._nodeTypes = meta.types[this._nodeTypeOffset]; + this._nodeHiddenType = this._nodeTypes.indexOf("hidden"); + var edgesMeta = meta.types[this._firstEdgeOffset]; + this._edgeFieldsCount = edgesMeta.fields.length; + this._edgeTypeOffset = edgesMeta.fields.indexOf("type"); + this._edgeNameOffset = edgesMeta.fields.indexOf("name_or_index"); + this._edgeToNodeOffset = edgesMeta.fields.indexOf("to_node"); + this._edgeTypes = edgesMeta.types[this._edgeTypeOffset]; + this._edgeElementType = this._edgeTypes.indexOf("element"); + this._edgeHiddenType = this._edgeTypes.indexOf("hidden"); + }, + + get rootEdges() + { + return (new WebInspector.HeapSnapshotNodeWrapper(this, this._rootNodeIndex)).edges; + } +}; WebInspector.HeapSnapshotView = function(parent, profile) { @@ -94,6 +242,7 @@ WebInspector.HeapSnapshotView = function(parent, profile) this.percentButton = new WebInspector.StatusBarButton("", "percent-time-status-bar-item status-bar-item"); this.percentButton.addEventListener("click", this._percentClicked.bind(this), false); + this._loadedCallbacks = []; this._loadProfile(this.profile, profileCallback.bind(this)); function profileCallback(profile) @@ -290,6 +439,14 @@ WebInspector.HeapSnapshotView.prototype = { this._updateSummaryGraph(); }, + snapshotLoaded: function(uid, loadedSnapshot) + { + if (!this._loadedCallbacks[uid]) + return; + this._loadedCallbacks[uid](loadedSnapshot); + delete this._loadedCallbacks[uid]; + }, + _changeBase: function() { if (this.baseSnapshot.uid === this._getProfiles()[this.baseSelectElement.selectedIndex].uid) @@ -332,15 +489,17 @@ WebInspector.HeapSnapshotView.prototype = { return; } - InspectorBackend.getProfile(profile.typeId, profile.uid, loadedCallback.bind(this)); + this._loadedCallbacks[profile.uid] = processLoadedSnapshot.bind(this); + InspectorBackend.getProfile(profile.typeId, profile.uid); - function loadedCallback(loadedSnapshot) { - profile.children = loadedSnapshot.head.children; - profile.entries = loadedSnapshot.head.entries; - profile.lowlevels = loadedSnapshot.head.lowlevels; + function processLoadedSnapshot(loadedSnapshot) + { + var snapshot = this._convertSnapshot(loadedSnapshot); + profile.children = snapshot.children; + profile.entries = snapshot.entries; + profile.lowlevels = snapshot.lowlevels; this._prepareProfile(profile); profile._loaded = true; - this.parent.updateProfile(profile); callback(profile); } }, @@ -384,6 +543,26 @@ WebInspector.HeapSnapshotView.prototype = { this.refreshShowAsPercents(); }, + _convertSnapshot: function(loadedSnapshot) + { + var snapshot = new WebInspector.HeapSnapshot(loadedSnapshot); + var result = {lowlevels: {}, entries: {}, children: {}}; + for (var rootEdges = snapshot.rootEdges; !rootEdges.done; rootEdges.next()) { + var node = rootEdges.node; + if (node.isHidden) + result.lowlevels[node.name] = {count: node.instancesCount, size: node.selfSize, type: node.name}; + else if (node.instancesCount) + result.entries[node.name] = {constructorName: node.name, count: node.instancesCount, size: node.selfSize}; + else { + var entry = {constructorName: node.name}; + for (var edges = node.edges; !edges.done; edges.next()) + entry[edges.nodeIndex] = {constructorName: edges.node.name, count: edges.name}; + result.children[rootEdges.nodeIndex] = entry; + } + } + return result; + }, + _prepareProfile: function(profile) { for (var profileEntry in profile.entries) @@ -392,12 +571,12 @@ WebInspector.HeapSnapshotView.prototype = { for (var addr in profile.children) { var retainer = profile.children[addr]; - var retainerId = retainer.constructorName + ':' + addr; + var retainerId = retainer.constructorName + ":" + addr; for (var childAddr in retainer) { - if (childAddr === 'constructorName') continue; + if (childAddr === "constructorName") continue; var item = retainer[childAddr]; - var itemId = item.constructorName + ':' + childAddr; - if ((item.constructorName === 'Object' || item.constructorName === 'Array')) { + 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); @@ -412,7 +591,7 @@ WebInspector.HeapSnapshotView.prototype = { 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') + if (retainer.constructorName === "Object" || retainer.constructorName === "Array") retainerEntry.clusters[retainerId] = true; } }, @@ -438,7 +617,7 @@ WebInspector.HeapSnapshotView.prototype = { var sortAscending = this.dataGrid.sortOrder === "ascending"; var sortColumnIdentifier = this.dataGrid.sortColumnIdentifier; var sortProperty = { - cons: ["cons", null], + cons: ["constructorName", null], count: ["count", null], size: ["size", "count"], countDelta: this.showCountDeltaAsPercent ? ["countDeltaPercent", null] : ["countDelta", null], diff --git a/WebCore/inspector/front-end/HelpScreen.js b/WebCore/inspector/front-end/HelpScreen.js index cad39d0..a1bbf1e 100644 --- a/WebCore/inspector/front-end/HelpScreen.js +++ b/WebCore/inspector/front-end/HelpScreen.js @@ -30,8 +30,6 @@ WebInspector.HelpScreen = function(title) { - this._addStyleSheetIfNeeded("helpScreen.css"); - this._element = document.createElement("div"); this._element.className = "help-window-outer"; this._element.addEventListener("keydown", this._onKeyDown.bind(this), false); @@ -86,17 +84,5 @@ WebInspector.HelpScreen.prototype = { // Pretend we're modal, grab focus back if we're still shown. if (this._isShown) WebInspector.currentFocusElement = this.contentElement; - }, - - _addStyleSheetIfNeeded: function(href) - { - if (WebInspector.HelpScreen._styleSheetAdded) - return; - - WebInspector.HelpScreen._styleSheetAdded = true; - var link = document.head.createChild("link"); - link.type = "text/css"; - link.rel = "stylesheet"; - link.href = href; } -}; +} diff --git a/WebCore/inspector/front-end/ImageView.js b/WebCore/inspector/front-end/ImageView.js index f70fad6..54a16bb 100644 --- a/WebCore/inspector/front-end/ImageView.js +++ b/WebCore/inspector/front-end/ImageView.js @@ -34,26 +34,33 @@ WebInspector.ImageView = function(resource) } WebInspector.ImageView.prototype = { - hasContentTab: function() + hasContent: function() { return true; }, - contentTabSelected: function() + show: function(parentElement) + { + WebInspector.ResourceView.prototype.show.call(this, parentElement); + this._createContentIfNeeded(); + }, + + _createContentIfNeeded: function() { if (this._container) return; - this._container = document.createElement("div"); - this._container.className = "image"; - this.contentElement.appendChild(this._container); + + var imageContainer = document.createElement("div"); + imageContainer.className = "image"; + this.element.appendChild(imageContainer); var imagePreviewElement = document.createElement("img"); imagePreviewElement.addStyleClass("resource-image-view"); - this._container.appendChild(imagePreviewElement); + imageContainer.appendChild(imagePreviewElement); this._container = document.createElement("div"); this._container.className = "info"; - this.contentElement.appendChild(this._container); + this.element.appendChild(this._container); var imageNameElement = document.createElement("h1"); imageNameElement.className = "title"; diff --git a/WebCore/inspector/front-end/InjectedScript.js b/WebCore/inspector/front-end/InjectedScript.js index fff6680..fb6b796 100644 --- a/WebCore/inspector/front-end/InjectedScript.js +++ b/WebCore/inspector/front-end/InjectedScript.js @@ -26,7 +26,7 @@ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -var injectedScriptConstructor = (function (InjectedScriptHost, inspectedWindow, injectedScriptId, jsEngine) { +var injectedScriptConstructor = (function (InjectedScriptHost, inspectedWindow, injectedScriptId) { var InjectedScript = function() { @@ -427,9 +427,17 @@ InjectedScript.prototype = { switch (type) { case "object": case "node": - return this._className(obj); + var result = InjectedScriptHost.internalConstructorName(obj); + if (result === "Object") { + // In Chromium DOM wrapper prototypes will have Object as their constructor name, + // get the real DOM wrapper name from the constructor property. + var constructorName = obj.constructor && obj.constructor.name; + if (constructorName) + return constructorName; + } + return result; case "array": - var className = this._className(obj); + var className = InjectedScriptHost.internalConstructorName(obj); if (typeof obj.length === "number") className += "[" + obj.length + "]"; return className; @@ -455,25 +463,6 @@ InjectedScript.prototype = { return "" + obj; }, - _className: function(obj) - { - // We can't use the same code for fetching class names of the dom bindings prototype chain. - // Both of the methods below result in "Object" names on the foreign engine bindings. - // I gave up and am using a check below to distinguish between the egine bingings. - - if (jsEngine == "JSC") { - var str = inspectedWindow.Object ? inspectedWindow.Object.prototype.toString.call(obj) : this._toString(obj); - return str.replace(/^\[object (.*)\]$/i, "$1"); - } else { - // V8 - if (isFinite(obj.length) && typeof obj.callee === "function") { - // Arguments.constructor === Object in V8 - return "Arguments"; - } - return obj.constructor && obj.constructor.name || "Object"; - } - }, - _logEvent: function(event) { console.log(event.type, event); @@ -711,11 +700,9 @@ CommandLineAPI.prototype = { copy: function(object) { - if (injectedScript._type(object) === "node") { - var nodeId = InjectedScriptHost.pushNodePathToFrontend(object, false, false); - InjectedScriptHost.copyNode(nodeId); - } else - InjectedScriptHost.copyText(object); + if (injectedScript._type(object) === "node") + object = object.outerHTML; + InjectedScriptHost.copyText(object); }, clear: function() diff --git a/WebCore/inspector/front-end/NetworkItemView.js b/WebCore/inspector/front-end/NetworkItemView.js new file mode 100644 index 0000000..48e3b19 --- /dev/null +++ b/WebCore/inspector/front-end/NetworkItemView.js @@ -0,0 +1,91 @@ +/* + * 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.NetworkItemView = function(resource) +{ + WebInspector.View.call(this); + + this.element.addStyleClass("network-item-view"); + + this._headersView = new WebInspector.ResourceHeadersView(resource); + // Do not store reference to content view - it can be recreated. + var contentView = WebInspector.ResourceManager.resourceViewForResource(resource); + + this._tabbedPane = new WebInspector.TabbedPane(this.element); + this._tabbedPane.appendTab("headers", WebInspector.UIString("Headers"), this._headersView); + if (contentView.hasContent()) { + // Reusing this view, so hide it at first. + contentView.visible = false; + this._tabbedPane.appendTab("content", WebInspector.UIString("Content"), contentView); + } + if (Preferences.showCookiesTab) { + this._cookiesView = new WebInspector.ResourceCookiesView(resource); + this._tabbedPane.appendTab("cookies", WebInspector.UIString("Cookies"), this._cookiesView); + } + if (Preferences.showTimingTab) { + var timingView = new WebInspector.ResourceTimingView(resource); + this._tabbedPane.appendTab("timing", WebInspector.UIString("Timing"), timingView); + } + + this._tabbedPane.addEventListener("tab-selected", this._tabSelected, this); +} + +WebInspector.NetworkItemView.prototype = { + show: function(parentElement) + { + WebInspector.View.prototype.show.call(this, parentElement); + this._selectTab(); + }, + + _selectTab: function(tabId) + { + if (!tabId) + tabId = WebInspector.settings.resourceViewTab; + + if (!this._tabbedPane.selectTab(tabId)) { + this._isInFallbackSelection = true; + this._tabbedPane.selectTab("headers"); + delete this._isInFallbackSelection; + } + }, + + _tabSelected: function(event) + { + WebInspector.settings.resourceViewTab = event.data.tabId; + }, + + resize: function() + { + if (this._cookiesView && this._cookiesView.visible) + this._cookiesView.resize(); + } +} + +WebInspector.NetworkItemView.prototype.__proto__ = WebInspector.View.prototype; diff --git a/WebCore/inspector/front-end/NetworkPanel.js b/WebCore/inspector/front-end/NetworkPanel.js index a695167..8f3cfd6 100644 --- a/WebCore/inspector/front-end/NetworkPanel.js +++ b/WebCore/inspector/front-end/NetworkPanel.js @@ -1,7 +1,7 @@ /* * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2008, 2009 Anthony Ricaud <rik@webkit.org> - * Copyright (C) 2009, 2010 Google Inc. All rights reserved. + * 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 @@ -72,6 +72,8 @@ WebInspector.NetworkPanel = function() this._setLargerResources(WebInspector.settings.resourcesLargeRows); this._popoverHelper = new WebInspector.PopoverHelper(this.element, this._getPopoverAnchor.bind(this), this._showPopover.bind(this), true); + // Enable faster hint. + this._popoverHelper.setTimeout(100); this.calculator = new WebInspector.NetworkTransferTimeCalculator(); this._filter(this._filterAllElement, false); @@ -641,27 +643,11 @@ WebInspector.NetworkPanel.prototype = { show: function() { WebInspector.Panel.prototype.show.call(this); - this._refreshIfNeeded(); - var visibleView = this.visibleView; - if (this.visibleResource) { - this.visibleView.headersVisible = true; + if (this.visibleView) this.visibleView.show(this._viewsContainerElement); - } else if (visibleView) - visibleView.show(); - // Hide any views that are visible that are not this panel's current visible view. - // This can happen when a ResourceView is visible in the Scripts panel then switched - // to the this panel. - var resourcesLength = this._resources.length; - for (var i = 0; i < resourcesLength; ++i) { - var resource = this._resources[i]; - var view = resource._resourcesView; - if (!view || view === visibleView) - continue; - view.visible = false; - } this._dataGrid.updateWidths(); this._positionSummaryBar(); }, @@ -696,13 +682,6 @@ WebInspector.NetworkPanel.prototype = { WebInspector.Panel.prototype.performSearch.call(this, query); }, - get visibleView() - { - if (this.visibleResource) - return this.visibleResource._resourcesView; - return null; - }, - refresh: function() { this._needsRefresh = false; @@ -813,28 +792,20 @@ WebInspector.NetworkPanel.prototype = { this._staleResources.push(resource); this._scheduleRefresh(); - - if (!resource || !resource._resourcesView) + + if (!resource) return; - if (WebInspector.ResourceManager.resourceViewTypeMatchesResource(resource, resource._resourcesView)) + var oldView = WebInspector.ResourceManager.existingResourceViewForResource(resource); + if (!oldView) return; - var newView = WebInspector.ResourceManager.createResourceView(resource); - - var oldView = resource._resourcesView; - var oldViewParentNode = oldView.visible ? oldView.element.parentNode : null; - resource._resourcesView.detach(); - delete resource._resourcesView; - - resource._resourcesView = newView; - - newView.headersVisible = oldView.headersVisible; - - if (oldViewParentNode) - newView.show(oldViewParentNode); + if (WebInspector.ResourceManager.resourceViewTypeMatchesResource(resource)) + return; - WebInspector.panels.scripts.viewRecreated(oldView, newView); + var newView = WebInspector.ResourceManager.recreateResourceView(resource); + if (this.visibleView === oldView) + this.visibleView = newView; }, canShowSourceLine: function(url, line) @@ -856,22 +827,15 @@ WebInspector.NetworkPanel.prototype = { this._toggleViewingResourceMode(); - if (this.visibleResource && this.visibleResource._resourcesView) - this.visibleResource._resourcesView.hide(); + if (this.visibleView) { + this.visibleView.detach(); + delete this.visibleView; + } - var view = WebInspector.ResourceManager.resourceViewForResource(resource); - view.headersVisible = true; + var view = new WebInspector.NetworkItemView(resource); view.show(this._viewsContainerElement); + this.visibleView = view; - if (line) { - view.selectContentTab(); - if (view.revealLine) - view.revealLine(line); - if (view.highlightLine) - view.highlightLine(line); - } - - this.visibleResource = resource; this.updateSidebarWidth(); }, @@ -879,9 +843,10 @@ WebInspector.NetworkPanel.prototype = { { this.element.removeStyleClass("viewing-resource"); - if (this.visibleResource && this.visibleResource._resourcesView) - this.visibleResource._resourcesView.hide(); - delete this.visibleResource; + if (this.visibleView) { + this.visibleView.detach(); + delete this.visibleView; + } if (this._lastSelectedGraphTreeElement) this._lastSelectedGraphTreeElement.select(true); @@ -923,87 +888,8 @@ WebInspector.NetworkPanel.prototype = { _showPopover: function(anchor) { - var tableElement = document.createElement("table"); var resource = anchor.parentElement.resource; - var rows = []; - - function addRow(title, start, end, color) - { - var row = {}; - row.title = title; - row.start = start; - row.end = end; - rows.push(row); - } - - if (resource.timing.proxyStart !== -1) - addRow(WebInspector.UIString("Proxy"), resource.timing.proxyStart, resource.timing.proxyEnd); - - if (resource.timing.dnsStart !== -1) - addRow(WebInspector.UIString("DNS Lookup"), resource.timing.dnsStart, resource.timing.dnsEnd); - - if (resource.timing.connectStart !== -1) { - if (resource.connectionReused) - addRow(WebInspector.UIString("Blocking"), resource.timing.connectStart, resource.timing.connectEnd); - else { - var connectStart = resource.timing.connectStart; - // Connection includes DNS, subtract it here. - if (resource.timing.dnsStart !== -1) - connectStart += resource.timing.dnsEnd - resource.timing.dnsStart; - addRow(WebInspector.UIString("Connecting"), connectStart, resource.timing.connectEnd); - } - } - - if (resource.timing.sslStart !== -1) - addRow(WebInspector.UIString("SSL"), resource.timing.sslStart, resource.timing.sslEnd); - - var sendStart = resource.timing.sendStart; - if (resource.timing.sslStart !== -1) - sendStart += resource.timing.sslEnd - resource.timing.sslStart; - - addRow(WebInspector.UIString("Sending"), resource.timing.sendStart, resource.timing.sendEnd); - addRow(WebInspector.UIString("Waiting"), resource.timing.sendEnd, resource.timing.receiveHeadersEnd); - addRow(WebInspector.UIString("Receiving"), (resource.responseReceivedTime - resource.timing.requestTime) * 1000, (resource.endTime - resource.timing.requestTime) * 1000); - - const chartWidth = 200; - var total = (resource.endTime - resource.timing.requestTime) * 1000; - var scale = chartWidth / total; - - for (var i = 0; i < rows.length; ++i) { - var tr = document.createElement("tr"); - tableElement.appendChild(tr); - - var td = document.createElement("td"); - td.textContent = rows[i].title; - tr.appendChild(td); - - td = document.createElement("td"); - td.width = chartWidth + "px"; - - var row = document.createElement("div"); - row.className = "network-timing-row"; - td.appendChild(row); - - var bar = document.createElement("span"); - bar.className = "network-timing-bar"; - bar.style.left = scale * rows[i].start + "px"; - bar.style.right = scale * (total - rows[i].end) + "px"; - bar.style.backgroundColor = rows[i].color; - bar.textContent = "\u200B"; // Important for 0-time items to have 0 width. - row.appendChild(bar); - - var title = document.createElement("span"); - title.className = "network-timing-bar-title"; - if (total - rows[i].end < rows[i].start) - title.style.right = (scale * (total - rows[i].end) + 3) + "px"; - else - title.style.left = (scale * rows[i].start + 3) + "px"; - title.textContent = Number.millisToString(rows[i].end - rows[i].start); - row.appendChild(title); - - tr.appendChild(td); - } - + var tableElement = WebInspector.ResourceTimingView.createTimingTable(resource); var popover = new WebInspector.Popover(tableElement); popover.show(anchor); return popover; @@ -1019,6 +905,8 @@ WebInspector.NetworkPanel.prototype = { this.sidebarElement.style.right = 0; this.sidebarElement.style.removeProperty("width"); this._summaryBarElement.style.removeProperty("width"); + if (this._dataGrid.selectedNode) + this._dataGrid.selectedNode.selected = false; } if (this._briefGrid) { @@ -1388,16 +1276,19 @@ WebInspector.NetworkDataGridNode.prototype = { this._sizeCell = this._createDivInTD("size"); this._timeCell = this._createDivInTD("time"); this._createTimelineCell(); + this._nameCell.addEventListener("click", this.select.bind(this), false); }, select: function() { - WebInspector.DataGridNode.prototype.select.apply(this, arguments); this._panel._showResource(this._resource); + WebInspector.DataGridNode.prototype.select.apply(this, arguments); }, get selectable() { + if (!this._panel._viewingResourceMode) + return false; if (!this._panel._hiddenCategories.all) return true; if (this._panel._hiddenCategories[this._resource.category.name]) @@ -1419,7 +1310,6 @@ WebInspector.NetworkDataGridNode.prototype = { { this._graphElement = document.createElement("div"); this._graphElement.className = "network-graph-side"; - this._graphElement.addEventListener("mouseover", this._refreshLabelPositions.bind(this), false); this._barAreaElement = document.createElement("div"); // this._barAreaElement.className = "network-graph-bar-area hidden"; @@ -1435,6 +1325,7 @@ WebInspector.NetworkDataGridNode.prototype = { this._barRightElement.className = "network-graph-bar"; this._barAreaElement.appendChild(this._barRightElement); + this._labelLeftElement = document.createElement("div"); this._labelLeftElement.className = "network-graph-label waiting"; this._barAreaElement.appendChild(this._labelLeftElement); @@ -1443,6 +1334,8 @@ WebInspector.NetworkDataGridNode.prototype = { this._labelRightElement.className = "network-graph-label"; this._barAreaElement.appendChild(this._labelRightElement); + this._graphElement.addEventListener("mouseover", this._refreshLabelPositions.bind(this), false); + this._timelineCell = document.createElement("td"); this._timelineCell.className = "timeline-column"; this._element.appendChild(this._timelineCell); @@ -1529,6 +1422,14 @@ WebInspector.NetworkDataGridNode.prototype = { { this._statusCell.removeChildren(); + var fromCache = this._resource.cached; + if (fromCache) { + this._statusCell.textContent = WebInspector.UIString("(from cache)"); + this._statusCell.addStyleClass("network-dim-cell"); + return; + } + + this._statusCell.removeStyleClass("network-dim-cell"); if (this._resource.statusCode) { this._statusCell.appendChild(document.createTextNode(this._resource.statusCode)); this._statusCell.removeStyleClass("network-dim-cell"); @@ -1577,8 +1478,6 @@ WebInspector.NetworkDataGridNode.prototype = { refreshGraph: function(calculator) { var percentages = calculator.computeBarGraphPercentages(this._resource); - var labels = calculator.computeBarGraphLabels(this._resource); - this._percentages = percentages; this._barAreaElement.removeStyleClass("hidden"); @@ -1594,6 +1493,7 @@ WebInspector.NetworkDataGridNode.prototype = { this._barLeftElement.style.setProperty("right", (100 - percentages.end) + "%"); this._barRightElement.style.setProperty("left", percentages.middle + "%"); + var labels = calculator.computeBarGraphLabels(this._resource); this._labelLeftElement.textContent = labels.left; this._labelRightElement.textContent = labels.right; diff --git a/WebCore/inspector/front-end/Popover.js b/WebCore/inspector/front-end/Popover.js index 59b48f9..32535e9 100644 --- a/WebCore/inspector/front-end/Popover.js +++ b/WebCore/inspector/front-end/Popover.js @@ -155,9 +155,15 @@ WebInspector.PopoverHelper = function(panelElement, getAnchor, showPopup, showOn this._onHide = onHide; panelElement.addEventListener("mousedown", this._mouseDown.bind(this), false); panelElement.addEventListener("mousemove", this._mouseMove.bind(this), false); + this.setTimeout(1000); } WebInspector.PopoverHelper.prototype = { + setTimeout: function(timeout) + { + this._timeout = timeout; + }, + _mouseDown: function(event) { this._killHidePopupTimer(); @@ -170,7 +176,7 @@ WebInspector.PopoverHelper.prototype = { if (this._hoverElement === event.target || (this._hoverElement && this._hoverElement.isAncestor(event.target))) return; - // User has 500ms to reach the popup. + // User has 500ms (this._timeout / 2) to reach the popup. if (this._popup && !this._hidePopupTimer) { var self = this; function doHide() @@ -178,7 +184,7 @@ WebInspector.PopoverHelper.prototype = { self._hidePopup(); delete self._hidePopupTimer; } - this._hidePopupTimer = setTimeout(doHide, 500); + this._hidePopupTimer = setTimeout(doHide, this._timeout / 2); } this._handleMouseAction(event); @@ -192,7 +198,7 @@ WebInspector.PopoverHelper.prototype = { if (!this._hoverElement) return; - const toolTipDelay = isMouseDown ? 0 : (this._popup ? 600 : 1000); + const toolTipDelay = isMouseDown ? 0 : (this._popup ? this._timeout * 0.6 : this._timeout); this._hoverTimer = setTimeout(this._mouseHover.bind(this, this._hoverElement), toolTipDelay); }, diff --git a/WebCore/inspector/front-end/ProfilesPanel.js b/WebCore/inspector/front-end/ProfilesPanel.js index 0aa4174..50795e8 100644 --- a/WebCore/inspector/front-end/ProfilesPanel.js +++ b/WebCore/inspector/front-end/ProfilesPanel.js @@ -123,6 +123,7 @@ WebInspector.ProfilesPanel = function() this._profiles = []; this._profilerEnabled = Preferences.profilerAlwaysEnabled; + this._tempHeapSnapshots = []; this._reset(); } @@ -411,6 +412,25 @@ WebInspector.ProfilesPanel.prototype = { } }, + addHeapSnapshotChunk: function(uid, chunk) + { + if (this._tempHeapSnapshots[uid]) + this._tempHeapSnapshots[uid] += chunk; + else + this._tempHeapSnapshots[uid] = chunk; + }, + + finishHeapSnapshot: function(uid) + { + var profile = + this._profilesIdMap[this._makeKey(uid, WebInspector.HeapSnapshotProfileType.TypeId)]; + if (profile) { + var view = profile.__profilesPanelProfileType.viewForProfile(profile); + view.snapshotLoaded(uid, JSON.parse(this._tempHeapSnapshots[uid])); + } + delete this._tempHeapSnapshots[uid]; + }, + showView: function(view) { this.showProfile(view.profile); diff --git a/WebCore/inspector/front-end/Resource.js b/WebCore/inspector/front-end/Resource.js index 24af165..aefdd6c 100644 --- a/WebCore/inspector/front-end/Resource.js +++ b/WebCore/inspector/front-end/Resource.js @@ -163,11 +163,6 @@ WebInspector.Resource.prototype = { get responseReceivedTime() { - if (this.timing && this.timing.requestTime) { - // Calculate responseReceivedTime from timing data for better accuracy. - // Timing's requestTime is a baseline in seconds, rest of the numbers there are ticks in millis. - return this.timing.requestTime + this.timing.receiveHeadersEnd / 1000.0; - } return this._responseReceivedTime || -1; }, @@ -183,13 +178,15 @@ WebInspector.Resource.prototype = { set endTime(x) { - // In case of fast load (or in case of cached resources), endTime on network stack - // can be less then m_responseReceivedTime measured in WebCore. Normalize it here, - // prefer actualEndTime to m_responseReceivedTime. - if (x < this.responseReceivedTime) - this.responseReceivedTime = x; - - this._endTime = x; + if (this.timing && this.timing.requestTime) { + // Check against accurate responseReceivedTime. + this._endTime = Math.max(x, this.responseReceivedTime); + } else { + // Prefer endTime since it might be from the network stack. + this._endTime = x; + if (this._responseReceivedTime > x) + this._responseReceivedTime = x; + } }, get duration() @@ -299,8 +296,15 @@ WebInspector.Resource.prototype = { set timing(x) { - if (!this._cached) + if (x && !this._cached) { + // Take startTime and responseReceivedTime from timing data for better accuracy. + // Timing's requestTime is a baseline in seconds, rest of the numbers there are ticks in millis. + this._startTime = x.requestTime; + this._responseReceivedTime = x.requestTime + x.receiveHeadersEnd / 1000.0; + this._timing = x; + this.dispatchEventToListeners("timing changed"); + } }, get mimeType() @@ -621,11 +625,71 @@ WebInspector.Resource.prototype = { return this._content; }, - set content(content) + get contentTimestamp() + { + return this._contentTimestamp; + }, + + setInitialContent: function(content) { this._content = content; }, + isLocallyModified: function() + { + return !!this._baseRevision; + }, + + setContent: function(newContent, onRevert) + { + var revisionResource = new WebInspector.Resource(null, this.url); + revisionResource.type = this.type; + revisionResource.loader = this.loader; + revisionResource.timestamp = this.timestamp; + revisionResource._content = this._content; + revisionResource._actualResource = this; + revisionResource._fireOnRevert = onRevert; + + if (this.finished) + revisionResource.finished = true; + else { + function finished() + { + this.removeEventListener("finished", finished); + revisionResource.finished = true; + } + this.addEventListener("finished", finished.bind(this)); + } + + if (!this._baseRevision) + this._baseRevision = revisionResource; + else + revisionResource._baseRevision = this._baseRevision; + + var data = { revision: revisionResource }; + this._content = newContent; + this.timestamp = new Date(); + this.dispatchEventToListeners("content-changed", data); + }, + + revertToThis: function() + { + if (!this._actualResource || !this._fireOnRevert) + return; + + function callback(content) + { + if (content) + this._fireOnRevert(content); + } + this.requestContent(callback.bind(this)); + }, + + get baseRevision() + { + return this._baseRevision; + }, + requestContent: function(callback) { if (this._content) { diff --git a/WebCore/inspector/front-end/ResourceCookiesView.js b/WebCore/inspector/front-end/ResourceCookiesView.js new file mode 100644 index 0000000..e419070 --- /dev/null +++ b/WebCore/inspector/front-end/ResourceCookiesView.js @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2009, 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.ResourceCookiesView = function(resource) +{ + WebInspector.View.call(this); + this.element.addStyleClass("resource-cookies-view"); + + this._resource = resource; + + resource.addEventListener("requestHeaders changed", this.show, this); + resource.addEventListener("responseHeaders changed", this.show, this); +} + +WebInspector.ResourceCookiesView.prototype = { + show: function(parentElement) + { + if (!this._resource.requestCookies && !this._resource.responseCookies) { + if (!this._emptyMsgElement) { + this._emptyMsgElement = document.createElement("div"); + this._emptyMsgElement.className = "storage-empty-view"; + this._emptyMsgElement.textContent = WebInspector.UIString("This request has no cookies."); + this.element.appendChild(this._emptyMsgElement); + } + WebInspector.View.prototype.show.call(this, parentElement); + return; + } + + if (this._emptyMsgElement) + this._emptyMsgElement.parentElement.removeChild(this._emptyMsgElement); + + this._cookiesTable = new WebInspector.CookiesTable(null, true, true); + this._cookiesTable.addCookiesFolder(WebInspector.UIString("Request Cookies"), this._resource.requestCookies); + this._cookiesTable.addCookiesFolder(WebInspector.UIString("Response Cookies"), this._resource.responseCookies); + this.element.appendChild(this._cookiesTable.element); + + WebInspector.View.prototype.show.call(this, parentElement); + this._cookiesTable.updateWidths(); + } +} + +WebInspector.ResourceCookiesView.prototype.__proto__ = WebInspector.View.prototype; diff --git a/WebCore/inspector/front-end/ResourceHeadersView.js b/WebCore/inspector/front-end/ResourceHeadersView.js new file mode 100644 index 0000000..ee1010f --- /dev/null +++ b/WebCore/inspector/front-end/ResourceHeadersView.js @@ -0,0 +1,276 @@ +/* + * Copyright (C) 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) IBM Corp. 2009 All rights reserved. + * 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: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY + * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND + * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +WebInspector.ResourceHeadersView = function(resource) +{ + WebInspector.View.call(this); + this.element.addStyleClass("resource-headers-view"); + + this._resource = resource; + + this._headersListElement = document.createElement("ol"); + this._headersListElement.className = "outline-disclosure"; + this.element.appendChild(this._headersListElement); + + this._headersTreeOutline = new TreeOutline(this._headersListElement); + this._headersTreeOutline.expandTreeElementsWhenArrowing = true; + + this._urlTreeElement = new TreeElement("", null, false); + this._urlTreeElement.selectable = false; + this._headersTreeOutline.appendChild(this._urlTreeElement); + + this._requestMethodTreeElement = new TreeElement("", null, false); + this._requestMethodTreeElement.selectable = false; + this._headersTreeOutline.appendChild(this._requestMethodTreeElement); + + this._statusCodeTreeElement = new TreeElement("", null, false); + this._statusCodeTreeElement.selectable = false; + this._headersTreeOutline.appendChild(this._statusCodeTreeElement); + + this._requestHeadersTreeElement = new TreeElement("", null, true); + this._requestHeadersTreeElement.expanded = true; + this._requestHeadersTreeElement.selectable = false; + this._headersTreeOutline.appendChild(this._requestHeadersTreeElement); + + this._decodeHover = WebInspector.UIString("Double-Click to toggle between URL encoded and decoded formats"); + this._decodeRequestParameters = true; + + this._queryStringTreeElement = new TreeElement("", null, true); + this._queryStringTreeElement.expanded = true; + this._queryStringTreeElement.selectable = false; + this._queryStringTreeElement.hidden = true; + this._headersTreeOutline.appendChild(this._queryStringTreeElement); + + this._formDataTreeElement = new TreeElement("", null, true); + this._formDataTreeElement.expanded = true; + this._formDataTreeElement.selectable = false; + this._formDataTreeElement.hidden = true; + this._headersTreeOutline.appendChild(this._formDataTreeElement); + + this._requestPayloadTreeElement = new TreeElement(WebInspector.UIString("Request Payload"), null, true); + this._requestPayloadTreeElement.expanded = true; + this._requestPayloadTreeElement.selectable = false; + this._requestPayloadTreeElement.hidden = true; + this._headersTreeOutline.appendChild(this._requestPayloadTreeElement); + + this._responseHeadersTreeElement = new TreeElement("", null, true); + this._responseHeadersTreeElement.expanded = true; + this._responseHeadersTreeElement.selectable = false; + this._headersTreeOutline.appendChild(this._responseHeadersTreeElement); + + resource.addEventListener("requestHeaders changed", this._refreshRequestHeaders, this); + resource.addEventListener("responseHeaders changed", this._refreshResponseHeaders, this); + resource.addEventListener("finished", this._refreshHTTPInformation, this); + + this._refreshURL(); + this._refreshQueryString(); + this._refreshRequestHeaders(); + this._refreshResponseHeaders(); + this._refreshHTTPInformation(); +} + +WebInspector.ResourceHeadersView.prototype = { + + _refreshURL: function() + { + this._urlTreeElement.titleHTML = "<div class=\"header-name\">" + WebInspector.UIString("Request URL") + ":</div>" + + "<div class=\"header-value source-code\">" + this._resource.url.escapeHTML() + "</div>"; + }, + + _refreshQueryString: function() + { + var queryParameters = this._resource.queryParameters; + this._queryStringTreeElement.hidden = !queryParameters; + if (queryParameters) + this._refreshParms(WebInspector.UIString("Query String Parameters"), queryParameters, this._queryStringTreeElement); + }, + + _refreshFormData: function() + { + this._formDataTreeElement.hidden = true; + this._requestPayloadTreeElement.hidden = true; + + var formData = this._resource.requestFormData; + if (!formData) + return; + + var formParameters = this._resource.formParameters; + if (formParameters) { + this._formDataTreeElement.hidden = false; + this._refreshParms(WebInspector.UIString("Form Data"), formParameters, this._formDataTreeElement); + } else { + this._requestPayloadTreeElement.hidden = false; + this._refreshRequestPayload(formData); + } + }, + + _refreshRequestPayload: function(formData) + { + this._requestPayloadTreeElement.removeChildren(); + + var title = "<div class=\"raw-form-data header-value source-code\">" + formData.escapeHTML() + "</div>"; + var parmTreeElement = new TreeElement(null, null, false); + parmTreeElement.titleHTML = title; + parmTreeElement.selectable = false; + this._requestPayloadTreeElement.appendChild(parmTreeElement); + }, + + _refreshParms: function(title, parms, parmsTreeElement) + { + parmsTreeElement.removeChildren(); + + parmsTreeElement.titleHTML = title + "<span class=\"header-count\">" + WebInspector.UIString(" (%d)", parms.length) + "</span>"; + + for (var i = 0; i < parms.length; ++i) { + var name = parms[i].name; + var value = parms[i].value; + + var errorDecoding = false; + if (this._decodeRequestParameters) { + if (value.indexOf("%") >= 0) { + try { + value = decodeURIComponent(value); + } catch(e) { + errorDecoding = true; + } + } + + value = value.replace(/\+/g, " "); + } + + valueEscaped = value.escapeHTML(); + if (errorDecoding) + valueEscaped += " <span class=\"error-message\">" + WebInspector.UIString("(unable to decode value)").escapeHTML() + "</span>"; + + var title = "<div class=\"header-name\">" + name.escapeHTML() + ":</div>"; + title += "<div class=\"header-value source-code\">" + valueEscaped + "</div>"; + + var parmTreeElement = new TreeElement(null, null, false); + parmTreeElement.titleHTML = title; + parmTreeElement.selectable = false; + parmTreeElement.tooltip = this._decodeHover; + parmTreeElement.ondblclick = this._toggleURLdecoding.bind(this); + parmsTreeElement.appendChild(parmTreeElement); + } + }, + + _toggleURLdecoding: function(event) + { + this._decodeRequestParameters = !this._decodeRequestParameters; + this._refreshQueryString(); + this._refreshFormData(); + }, + + _getHeaderValue: function(headers, key) + { + var lowerKey = key.toLowerCase(); + for (var testKey in headers) { + if (testKey.toLowerCase() === lowerKey) + return headers[testKey]; + } + }, + + _refreshRequestHeaders: function() + { + var additionalRow = null; + if (typeof this._resource.webSocketRequestKey3 !== "undefined") + additionalRow = {header: "(Key3)", value: this._resource.webSocketRequestKey3}; + this._refreshHeaders(WebInspector.UIString("Request Headers"), this._resource.sortedRequestHeaders, additionalRow, this._requestHeadersTreeElement); + this._refreshFormData(); + }, + + _refreshResponseHeaders: function() + { + var additionalRow = null; + if (typeof this._resource.webSocketChallengeResponse !== "undefined") + additionalRow = {header: "(Challenge Response)", value: this._resource.webSocketChallengeResponse}; + this._refreshHeaders(WebInspector.UIString("Response Headers"), this._resource.sortedResponseHeaders, additionalRow, this._responseHeadersTreeElement); + }, + + _refreshHTTPInformation: function() + { + var requestMethodElement = this._requestMethodTreeElement; + requestMethodElement.hidden = !this._resource.statusCode; + var statusCodeElement = this._statusCodeTreeElement; + statusCodeElement.hidden = !this._resource.statusCode; + var statusCodeImage = ""; + + if (this._resource.statusCode) { + var statusImageSource = ""; + if (this._resource.statusCode < 300) + statusImageSource = "Images/successGreenDot.png"; + else if (this._resource.statusCode < 400) + statusImageSource = "Images/warningOrangeDot.png"; + else + statusImageSource = "Images/errorRedDot.png"; + + var statusTextEscaped = this._resource.statusCode + " " + this._resource.statusText.escapeHTML(); + statusCodeImage = "<img class=\"resource-status-image\" src=\"" + statusImageSource + "\" title=\"" + statusTextEscaped + "\">"; + + requestMethodElement.titleHTML = "<div class=\"header-name\">" + WebInspector.UIString("Request Method") + ":</div>" + + "<div class=\"header-value source-code\">" + this._resource.requestMethod + "</div>"; + + statusCodeElement.titleHTML = "<div class=\"header-name\">" + WebInspector.UIString("Status Code") + ":</div>" + + statusCodeImage + "<div class=\"header-value source-code\">" + statusTextEscaped + "</div>"; + } + }, + + _refreshHeaders: function(title, headers, additionalRow, headersTreeElement) + { + headersTreeElement.removeChildren(); + + var length = headers.length; + headersTreeElement.titleHTML = title.escapeHTML() + "<span class=\"header-count\">" + WebInspector.UIString(" (%d)", length) + "</span>"; + headersTreeElement.hidden = !length; + + var length = headers.length; + for (var i = 0; i < length; ++i) { + var title = "<div class=\"header-name\">" + headers[i].header.escapeHTML() + ":</div>"; + title += "<div class=\"header-value source-code\">" + headers[i].value.escapeHTML() + "</div>" + + var headerTreeElement = new TreeElement(null, null, false); + headerTreeElement.titleHTML = title; + headerTreeElement.selectable = false; + headersTreeElement.appendChild(headerTreeElement); + } + + if (additionalRow) { + var title = "<div class=\"header-name\">" + additionalRow.header.escapeHTML() + ":</div>"; + title += "<div class=\"header-value source-code\">" + additionalRow.value.escapeHTML() + "</div>" + + var headerTreeElement = new TreeElement(null, null, false); + headerTreeElement.titleHTML = title; + headerTreeElement.selectable = false; + headersTreeElement.appendChild(headerTreeElement); + } + } +} + +WebInspector.ResourceHeadersView.prototype.__proto__ = WebInspector.View.prototype; diff --git a/WebCore/inspector/front-end/ResourceManager.js b/WebCore/inspector/front-end/ResourceManager.js index 223e435..056be8c 100644 --- a/WebCore/inspector/front-end/ResourceManager.js +++ b/WebCore/inspector/front-end/ResourceManager.js @@ -39,7 +39,7 @@ WebInspector.ResourceManager = function() "didFinishLoading", "didFailLoading", "didLoadResourceFromMemoryCache", - "setOverrideContent", + "setInitialContent", "didCommitLoadForFrame", "frameDetachedFromParent", "didCreateWebSocket", @@ -141,9 +141,11 @@ WebInspector.ResourceManager.prototype = { var resource = this._resourcesById[identifier]; if (!resource) return; - this._updateResourceWithResponse(resource, response); - resource.type = WebInspector.Resource.Type[resourceType]; + resource.responseReceivedTime = time; + resource.type = WebInspector.Resource.Type[resourceType]; + + this._updateResourceWithResponse(resource, response); WebInspector.panels.network.refreshResource(resource); this._resourceTreeModel.addResourceToFrame(resource.loader.frameId, resource); @@ -170,9 +172,13 @@ WebInspector.ResourceManager.prototype = { else resource.timing = response.timing; - if (response.rawHeaders) { - resource.requestHeaders = response.rawHeaders.requestHeaders; - resource.responseHeaders = response.rawHeaders.responseHeaders; + if (response.loadInfo) { + if (response.loadInfo.httpStatusCode) + resource.statusCode = response.loadInfo.httpStatusCode; + if (response.loadInfo.httpStatusText) + resource.statusText = response.loadInfo.httpStatusText; + resource.requestHeaders = response.loadInfo.requestHeaders; + resource.responseHeaders = response.loadInfo.responseHeaders; } }, @@ -194,8 +200,8 @@ WebInspector.ResourceManager.prototype = { if (!resource) return; - resource.finished = true; resource.endTime = finishTime; + resource.finished = true; WebInspector.panels.network.refreshResource(resource); WebInspector.panels.audits.resourceFinished(resource); @@ -242,14 +248,14 @@ WebInspector.ResourceManager.prototype = { this._updateResourceWithResponse(resource, cachedResource.response); }, - setOverrideContent: function(identifier, sourceString, type) + setInitialContent: function(identifier, sourceString, type) { var resource = WebInspector.panels.network.resources[identifier]; if (!resource) return; resource.type = WebInspector.Resource.Type[type]; - resource.content = sourceString; + resource.setInitialContent(sourceString); WebInspector.panels.resources.refreshResource(resource); WebInspector.panels.network.refreshResource(resource); }, @@ -441,8 +447,9 @@ WebInspector.ResourceManager.createResourceView = function(resource) } } -WebInspector.ResourceManager.resourceViewTypeMatchesResource = function(resource, resourceView) +WebInspector.ResourceManager.resourceViewTypeMatchesResource = function(resource) { + var resourceView = resource._resourcesView; switch (resource.category) { case WebInspector.resourceCategories.documents: case WebInspector.resourceCategories.stylesheets: @@ -467,6 +474,28 @@ WebInspector.ResourceManager.resourceViewForResource = function(resource) return resource._resourcesView; } +WebInspector.ResourceManager.recreateResourceView = function(resource) +{ + var newView = WebInspector.ResourceManager.createResourceView(resource); + + var oldView = resource._resourcesView; + var oldViewParentNode = oldView.visible ? oldView.element.parentNode : null; + var scrollTop = oldView.scrollTop; + + resource._resourcesView.detach(); + delete resource._resourcesView; + + resource._resourcesView = newView; + + if (oldViewParentNode) + newView.show(oldViewParentNode); + if (scrollTop) + newView.scrollTop = scrollTop; + + WebInspector.panels.scripts.viewRecreated(oldView, newView); + return newView; +} + WebInspector.ResourceManager.existingResourceViewForResource = function(resource) { if (!resource) diff --git a/WebCore/inspector/front-end/ResourceTimingView.js b/WebCore/inspector/front-end/ResourceTimingView.js new file mode 100644 index 0000000..04f22f8 --- /dev/null +++ b/WebCore/inspector/front-end/ResourceTimingView.js @@ -0,0 +1,157 @@ +/* + * 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.ResourceTimingView = function(resource) +{ + WebInspector.View.call(this); + this.element.addStyleClass("resource-timing-view"); + + this._resource = resource; + + resource.addEventListener("timing changed", this._refresh, this); +} + +WebInspector.ResourceTimingView.prototype = { + show: function(parentElement) + { + if (!this._resource.timing) { + if (!this._emptyMsgElement) { + this._emptyMsgElement = document.createElement("div"); + this._emptyMsgElement.className = "storage-empty-view"; + this._emptyMsgElement.textContent = WebInspector.UIString("This request has no detailed timing info."); + this.element.appendChild(this._emptyMsgElement); + } + WebInspector.View.prototype.show.call(this, parentElement); + return; + } + + if (this._emptyMsgElement) + this._emptyMsgElement.parentElement.removeChild(this._emptyMsgElement); + + this._refresh(); + WebInspector.View.prototype.show.call(this, parentElement); + }, + + _refresh: function() + { + if (this._tableElement) + this._tableElement.parentElement.removeChild(this._tableElement); + + this._tableElement = WebInspector.ResourceTimingView.createTimingTable(this._resource); + this.element.appendChild(this._tableElement); + } +} + +WebInspector.ResourceTimingView.createTimingTable = function(resource) +{ + var tableElement = document.createElement("table"); + var rows = []; + + function addRow(title, className, start, end, color) + { + var row = {}; + row.title = title; + row.className = className; + row.start = start; + row.end = end; + rows.push(row); + } + + if (resource.timing.proxyStart !== -1) + addRow(WebInspector.UIString("Proxy"), "proxy", resource.timing.proxyStart, resource.timing.proxyEnd); + + if (resource.timing.dnsStart !== -1) + addRow(WebInspector.UIString("DNS Lookup"), "dns", resource.timing.dnsStart, resource.timing.dnsEnd); + + if (resource.timing.connectStart !== -1) { + if (resource.connectionReused) + addRow(WebInspector.UIString("Blocking"), "connecting", resource.timing.connectStart, resource.timing.connectEnd); + else { + var connectStart = resource.timing.connectStart; + // Connection includes DNS, subtract it here. + if (resource.timing.dnsStart !== -1) + connectStart += resource.timing.dnsEnd - resource.timing.dnsStart; + addRow(WebInspector.UIString("Connecting"), "connecting", connectStart, resource.timing.connectEnd); + } + } + + if (resource.timing.sslStart !== -1) + addRow(WebInspector.UIString("SSL"), "ssl", resource.timing.sslStart, resource.timing.sslEnd); + + var sendStart = resource.timing.sendStart; + if (resource.timing.sslStart !== -1) + sendStart += resource.timing.sslEnd - resource.timing.sslStart; + + addRow(WebInspector.UIString("Sending"), "sending", resource.timing.sendStart, resource.timing.sendEnd); + addRow(WebInspector.UIString("Waiting"), "waiting", resource.timing.sendEnd, resource.timing.receiveHeadersEnd); + addRow(WebInspector.UIString("Receiving"), "receiving", (resource.responseReceivedTime - resource.timing.requestTime) * 1000, (resource.endTime - resource.timing.requestTime) * 1000); + + const chartWidth = 200; + var total = (resource.endTime - resource.timing.requestTime) * 1000; + var scale = chartWidth / total; + + for (var i = 0; i < rows.length; ++i) { + var tr = document.createElement("tr"); + tableElement.appendChild(tr); + + var td = document.createElement("td"); + td.textContent = rows[i].title; + tr.appendChild(td); + + td = document.createElement("td"); + td.width = chartWidth + "px"; + + var row = document.createElement("div"); + row.className = "network-timing-row"; + td.appendChild(row); + + var bar = document.createElement("span"); + bar.className = "network-timing-bar " + rows[i].className; + bar.style.left = scale * rows[i].start + "px"; + bar.style.right = scale * (total - rows[i].end) + "px"; + bar.style.backgroundColor = rows[i].color; + bar.textContent = "\u200B"; // Important for 0-time items to have 0 width. + row.appendChild(bar); + + var title = document.createElement("span"); + title.className = "network-timing-bar-title"; + if (total - rows[i].end < rows[i].start) + title.style.right = (scale * (total - rows[i].end) + 3) + "px"; + else + title.style.left = (scale * rows[i].start + 3) + "px"; + title.textContent = Number.millisToString(rows[i].end - rows[i].start); + row.appendChild(title); + + tr.appendChild(td); + } + return tableElement; +} + +WebInspector.ResourceTimingView.prototype.__proto__ = WebInspector.View.prototype; diff --git a/WebCore/inspector/front-end/ResourceView.js b/WebCore/inspector/front-end/ResourceView.js index 19e3052..a284da1 100644 --- a/WebCore/inspector/front-end/ResourceView.js +++ b/WebCore/inspector/front-end/ResourceView.js @@ -7,13 +7,13 @@ * are met: * * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. + * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. + * documentation and/or other materials provided with the distribution. * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of * its contributors may be used to endorse or promote products derived - * from this software without specific prior written permission. + * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED @@ -30,403 +30,15 @@ WebInspector.ResourceView = function(resource) { WebInspector.View.call(this); - this.element.addStyleClass("resource-view"); - this.resource = resource; - - this.tabbedPane = new WebInspector.TabbedPane(this.element); - - this.headersElement = document.createElement("div"); - this.headersElement.className = "resource-view-headers"; - this.tabbedPane.appendTab("headers", WebInspector.UIString("Headers"), this.headersElement, this._selectTab.bind(this, "headers")); - - if (this.hasContentTab()) { - this.contentElement = document.createElement("div"); - this.contentElement.className = "resource-view-content"; - this.tabbedPane.appendTab("content", WebInspector.UIString("Content"), this.contentElement, this._selectTab.bind(this, "content")); - } - - this.headersListElement = document.createElement("ol"); - this.headersListElement.className = "outline-disclosure"; - this.headersElement.appendChild(this.headersListElement); - - this.headersTreeOutline = new TreeOutline(this.headersListElement); - this.headersTreeOutline.expandTreeElementsWhenArrowing = true; - - this.urlTreeElement = new TreeElement("", null, false); - this.urlTreeElement.selectable = false; - this.headersTreeOutline.appendChild(this.urlTreeElement); - - this.requestMethodTreeElement = new TreeElement("", null, false); - this.requestMethodTreeElement.selectable = false; - this.headersTreeOutline.appendChild(this.requestMethodTreeElement); - - this.statusCodeTreeElement = new TreeElement("", null, false); - this.statusCodeTreeElement.selectable = false; - this.headersTreeOutline.appendChild(this.statusCodeTreeElement); - - this.requestHeadersTreeElement = new TreeElement("", null, true); - this.requestHeadersTreeElement.expanded = true; - this.requestHeadersTreeElement.selectable = false; - this.headersTreeOutline.appendChild(this.requestHeadersTreeElement); - - this._decodeHover = WebInspector.UIString("Double-Click to toggle between URL encoded and decoded formats"); - this._decodeRequestParameters = true; - - this.queryStringTreeElement = new TreeElement("", null, true); - this.queryStringTreeElement.expanded = true; - this.queryStringTreeElement.selectable = false; - this.queryStringTreeElement.hidden = true; - this.headersTreeOutline.appendChild(this.queryStringTreeElement); - - this.formDataTreeElement = new TreeElement("", null, true); - this.formDataTreeElement.expanded = true; - this.formDataTreeElement.selectable = false; - this.formDataTreeElement.hidden = true; - this.headersTreeOutline.appendChild(this.formDataTreeElement); - - this.requestPayloadTreeElement = new TreeElement(WebInspector.UIString("Request Payload"), null, true); - this.requestPayloadTreeElement.expanded = true; - this.requestPayloadTreeElement.selectable = false; - this.requestPayloadTreeElement.hidden = true; - this.headersTreeOutline.appendChild(this.requestPayloadTreeElement); - - this.responseHeadersTreeElement = new TreeElement("", null, true); - this.responseHeadersTreeElement.expanded = true; - this.responseHeadersTreeElement.selectable = false; - this.headersTreeOutline.appendChild(this.responseHeadersTreeElement); - - this.headersVisible = true; - - resource.addEventListener("requestHeaders changed", this._refreshRequestHeaders, this); - resource.addEventListener("responseHeaders changed", this._refreshResponseHeaders, this); - resource.addEventListener("finished", this._refreshHTTPInformation, this); - - this._refreshURL(); - this._refreshQueryString(); - this._refreshRequestHeaders(); - this._refreshResponseHeaders(); - this._refreshHTTPInformation(); - this._selectTab(); } WebInspector.ResourceView.prototype = { - attach: function() - { - if (!this.element.parentNode) { - var parentElement = (document.getElementById("resource-views") || document.getElementById("script-resource-views")); - if (parentElement) - parentElement.appendChild(this.element); - } - }, - - show: function(parentElement) - { - WebInspector.View.prototype.show.call(this, parentElement); - this._selectTab(); - }, - - set headersVisible(x) + hasContent: function() { - if (x === this._headersVisible) - return; - this._headersVisible = x; - if (x) - this.element.addStyleClass("headers-visible"); - else - this.element.removeStyleClass("headers-visible"); - this._selectTab(); - }, - - resize: function() - { - if (this._cookiesView && !this._cookiesView.element.hasStyleClass("hidden")) - this._cookiesView.resize(); - }, - - selectContentTab: function() - { - this._selectTab("content"); - }, - - _selectTab: function(tab) - { - if (tab) - WebInspector.settings.resourceViewTab = tab; - else { - var preferredTab = WebInspector.settings.resourceViewTab; - tab = "content"; - - // Honor user tab preference (if we can). Fallback to content if headers not visible, headers otherwise. - if (this._headersVisible) - tab = this.tabbedPane.hasTab(preferredTab) ? preferredTab : "headers"; - } - this.tabbedPane.selectTabById(tab); - if (tab === "content" && this.hasContentTab()) - this.contentTabSelected(); - }, - - hasContentTab: function() - { - // Derived classes should override this method and define this.contentTabSelected for content rendering. return false; - }, - - _refreshURL: function() - { - this.urlTreeElement.titleHTML = "<div class=\"header-name\">" + WebInspector.UIString("Request URL") + ":</div>" + - "<div class=\"header-value source-code\">" + this.resource.url.escapeHTML() + "</div>"; - }, - - _refreshQueryString: function() - { - var queryParameters = this.resource.queryParameters; - this.queryStringTreeElement.hidden = !queryParameters; - if (queryParameters) - this._refreshParms(WebInspector.UIString("Query String Parameters"), queryParameters, this.queryStringTreeElement); - }, - - _refreshFormData: function() - { - this.formDataTreeElement.hidden = true; - this.requestPayloadTreeElement.hidden = true; - - var formData = this.resource.requestFormData; - if (!formData) - return; - - var formParameters = this.resource.formParameters; - if (formParameters) { - this.formDataTreeElement.hidden = false; - this._refreshParms(WebInspector.UIString("Form Data"), formParameters, this.formDataTreeElement); - } else { - this.requestPayloadTreeElement.hidden = false; - this._refreshRequestPayload(formData); - } - }, - - _refreshRequestPayload: function(formData) - { - this.requestPayloadTreeElement.removeChildren(); - - var title = "<div class=\"raw-form-data header-value source-code\">" + formData.escapeHTML() + "</div>"; - var parmTreeElement = new TreeElement(null, null, false); - parmTreeElement.titleHTML = title; - parmTreeElement.selectable = false; - this.requestPayloadTreeElement.appendChild(parmTreeElement); - }, - - _refreshParms: function(title, parms, parmsTreeElement) - { - parmsTreeElement.removeChildren(); - - parmsTreeElement.titleHTML = title + "<span class=\"header-count\">" + WebInspector.UIString(" (%d)", parms.length) + "</span>"; - - for (var i = 0; i < parms.length; ++i) { - var name = parms[i].name; - var value = parms[i].value; - - var errorDecoding = false; - if (this._decodeRequestParameters) { - if (value.indexOf("%") >= 0) { - try { - value = decodeURIComponent(value); - } catch(e) { - errorDecoding = true; - } - } - - value = value.replace(/\+/g, " "); - } - - valueEscaped = value.escapeHTML(); - if (errorDecoding) - valueEscaped += " <span class=\"error-message\">" + WebInspector.UIString("(unable to decode value)").escapeHTML() + "</span>"; - - var title = "<div class=\"header-name\">" + name.escapeHTML() + ":</div>"; - title += "<div class=\"header-value source-code\">" + valueEscaped + "</div>"; - - var parmTreeElement = new TreeElement(null, null, false); - parmTreeElement.titleHTML = title; - parmTreeElement.selectable = false; - parmTreeElement.tooltip = this._decodeHover; - parmTreeElement.ondblclick = this._toggleURLdecoding.bind(this); - parmsTreeElement.appendChild(parmTreeElement); - } - }, - - _toggleURLdecoding: function(event) - { - this._decodeRequestParameters = !this._decodeRequestParameters; - this._refreshQueryString(); - this._refreshFormData(); - }, - - _getHeaderValue: function(headers, key) - { - var lowerKey = key.toLowerCase(); - for (var testKey in headers) { - if (testKey.toLowerCase() === lowerKey) - return headers[testKey]; - } - }, - - _refreshRequestHeaders: function() - { - var additionalRow = null; - if (typeof this.resource.webSocketRequestKey3 !== "undefined") - additionalRow = {header: "(Key3)", value: this.resource.webSocketRequestKey3}; - this._refreshHeaders(WebInspector.UIString("Request Headers"), this.resource.sortedRequestHeaders, additionalRow, this.requestHeadersTreeElement); - this._refreshFormData(); - this._refreshCookies(); - }, - - _refreshResponseHeaders: function() - { - var additionalRow = null; - if (typeof this.resource.webSocketChallengeResponse !== "undefined") - additionalRow = {header: "(Challenge Response)", value: this.resource.webSocketChallengeResponse}; - this._refreshHeaders(WebInspector.UIString("Response Headers"), this.resource.sortedResponseHeaders, additionalRow, this.responseHeadersTreeElement); - this._refreshCookies(); - }, - - _refreshHTTPInformation: function() - { - var requestMethodElement = this.requestMethodTreeElement; - requestMethodElement.hidden = !this.resource.statusCode; - var statusCodeElement = this.statusCodeTreeElement; - statusCodeElement.hidden = !this.resource.statusCode; - var statusCodeImage = ""; - - if (this.resource.statusCode) { - var statusImageSource = ""; - if (this.resource.statusCode < 300) - statusImageSource = "Images/successGreenDot.png"; - else if (this.resource.statusCode < 400) - statusImageSource = "Images/warningOrangeDot.png"; - else - statusImageSource = "Images/errorRedDot.png"; - - var statusTextEscaped = this.resource.statusCode + " " + this.resource.statusText.escapeHTML(); - statusCodeImage = "<img class=\"resource-status-image\" src=\"" + statusImageSource + "\" title=\"" + statusTextEscaped + "\">"; - - requestMethodElement.titleHTML = "<div class=\"header-name\">" + WebInspector.UIString("Request Method") + ":</div>" + - "<div class=\"header-value source-code\">" + this.resource.requestMethod + "</div>"; - - statusCodeElement.titleHTML = "<div class=\"header-name\">" + WebInspector.UIString("Status Code") + ":</div>" + - statusCodeImage + "<div class=\"header-value source-code\">" + statusTextEscaped + "</div>"; - } - }, - - _refreshHeaders: function(title, headers, additionalRow, headersTreeElement) - { - headersTreeElement.removeChildren(); - - var length = headers.length; - headersTreeElement.titleHTML = title.escapeHTML() + "<span class=\"header-count\">" + WebInspector.UIString(" (%d)", length) + "</span>"; - headersTreeElement.hidden = !length; - - var length = headers.length; - for (var i = 0; i < length; ++i) { - var title = "<div class=\"header-name\">" + headers[i].header.escapeHTML() + ":</div>"; - title += "<div class=\"header-value source-code\">" + headers[i].value.escapeHTML() + "</div>" - - var headerTreeElement = new TreeElement(null, null, false); - headerTreeElement.titleHTML = title; - headerTreeElement.selectable = false; - headersTreeElement.appendChild(headerTreeElement); - } - - if (additionalRow) { - var title = "<div class=\"header-name\">" + additionalRow.header.escapeHTML() + ":</div>"; - title += "<div class=\"header-value source-code\">" + additionalRow.value.escapeHTML() + "</div>" - - var headerTreeElement = new TreeElement(null, null, false); - headerTreeElement.titleHTML = title; - headerTreeElement.selectable = false; - headersTreeElement.appendChild(headerTreeElement); - } - }, - - _refreshCookies: function() - { - if (!this._cookiesView) { - if (!this.resource.requestCookies && !this.resource.responseCookies) - return; - this._cookiesView = new WebInspector.ResourceCookiesTab(); - this.tabbedPane.appendTab("cookies", WebInspector.UIString("Cookies"), this._cookiesView, this._selectTab.bind(this, "cookies")); - } - this._cookiesView.requestCookies = this.resource.requestCookies; - this._cookiesView.responseCookies = this.resource.responseCookies; } } WebInspector.ResourceView.prototype.__proto__ = WebInspector.View.prototype; - -WebInspector.ResourceCookiesTab = function() -{ - WebInspector.CookiesTable.call(this); - this.element.addStyleClass("resource-view-cookies"); - this._requestCookies = []; - this._responseCookies = []; - this._createDataGrid(true); - this._requestCookiesNode = this._createFolder(WebInspector.UIString("Request Cookies")); - this._responseCookiesNode = this._createFolder(WebInspector.UIString("Response Cookies")); -} - -WebInspector.ResourceCookiesTab.prototype = { - show: function(parentElement) - { - WebInspector.CookiesTable.prototype.show.call(this, parentElement); - this.resize(); - }, - - set requestCookies(cookies) - { - if (this._requestCookies === cookies) - return; - this._requestCookies = cookies; - this._populateCookies(this._requestCookiesNode, this._requestCookies); - }, - - set responseCookies(cookies) - { - if (this._responseCookies === cookies) - return; - this._responseCookies = cookies; - this._populateCookies(this._responseCookiesNode, this._responseCookies); - }, - - _populateDataGrid: function() - { - this._populateCookies(this._requestCookiesNode, this._requestCookies); - this._populateCookies(this._responseCookiesNode, this._responseCookies); - }, - - _populateCookies: function(parentNode, cookies) - { - WebInspector.CookiesTable.prototype._populateCookies.call(this, parentNode, cookies); - var totalSize = 0; - if (cookies) { - for (var i = 0; i < cookies.length; ++i) - totalSize += cookies[i].size; - } - parentNode.expanded = true; - parentNode.data[5] = totalSize; - parentNode.refresh(); - }, - - _createFolder: function(name) - { - var data = [ name, "", "", "", "", 0, "", "" ]; - var node = new WebInspector.DataGridNode(data); - node.selectable = true; - node.expanded = true; - this._dataGrid.appendChild(node); - node.element.addStyleClass("row-group"); - return node; - } -}; - -WebInspector.ResourceCookiesTab.prototype.__proto__ = WebInspector.CookiesTable.prototype; diff --git a/WebCore/inspector/front-end/ResourcesPanel.js b/WebCore/inspector/front-end/ResourcesPanel.js index 5285dae..d6f7172 100644 --- a/WebCore/inspector/front-end/ResourcesPanel.js +++ b/WebCore/inspector/front-end/ResourcesPanel.js @@ -61,9 +61,10 @@ WebInspector.ResourcesPanel = function(database) this.sidebarTree.appendChild(this.fileSystemListTreeElement); this.fileSystemListTreeElement.expand(); } - + this.storageViews = document.createElement("div"); this.storageViews.id = "storage-views"; + this.storageViews.className = "diff-container"; this.element.appendChild(this.storageViews); this.storageViewStatusBarItemsContainer = document.createElement("div"); @@ -99,11 +100,8 @@ WebInspector.ResourcesPanel.prototype = { { WebInspector.Panel.prototype.show.call(this); - if (this.visibleView instanceof WebInspector.ResourceView) { - // SourceViews are shared between the panels. - this.visibleView.headersVisible = false; - this.visibleView.show(this.storageViews); - } + if (this.visibleView instanceof WebInspector.ResourceView) + this._showResourceView(this.visibleView.resource); if (this._initializedDefaultSelection) return; @@ -147,7 +145,6 @@ WebInspector.ResourcesPanel.prototype = { this._domStorage = []; this._cookieViews = {}; - this._fileSystemView = null; this._applicationCacheView = null; @@ -359,7 +356,6 @@ WebInspector.ResourcesPanel.prototype = { if (line) { var view = WebInspector.ResourceManager.resourceViewForResource(resource); - view.selectContentTab(); if (view.revealLine) view.revealLine(line); if (view.highlightLine) @@ -371,10 +367,46 @@ WebInspector.ResourcesPanel.prototype = { _showResourceView: function(resource) { var view = WebInspector.ResourceManager.resourceViewForResource(resource); - view.headersVisible = false; + + // Consider rendering diff markup here. + if (resource.baseRevision && view instanceof WebInspector.SourceView) { + function callback(baseContent) + { + if (baseContent) + this._applyDiffMarkup(view, baseContent, resource.content); + } + resource.baseRevision.requestContent(callback.bind(this)); + } this._innerShowView(view); }, + _applyDiffMarkup: function(view, baseContent, newContent) { + var oldLines = baseContent.split("\n"); + var newLines = newContent.split("\n"); + + var diff = Array.diff(oldLines, newLines); + + var diffData = {}; + diffData.added = []; + diffData.removed = []; + diffData.changed = []; + + var offset = 0; + var right = diff.right; + for (var i = 0; i < right.length; ++i) { + if (typeof right[i] === "string") { + if (right.length > i + 1 && right[i + 1].row === i + 1 - offset) + diffData.changed.push(i); + else { + diffData.added.push(i); + offset++; + } + } else + offset = i - right[i].row; + } + view.sourceFrame.markDiff(diffData); + }, + showDatabase: function(database, tableName) { if (!database) @@ -813,7 +845,8 @@ WebInspector.BaseStorageTreeElement.prototype = { set titleText(titleText) { this._titleText = titleText; - this.titleElement.textContent = this._titleText; + if (this.titleElement) + this.titleElement.textContent = this._titleText; }, isEventWithinDisclosureTriangle: function() @@ -944,6 +977,7 @@ WebInspector.FrameResourceTreeElement = function(storagePanel, resource) WebInspector.BaseStorageTreeElement.call(this, storagePanel, resource, resource.displayName, "resource-sidebar-tree-item resources-category-" + resource.category.name); this._resource = resource; this._resource.addEventListener("errors-warnings-updated", this._errorsWarningsUpdated, this); + this._resource.addEventListener("content-changed", this._contentChanged, this); this.tooltip = resource.url; } @@ -989,8 +1023,7 @@ WebInspector.FrameResourceTreeElement.prototype = { _ondragstart: function(event) { - event.dataTransfer.setData("text/plain", this._resource.url); - event.dataTransfer.setData("text/uri-list", this._resource.url + "\r\n"); + event.dataTransfer.setData("text/plain", this._resource.content); event.dataTransfer.effectAllowed = "copy"; return true; }, @@ -1054,6 +1087,17 @@ WebInspector.FrameResourceTreeElement.prototype = { if (this._resource.errors) this._bubbleElement.addStyleClass("error"); + }, + + _contentChanged: function(event) + { + this.insertChild(new WebInspector.ResourceRevisionTreeElement(this._storagePanel, event.data.revision), 0); + var oldView = WebInspector.ResourceManager.existingResourceViewForResource(this._resource); + if (oldView) { + var newView = WebInspector.ResourceManager.recreateResourceView(this._resource); + if (oldView === this._storagePanel.visibleView) + this._storagePanel.visibleView = newView; + } } } @@ -1181,6 +1225,47 @@ WebInspector.ApplicationCacheTreeElement.prototype = { } WebInspector.ApplicationCacheTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype; +WebInspector.ResourceRevisionTreeElement = function(storagePanel, revision) +{ + var title = revision.timestamp ? revision.timestamp.toLocaleTimeString() : "(original)"; + WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, title, "resource-sidebar-tree-item resources-category-" + revision.category.name); + if (revision.timestamp) + this.tooltip = revision.timestamp.toLocaleString(); + this._resource = revision; +} + +WebInspector.ResourceRevisionTreeElement.prototype = { + onattach: function() + { + WebInspector.BaseStorageTreeElement.prototype.onattach.call(this); + this.listItemElement.draggable = true; + this.listItemElement.addEventListener("dragstart", this._ondragstart.bind(this), false); + this.listItemElement.addEventListener("contextmenu", this._handleContextMenuEvent.bind(this), true); + }, + + onselect: function() + { + WebInspector.BaseStorageTreeElement.prototype.onselect.call(this); + this._storagePanel._showResourceView(this._resource); + }, + + _ondragstart: function(event) + { + event.dataTransfer.setData("text/plain", this._resource.content); + event.dataTransfer.effectAllowed = "copy"; + return true; + }, + + _handleContextMenuEvent: function(event) + { + var contextMenu = new WebInspector.ContextMenu(); + contextMenu.appendItem(WebInspector.UIString("Revert to this revision"), this._resource.revertToThis.bind(this._resource)); + contextMenu.show(event); + } +} + +WebInspector.ResourceRevisionTreeElement.prototype.__proto__ = WebInspector.BaseStorageTreeElement.prototype; + WebInspector.FileSystemTreeElement = function(storagePanel, origin) { WebInspector.BaseStorageTreeElement.call(this, storagePanel, null, origin, "file-system-storage-tree-item"); diff --git a/WebCore/inspector/front-end/ScriptsPanel.js b/WebCore/inspector/front-end/ScriptsPanel.js index 32c7f21..61a2f28 100644 --- a/WebCore/inspector/front-end/ScriptsPanel.js +++ b/WebCore/inspector/front-end/ScriptsPanel.js @@ -213,11 +213,9 @@ WebInspector.ScriptsPanel.prototype = { WebInspector.Panel.prototype.show.call(this); this.sidebarResizeElement.style.right = (this.sidebarElement.offsetWidth - 3) + "px"; - if (this.visibleView) { - if (this.visibleView instanceof WebInspector.ResourceView) - this.visibleView.headersVisible = false; + if (this.visibleView) this.visibleView.show(this.viewsContainerElement); - } + if (this._attachDebuggerWhenShown) { InspectorBackend.enableDebugger(false); delete this._attachDebuggerWhenShown; @@ -308,7 +306,7 @@ WebInspector.ScriptsPanel.prototype = { return Preferences.canEditScriptSource; }, - editScriptSource: function(sourceID, newContent, line, linesCountToShift, commitEditingCallback, cancelEditingCallback) + editScriptSource: function(editData, commitEditingCallback, cancelEditingCallback) { if (!this.canEditScripts()) return; @@ -325,18 +323,19 @@ WebInspector.ScriptsPanel.prototype = { if (callFrames && callFrames.length) this.debuggerPaused(callFrames); } else { - cancelEditingCallback(); + if (cancelEditingCallback) + cancelEditingCallback(); WebInspector.log(newBodyOrErrorMessage, WebInspector.ConsoleMessage.MessageLevel.Warning); } for (var i = 0; i < breakpoints.length; ++i) { var breakpoint = breakpoints[i]; var newLine = breakpoint.line; - if (success && breakpoint.line >= line) - newLine += linesCountToShift; - WebInspector.breakpointManager.setBreakpoint(sourceID, breakpoint.url, newLine, breakpoint.enabled, breakpoint.condition); + if (success && breakpoint.line >= editData.line) + newLine += editData.linesCountToShift; + WebInspector.breakpointManager.setBreakpoint(editData.sourceID, breakpoint.url, newLine, breakpoint.enabled, breakpoint.condition); } }; - InspectorBackend.editScriptSource(sourceID, newContent, mycallback.bind(this)); + InspectorBackend.editScriptSource(editData.sourceID, editData.content, mycallback.bind(this)); }, selectedCallFrameId: function() @@ -385,10 +384,11 @@ WebInspector.ScriptsPanel.prototype = { this._updateDebuggerButtons(); + WebInspector.currentPanel = this; + this.sidebarPanes.callstack.update(callFrames, this._sourceIDMap); this.sidebarPanes.callstack.selectedCallFrame = callFrames[0]; - WebInspector.currentPanel = this; window.focus(); }, @@ -597,10 +597,9 @@ WebInspector.ScriptsPanel.prototype = { return; var view; - if (scriptOrResource instanceof WebInspector.Resource) { + if (scriptOrResource instanceof WebInspector.Resource) view = WebInspector.ResourceManager.resourceViewForResource(scriptOrResource); - view.headersVisible = false; - } else if (scriptOrResource instanceof WebInspector.Script) + else if (scriptOrResource instanceof WebInspector.Script) view = this.scriptViewForScript(scriptOrResource); if (!view) diff --git a/WebCore/inspector/front-end/Settings.js b/WebCore/inspector/front-end/Settings.js index 1acc2e0..163b184 100644 --- a/WebCore/inspector/front-end/Settings.js +++ b/WebCore/inspector/front-end/Settings.js @@ -47,6 +47,8 @@ var Preferences = { resourceExportEnabled: false, fileSystemEnabled: false, useDataURLForResourceImageIcons: true, + showTimingTab: false, + showCookiesTab: false, debugMode: false } diff --git a/WebCore/inspector/front-end/SourceFrame.js b/WebCore/inspector/front-end/SourceFrame.js index 4b391ac..8e077cd 100644 --- a/WebCore/inspector/front-end/SourceFrame.js +++ b/WebCore/inspector/front-end/SourceFrame.js @@ -87,6 +87,16 @@ WebInspector.SourceFrame.prototype = { this._updateExecutionLine(previousLine); }, + markDiff: function(diffData) + { + if (this._diffLines && this._textViewer) + this._removeDiffDecorations(); + + this._diffLines = diffData; + if (this._textViewer) + this._updateDiffDecorations(); + }, + revealLine: function(lineNumber) { if (this._textViewer) @@ -161,6 +171,17 @@ WebInspector.SourceFrame.prototype = { return this._textModel; }, + get scrollTop() + { + return this._textViewer ? this._textViewer.element.scrollTop : 0; + }, + + set scrollTop(scrollTop) + { + if (this._textViewer) + this._textViewer.element.scrollTop = scrollTop; + }, + highlightLine: function(line) { if (this._textViewer) @@ -199,6 +220,7 @@ WebInspector.SourceFrame.prototype = { this._addExistingMessagesToSource(); this._addExistingBreakpointsToSource(); this._updateExecutionLine(); + this._updateDiffDecorations(); this._textViewer.resize(); if (this._lineNumberToReveal) { @@ -319,6 +341,33 @@ WebInspector.SourceFrame.prototype = { this._textViewer.addDecoration(this._executionLine - 1, "webkit-execution-line"); }, + _updateDiffDecorations: function() + { + if (!this._diffLines) + return; + + function addDecorations(textViewer, lines, className) + { + for (var i = 0; i < lines.length; ++i) + textViewer.addDecoration(lines[i], className); + } + addDecorations(this._textViewer, this._diffLines.added, "webkit-added-line"); + addDecorations(this._textViewer, this._diffLines.removed, "webkit-removed-line"); + addDecorations(this._textViewer, this._diffLines.changed, "webkit-changed-line"); + }, + + _removeDiffDecorations: function() + { + function removeDecorations(textViewer, lines, className) + { + for (var i = 0; i < lines.length; ++i) + textViewer.removeDecoration(lines[i], className); + } + removeDecorations(this._textViewer, this._diffLines.added, "webkit-added-line"); + removeDecorations(this._textViewer, this._diffLines.removed, "webkit-removed-line"); + removeDecorations(this._textViewer, this._diffLines.changed, "webkit-changed-line"); + }, + _addExistingMessagesToSource: function() { var length = this._messages.length; diff --git a/WebCore/inspector/front-end/SourceView.js b/WebCore/inspector/front-end/SourceView.js index c7a35f7..9616321 100644 --- a/WebCore/inspector/front-end/SourceView.js +++ b/WebCore/inspector/front-end/SourceView.js @@ -33,7 +33,7 @@ WebInspector.SourceView = function(resource) this.element.addStyleClass("source"); var canEditScripts = WebInspector.panels.scripts && WebInspector.panels.scripts.canEditScripts() && resource.type === WebInspector.Resource.Type.Script; - this.sourceFrame = new WebInspector.SourceFrame(this.contentElement, this._addBreakpoint.bind(this), canEditScripts ? this._editLine.bind(this) : null, this._continueToLine.bind(this)); + this.sourceFrame = new WebInspector.SourceFrame(this.element, this._addBreakpoint.bind(this), canEditScripts ? this._editLine.bind(this) : null, this._continueToLine.bind(this)); resource.addEventListener("finished", this._resourceLoadingFinished, this); this._frameNeedsSetup = true; } @@ -50,9 +50,8 @@ WebInspector.SourceView.prototype = { show: function(parentElement) { WebInspector.ResourceView.prototype.show.call(this, parentElement); + this.setupSourceFrameIfNeeded(); this.sourceFrame.visible = true; - if (this.localSourceFrame) - this.localSourceFrame.visible = true; this.resize(); }, @@ -62,8 +61,6 @@ WebInspector.SourceView.prototype = { if (!this._frameNeedsSetup) this.sourceFrame.clearLineHighlight(); WebInspector.View.prototype.hide.call(this); - if (this.localSourceFrame) - this.localSourceFrame.visible = false; this._currentSearchResultIndex = -1; }, @@ -71,32 +68,33 @@ WebInspector.SourceView.prototype = { { if (this.sourceFrame) this.sourceFrame.resize(); - if (this.localSourceFrame) - this.localSourceFrame.resize(); - WebInspector.ResourceView.prototype.resize.call(this); }, + get scrollTop() + { + return this.sourceFrame.scrollTop; + }, + + set scrollTop(scrollTop) + { + this.sourceFrame.scrollTop = scrollTop; + }, + + setupSourceFrameIfNeeded: function() { if (!this._frameNeedsSetup) return; - this.attach(); - delete this._frameNeedsSetup; this.resource.requestContent(this._contentLoaded.bind(this)); }, - hasContentTab: function() + hasContent: function() { return true; }, - contentTabSelected: function() - { - this.setupSourceFrameIfNeeded(); - }, - _contentLoaded: function(content) { var mimeType = this._canonicalMimeType(this.resource); @@ -149,13 +147,28 @@ WebInspector.SourceView.prototype = { lines.push(textModel.line(i)); } - var linesCountToShift = newContent.split("\n").length - 1; - WebInspector.panels.scripts.editScriptSource(this._sourceIDForLine(line), lines.join("\n"), line, linesCountToShift, this._editLineComplete.bind(this), cancelEditingCallback); + var editData = {}; + editData.sourceID = this._sourceIDForLine(line); + editData.content = lines.join("\n"); + editData.line = line; + editData.linesCountToShift = newContent.split("\n").length - 1; + + WebInspector.panels.scripts.editScriptSource(editData, this._editLineComplete.bind(this, editData), cancelEditingCallback); + }, + + _editLineComplete: function(editData, newContent) + { + this.resource.setContent(newContent, this._revertEditLine.bind(this, editData)); }, - _editLineComplete: function(newBody) + _revertEditLine: function(editData, contentToRevertTo) { - this.sourceFrame.updateContent(newBody); + var newEditData = {}; + newEditData.sourceID = editData.sourceID; + newEditData.content = editData.content; + newEditData.line = editData.line; + newEditData.linesCountToShift = -editData.linesCountToShift; + WebInspector.panels.scripts.editScriptSource(newEditData, this._editLineComplete.bind(this, newEditData)); }, _sourceIDForLine: function(line) @@ -208,25 +221,6 @@ WebInspector.SourceView.prototype = { findSearchMatches.call(this, query, finishedCallback); }, - updateLocalContent: function(content, mimeType) - { - if (!this.localContentElement) { - this.localContentElement = document.createElement("div"); - this.localContentElement.className = "resource-view-content"; - this.tabbedPane.appendTab("local", WebInspector.UIString("Local"), this.localContentElement, this.selectLocalContentTab.bind(this)); - this.localSourceFrame = new WebInspector.SourceFrame(this.localContentElement, this._addBreakpoint.bind(this), null, this._continueToLine.bind(this)); - } - this.localSourceFrame.setContent(mimeType, content, ""); - }, - - selectLocalContentTab: function() - { - this.tabbedPane.selectTabById("local"); - this.localSourceFrame.visible = true; - if ("resize" in this) - this.resize(); - }, - jumpToFirstSearchResult: function() { if (!this._searchResults || !this._searchResults.length) diff --git a/WebCore/inspector/front-end/StylesSidebarPane.js b/WebCore/inspector/front-end/StylesSidebarPane.js index 1ad0ece..68ad0dd 100644 --- a/WebCore/inspector/front-end/StylesSidebarPane.js +++ b/WebCore/inspector/front-end/StylesSidebarPane.js @@ -34,6 +34,12 @@ WebInspector.StylesSidebarPane = function(computedStylePane) this.settingsSelectElement = document.createElement("select"); var option = document.createElement("option"); + option.value = "original"; + option.action = this._changeColorFormat.bind(this); + option.label = WebInspector.UIString("As Authored"); + this.settingsSelectElement.appendChild(option); + + var option = document.createElement("option"); option.value = "hex"; option.action = this._changeColorFormat.bind(this); option.label = WebInspector.UIString("Hex Colors"); @@ -61,12 +67,14 @@ WebInspector.StylesSidebarPane = function(computedStylePane) this.settingsSelectElement.addEventListener("click", function(event) { event.stopPropagation() }, false); this.settingsSelectElement.addEventListener("change", this._changeSetting.bind(this), false); var format = WebInspector.settings.colorFormat; - if (format === "hex") + if (format === "original") this.settingsSelectElement[0].selected = true; - else if (format === "rgb") + else if (format === "hex") this.settingsSelectElement[1].selected = true; - else if (format === "hsl") + else if (format === "rgb") this.settingsSelectElement[2].selected = true; + else if (format === "hsl") + this.settingsSelectElement[3].selected = true; this.titleElement.appendChild(this.settingsSelectElement); this._computedStylePane = computedStylePane; @@ -197,7 +205,7 @@ WebInspector.StylesSidebarPane.prototype = { // Add rules in reverse order to match the cascade order. for (var j = pseudoElementCSSRules.rules.length - 1; j >= 0; --j) { var rule = pseudoElementCSSRules.rules[j]; - styleRules.push({ style: rule.style, selectorText: rule.selectorText, sourceURL: rule.sourceURL, rule: rule }); + styleRules.push({ style: rule.style, selectorText: rule.selectorText, sourceURL: rule.sourceURL, rule: rule, editable: !!(rule.style && rule.style.id) }); } usedProperties = {}; disabledComputedProperties = {}; @@ -216,7 +224,7 @@ WebInspector.StylesSidebarPane.prototype = { continue; if (section.computedStyle) section.styleRule.style = nodeComputedStyle; - var styleRule = { section: section, style: section.styleRule.style, computedStyle: section.computedStyle, rule: section.rule }; + var styleRule = { section: section, style: section.styleRule.style, computedStyle: section.computedStyle, rule: section.rule, editable: !!(section.styleRule.style && section.styleRule.style.id) }; styleRules.push(styleRule); } return styleRules; @@ -252,7 +260,7 @@ WebInspector.StylesSidebarPane.prototype = { styleRules.push({ isStyleSeparator: true, text: WebInspector.UIString("Matched CSS Rules") }); for (var i = styles.matchedCSSRules.length - 1; i >= 0; --i) { var rule = styles.matchedCSSRules[i]; - styleRules.push({ style: rule.style, selectorText: rule.selectorText, sourceURL: rule.sourceURL, rule: rule }); + styleRules.push({ style: rule.style, selectorText: rule.selectorText, sourceURL: rule.sourceURL, rule: rule, editable: !!(rule.style && rule.style.id) }); } // Walk the node structure and identify styles with inherited properties. @@ -288,7 +296,7 @@ WebInspector.StylesSidebarPane.prototype = { insertInheritedNodeSeparator(parentNode); separatorInserted = true; } - styleRules.push({ style: rule.style, selectorText: rule.selectorText, sourceURL: rule.sourceURL, rule: rule, isInherited: true }); + styleRules.push({ style: rule.style, selectorText: rule.selectorText, sourceURL: rule.sourceURL, rule: rule, isInherited: true, editable: !!(rule.style && rule.style.id) }); } parentNode = parentNode.parentNode; } @@ -1248,7 +1256,9 @@ WebInspector.StylePropertyTreeElement.prototype = { swatchElement.addEventListener("dblclick", function(event) { event.stopPropagation() }, false); var format; - if (Preferences.showColorNicknames && color.nickname) + if (WebInspector.settings.colorFormat === "original") + format = "original"; + else if (Preferences.showColorNicknames && color.nickname) format = "nickname"; else if (WebInspector.settings.colorFormat === "rgb") format = (color.simple ? "rgb" : "rgba"); @@ -1262,55 +1272,59 @@ WebInspector.StylePropertyTreeElement.prototype = { var colorValueElement = document.createElement("span"); colorValueElement.textContent = color.toString(format); - function changeColorDisplay(event) + function nextFormat(curFormat) { - switch (format) { + // The format loop is as follows: + // * original + // * rgb(a) + // * hsl(a) + // * nickname (if the color has a nickname) + // * if the color is simple: + // - shorthex (if has short hex) + // - hex + switch (curFormat) { + case "original": + return color.simple ? "rgb" : "rgba"; + case "rgb": - format = "hsl"; - break; + case "rgba": + return color.simple ? "hsl" : "hsla"; + + case "hsl": + case "hsla": + if (color.nickname) + return "nickname"; + if (color.simple) + return color.hasShortHex() ? "shorthex" : "hex"; + else + return "original"; case "shorthex": - format = "hex"; - break; + return "hex"; case "hex": - format = "rgb"; - break; + return "original"; case "nickname": - if (color.simple) { - if (color.hasShortHex()) - format = "shorthex"; - else - format = "hex"; - break; - } - - format = "rgba"; - break; - - case "hsl": - if (color.nickname) - format = "nickname"; - else if (color.hasShortHex()) - format = "shorthex"; + if (color.simple) + return color.hasShortHex() ? "shorthex" : "hex"; else - format = "hex"; - break; - - case "rgba": - format = "hsla"; - break; + return "original"; - case "hsla": - if (color.nickname) - format = "nickname"; - else - format = "rgba"; - break; + default: + return null; } + } + + function changeColorDisplay(event) + { + do { + format = nextFormat(format); + var currentValue = color.toString(format || ""); + } while (format && currentValue === color.value && format !== "original"); - colorValueElement.textContent = color.toString(format); + if (format) + colorValueElement.textContent = currentValue; } var container = document.createDocumentFragment(); @@ -1771,7 +1785,7 @@ WebInspector.StylePropertyTreeElement.prototype = { // FIXME: this does not handle trailing comments. if (styleText.length && !/;\s*$/.test(styleText)) styleText += ";"; - this.property.setText(styleText, callback.bind(this)); + this.property.setText(styleText, updateInterface, callback.bind(this)); } } diff --git a/WebCore/inspector/front-end/TabbedPane.js b/WebCore/inspector/front-end/TabbedPane.js index 1ed9725..84ab702 100644 --- a/WebCore/inspector/front-end/TabbedPane.js +++ b/WebCore/inspector/front-end/TabbedPane.js @@ -32,62 +32,55 @@ WebInspector.TabbedPane = function(element) { this.element = element || document.createElement("div"); this.element.addStyleClass("tabbed-pane"); - this.tabsElement = this.element.createChild("div", "tabbed-pane-header"); - this.contentElement = this.element.createChild("div", "tabbed-pane-content"); - - this._tabObjects = {}; + this._tabsElement = this.element.createChild("div", "tabbed-pane-header"); + this._contentElement = this.element.createChild("div", "tabbed-pane-content"); + this._tabs = {}; } WebInspector.TabbedPane.prototype = { - appendTab: function(id, tabTitle, content, tabClickListener) + appendTab: function(id, tabTitle, view) { var tabElement = document.createElement("li"); tabElement.textContent = tabTitle; - tabElement.addEventListener("click", tabClickListener, false); - this.tabsElement.appendChild(tabElement); - var tabObject = { tab: tabElement }; - if (content instanceof HTMLElement) { - tabObject.element = content; - this.contentElement.appendChild(content); - } - else { - this.contentElement.appendChild(content.element); - tabObject.view = content; - } - this._tabObjects[id] = tabObject; - }, + tabElement.addEventListener("click", this.selectTab.bind(this, id, true), false); - hasTab: function(tabId) - { - return tabId in this._tabObjects; + this._tabsElement.appendChild(tabElement); + this._contentElement.appendChild(view.element); + + this._tabs[id] = { tabElement: tabElement, view: view } }, - - selectTabById: function(tabId) + + selectTab: function(id, userGesture) { - for (var id in this._tabObjects) { - if (id === tabId) - this._showTab(this._tabObjects[id]); - else - this._hideTab(this._tabObjects[id]); + if (!(id in this._tabs)) + return false; + + if (this._currentTab) { + this._hideTab(this._currentTab) + delete this._currentTab; } - return this.hasTab(tabId); + + var tab = this._tabs[id]; + this._showTab(tab); + this._currentTab = tab; + if (userGesture) { + var event = {tabId: id}; + this.dispatchEventToListeners("tab-selected", event); + } + return true; }, - _showTab: function(tabObject) + _showTab: function(tab) { - tabObject.tab.addStyleClass("selected"); - if (tabObject.element) - tabObject.element.removeStyleClass("hidden"); - else - tabObject.view.visible = true; + tab.tabElement.addStyleClass("selected"); + tab.view.show(this._contentElement); }, - _hideTab: function(tabObject) + _hideTab: function(tab) { - tabObject.tab.removeStyleClass("selected"); - if (tabObject.element) - tabObject.element.addStyleClass("hidden"); - else - tabObject.view.visible = false; + tab.tabElement.removeStyleClass("selected"); + tab.view.visible = false; } } + +WebInspector.TabbedPane.prototype.__proto__ = WebInspector.Object.prototype; diff --git a/WebCore/inspector/front-end/TimelinePanel.js b/WebCore/inspector/front-end/TimelinePanel.js index 8900d8d..16eb4d7 100644 --- a/WebCore/inspector/front-end/TimelinePanel.js +++ b/WebCore/inspector/front-end/TimelinePanel.js @@ -961,7 +961,7 @@ WebInspector.TimelinePanel.FormattedRecord.prototype = { contentHelper._appendLinkRow(WebInspector.UIString("Script"), this.data.url, this.data.lineNumber); break; case recordTypes.Paint: - contentHelper._appendTextRow(WebInspector.UIString("Location"), WebInspector.UIString("%d × %d", this.data.x, this.data.y)); + contentHelper._appendTextRow(WebInspector.UIString("Location"), WebInspector.UIString("(%d, %d)", this.data.x, this.data.y)); contentHelper._appendTextRow(WebInspector.UIString("Dimensions"), WebInspector.UIString("%d × %d", this.data.width, this.data.height)); case recordTypes.RecalculateStyles: // We don't want to see default details. break; diff --git a/WebCore/inspector/front-end/WebKit.qrc b/WebCore/inspector/front-end/WebKit.qrc index 2b87bcc..2db0182 100644 --- a/WebCore/inspector/front-end/WebKit.qrc +++ b/WebCore/inspector/front-end/WebKit.qrc @@ -21,6 +21,7 @@ <file>ContextMenu.js</file> <file>CookieItemsView.js</file> <file>CookieParser.js</file> + <file>CookiesTable.js</file> <file>CSSCompletions.js</file> <file>CSSStyleModel.js</file> <file>Database.js</file> @@ -55,6 +56,7 @@ <file>InspectorFrontendHostStub.js</file> <file>KeyboardShortcut.js</file> <file>MetricsSidebarPane.js</file> + <file>NetworkItemView.js</file> <file>NetworkPanel.js</file> <file>Object.js</file> <file>ObjectPropertiesSection.js</file> @@ -70,7 +72,10 @@ <file>RemoteObject.js</file> <file>Resource.js</file> <file>ResourceCategory.js</file> + <file>ResourceCookiesView.js</file> + <file>ResourceHeadersView.js</file> <file>ResourceManager.js</file> + <file>ResourceTimingView.js</file> <file>ResourceView.js</file> <file>ResourcesPanel.js</file> <file>ScopeChainSidebarPane.js</file> diff --git a/WebCore/inspector/front-end/WorkersSidebarPane.js b/WebCore/inspector/front-end/WorkersSidebarPane.js index 177cd15..658d57c 100644 --- a/WebCore/inspector/front-end/WorkersSidebarPane.js +++ b/WebCore/inspector/front-end/WorkersSidebarPane.js @@ -81,7 +81,6 @@ WebInspector.WorkersSidebarPane.prototype = { reset: function() { - InspectorBackend.removeAllScriptsToEvaluateOnLoad(); this.setInstrumentation(this._enableWorkersCheckbox.checked); this._treeOutline.removeChildren(); this._workers = {}; diff --git a/WebCore/inspector/front-end/inspector.css b/WebCore/inspector/front-end/inspector.css index 29f2385..0ee5864 100644 --- a/WebCore/inspector/front-end/inspector.css +++ b/WebCore/inspector/front-end/inspector.css @@ -798,91 +798,19 @@ body.platform-linux .monospace, body.platform-linux .source-code { display: block; } -.resource-view { - display: none; +.webkit-line-gutter-backdrop { + /* Keep this in sync with view-source.css (.webkit-line-gutter-backdrop) */ + width: 31px; + background-color: rgb(240, 240, 240); + border-right: 1px solid rgb(187, 187, 187); position: absolute; - background: white; - top: 0; + z-index: -1; left: 0; - right: 0; - bottom: 0; -} - -.resource-view.visible { - display: -webkit-box; -} - -.resource-view .tabbed-pane-header { - display: none; - height: 20px; - background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgb(236, 236, 236)), to(rgb(217, 217, 217))); - border-bottom: 1px solid rgb(163, 163, 163); -} - -.resource-view.headers-visible .tabbed-pane-header { - display: block; -} - -.resource-view .scope-bar li { - border-bottom-left-radius: 0; - border-bottom-right-radius: 0; -} - -.resource-view-headers { - padding: 6px; - -webkit-user-select: text; - position: absolute; top: 0; - left: 0; - right: 0; - bottom: 0; - overflow: auto; -} - -.resource-view-headers .outline-disclosure .parent { - -webkit-user-select: none; - font-weight: bold; -} - -.resource-view-headers .outline-disclosure .children li { - white-space: nowrap; -} - -.resource-view-headers .outline-disclosure li.expanded .header-count { - display: none; -} - -.resource-view-headers .outline-disclosure .header-name { - color: rgb(33%, 33%, 33%); - display: inline-block; - margin-right: 0.5em; - font-weight: bold; - vertical-align: top; - white-space: pre-wrap; -} - -.resource-view-headers .outline-disclosure .header-value { - display: inline; - margin-right: 100px; - white-space: pre-wrap; - word-break: break-all; - margin-top: 1px; -} - -.resource-view-headers .outline-disclosure .raw-form-data { - white-space:pre-wrap; -} - -.resource-view .resource-view-content { - position: absolute; - top: 0; - right: 0; - left: 0; - bottom: 0; - overflow: auto; + height: 100% } -.resource-view-cookies { +.resource-view { display: none; position: absolute; top: 0; @@ -890,36 +818,13 @@ body.platform-linux .monospace, body.platform-linux .source-code { left: 0; bottom: 0; overflow: auto; - padding: 12px; - height: 100%; } -.resource-view-cookies.visible { +.resource-view.visible { display: block; } -.resource-view-cookies.table .data-grid { - height: 100%; -} - -.resource-view-cookies .data-grid .row-group { - font-weight: bold; - font-size: 11px; -} - -.webkit-line-gutter-backdrop { - /* Keep this in sync with view-source.css (.webkit-line-gutter-backdrop) */ - width: 31px; - background-color: rgb(240, 240, 240); - border-right: 1px solid rgb(187, 187, 187); - position: absolute; - z-index: -1; - left: 0; - top: 0; - height: 100% -} - -.resource-view.font .resource-view-content { +.resource-view.font { font-size: 60px; white-space: pre-wrap; word-wrap: break-word; @@ -927,12 +832,12 @@ body.platform-linux .monospace, body.platform-linux .source-code { padding: 15px; } -.resource-view.image .resource-view-content > .image { +.resource-view.image > .image { padding: 20px 20px 10px 20px; text-align: center; } -.resource-view.image .resource-view-content > .info { +.resource-view.image > .info { padding-bottom: 10px; font-size: 11px; -webkit-user-select: text; @@ -2002,16 +1907,16 @@ li.selected .base-storage-tree-element-subtitle { display: block; } -.storage-view.table { +.storage-view { overflow: hidden; } -.storage-view.table .data-grid { +.storage-view .data-grid { border: none; height: 100%; } -.storage-empty-view, .storage-view.table .storage-table-error { +.storage-empty-view, .storage-view .storage-table-error { position: absolute; top: 0; bottom: 25%; @@ -2029,7 +1934,7 @@ li.selected .base-storage-tree-element-subtitle { white-space: pre-wrap; } -.storage-view.table .storage-table-error { +.storage-view .storage-table-error { color: rgb(66%, 33%, 33%); } @@ -4257,11 +4162,6 @@ a.worker-item { cursor: default; } -.styles-section .properties .inactive { - opacity: 0.75; - background-color: rgb(212, 212, 212); -} - .styles-section .header { white-space: nowrap; -webkit-background-origin: padding; @@ -4372,7 +4272,7 @@ a.worker-item { z-index: 1; } -.styles-section .properties .overloaded, .styles-section .properties .disabled { +.styles-section .properties .overloaded, .styles-section .properties .inactive, .styles-section .properties .disabled { text-decoration: line-through; } diff --git a/WebCore/inspector/front-end/inspector.html b/WebCore/inspector/front-end/inspector.html index e0c72e9..67fd081 100644 --- a/WebCore/inspector/front-end/inspector.html +++ b/WebCore/inspector/front-end/inspector.html @@ -35,6 +35,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <link rel="stylesheet" type="text/css" href="inspector.css"> <link rel="stylesheet" type="text/css" href="inspectorSyntaxHighlight.css"> <link rel="stylesheet" type="text/css" href="networkPanel.css"> + <link rel="stylesheet" type="text/css" href="helpScreen.css"> <link rel="stylesheet" type="text/css" href="popover.css"> <link rel="stylesheet" type="text/css" href="textViewer.css"> <script type="text/javascript" src="utilities.js"></script> @@ -67,6 +68,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <script type="text/javascript" src="DOMStorage.js"></script> <script type="text/javascript" src="DOMStorageItemsView.js"></script> <script type="text/javascript" src="DataGrid.js"></script> + <script type="text/javascript" src="CookiesTable.js"></script> <script type="text/javascript" src="CookieItemsView.js"></script> <script type="text/javascript" src="ApplicationCacheItemsView.js"></script> <script type="text/javascript" src="FileSystemView.js"></script> @@ -112,6 +114,10 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. <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="ResourceHeadersView.js"></script> + <script type="text/javascript" src="ResourceCookiesView.js"></script> + <script type="text/javascript" src="ResourceTimingView.js"></script> + <script type="text/javascript" src="NetworkItemView.js"></script> <script type="text/javascript" src="ResourceView.js"></script> <script type="text/javascript" src="SourceFrame.js"></script> <script type="text/javascript" src="DOMSyntaxHighlighter.js"></script> diff --git a/WebCore/inspector/front-end/inspector.js b/WebCore/inspector/front-end/inspector.js index 33b370a..51145cf 100644 --- a/WebCore/inspector/front-end/inspector.js +++ b/WebCore/inspector/front-end/inspector.js @@ -658,6 +658,9 @@ WebInspector.dispatch = function(message) { // This function is purposely put into the global scope for easy access. WebInspector_syncDispatch = function(message) { + if (window.dumpInspectorProtocolMessages) + console.log("backend: " + ((typeof message === "string") ? message : JSON.stringify(message))); + var messageObject = (typeof message === "string") ? JSON.parse(message) : message; var arguments = []; @@ -1228,6 +1231,7 @@ WebInspector.domContentEventFired = function(time) this.panels.audits.mainResourceDOMContentTime = time; if (this.panels.network) this.panels.network.mainResourceDOMContentTime = time; + this.extensionServer.notifyPageDOMContentLoaded((time - WebInspector.mainResource.startTime) * 1000); this.mainResourceDOMContentTime = time; } @@ -1236,6 +1240,7 @@ WebInspector.loadEventFired = function(time) this.panels.audits.mainResourceLoadTime = time; if (this.panels.network) this.panels.network.mainResourceLoadTime = time; + this.extensionServer.notifyPageLoaded((time - WebInspector.mainResource.startTime) * 1000); this.mainResourceLoadTime = time; } @@ -1400,7 +1405,6 @@ WebInspector.didCommitLoad = function() { // Cleanup elements panel early on inspected page refresh. WebInspector.setDocument(null); - this.extensionServer.notifyInspectedPageLoaded(); } WebInspector.updateConsoleMessageExpiredCount = function(count) @@ -1541,6 +1545,16 @@ WebInspector.setRecordingProfile = function(isProfiling) this.panels.profiles.updateProfileTypeButtons(); } +WebInspector.addHeapSnapshotChunk = function(uid, chunk) +{ + this.panels.profiles.addHeapSnapshotChunk(uid, chunk); +} + +WebInspector.finishHeapSnapshot = function(uid) +{ + this.panels.profiles.finishHeapSnapshot(uid); +} + WebInspector.drawLoadingPieChart = function(canvas, percent) { var g = canvas.getContext("2d"); var darkColor = "rgb(122, 168, 218)"; diff --git a/WebCore/inspector/front-end/networkPanel.css b/WebCore/inspector/front-end/networkPanel.css index 6b6aebe..70ebe56 100644 --- a/WebCore/inspector/front-end/networkPanel.css +++ b/WebCore/inspector/front-end/networkPanel.css @@ -26,7 +26,6 @@ line-height: 17px; height: 37px; border-right: 1px solid rgb(210, 210, 210); - -webkit-user-select: none; vertical-align: middle; } @@ -72,6 +71,11 @@ .network-sidebar .data-grid td.name-column { font-weight: bold; + cursor: pointer; +} + +.network.panel:not(.viewing-resource) .network-sidebar td.name-column:hover { + text-decoration: underline; } .network-sidebar .data-grid td.method-column, @@ -97,11 +101,15 @@ .network-cell-subtitle { font-weight: normal; - color: grey; + color: gray; +} + +.network-sidebar tr.selected .network-cell-subtitle { + color: white; } .network-header-subtitle { - color: grey; + color: gray; } .network-sidebar .data-grid.small .network-cell-subtitle, @@ -362,7 +370,7 @@ .network-timing-row { position: relative; - height: 12px; + height: 16px; } .network-timing-bar { @@ -370,10 +378,14 @@ background-color: red; border-left: 1px solid red; opacity: 0.4; + top: 0; + bottom: 0; } .network-timing-bar-title { position: absolute; + color: black; + top: 1px; } .network-dim-cell { @@ -629,13 +641,14 @@ color: black; } -#network-views .resource-view .tabbed-pane-header { +#network-views .network-item-view .tabbed-pane-header { height: 31px; padding-top: 8px; padding-left: 25px; + white-space: nowrap; } -#network-views.small .resource-view .tabbed-pane-header { +#network-views.small .network-item-view .tabbed-pane-header { height: 23px; padding-top: 0; } @@ -643,3 +656,163 @@ .network.panel.viewing-resource .data-grid .data-container { padding-right: 0; } + +.network-item-view { + display: none; + position: absolute; + background: white; + top: 0; + left: 0; + right: 0; + bottom: 0; +} + +.network-item-view.visible { + display: -webkit-box; +} + +.network-item-view .tabbed-pane-header { + height: 20px; + background: -webkit-gradient(linear, 0% 0%, 0% 100%, from(rgb(236, 236, 236)), to(rgb(217, 217, 217))); + border-bottom: 1px solid rgb(163, 163, 163); +} + +.network-item-view .scope-bar li { + border-bottom-left-radius: 0; + border-bottom-right-radius: 0; +} + +.resource-headers-view { + display: none; + padding: 6px; + -webkit-user-select: text; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + overflow: auto; +} + +.resource-headers-view.visible { + display: block; +} + +.resource-headers-view .outline-disclosure .parent { + -webkit-user-select: none; + font-weight: bold; +} + +.resource-headers-view .outline-disclosure .children li { + white-space: nowrap; +} + +.resource-headers-view .outline-disclosure li.expanded .header-count { + display: none; +} + +.resource-headers-view .outline-disclosure .header-name { + color: rgb(33%, 33%, 33%); + display: inline-block; + margin-right: 0.5em; + font-weight: bold; + vertical-align: top; + white-space: pre-wrap; +} + +.resource-headers-view .outline-disclosure .header-value { + display: inline; + margin-right: 100px; + white-space: pre-wrap; + word-break: break-all; + margin-top: 1px; +} + +.resource-headers-view .outline-disclosure .raw-form-data { + white-space: pre-wrap; +} + +.resource-cookies-view { + display: none; + position: absolute; + top: 0; + right: 0; + left: 0; + bottom: 0; + overflow: auto; + padding: 12px; + height: 100%; +} + +.resource-cookies-view.visible { + display: block; +} + +.resource-cookies-view .data-grid { + height: 100%; +} + +.resource-cookies-view .data-grid .row-group { + font-weight: bold; + font-size: 11px; +} + +.resource-timing-view { + display: none; + position: absolute; + top: 0; + right: 0; + left: 0; + bottom: 0; + padding: 6px; + font-weight: bold; + font-size: 11px; + color: rgb(30%, 30%, 30%); +} + +.resource-timing-view table { + border-spacing: 21px 0; +} + +.resource-timing-view .network-timing-bar { + opacity: 1; +} + +.resource-timing-view .network-timing-bar.proxy { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(239, 228, 176)), to(rgb(139, 128, 76))); + border-left: 1px solid rgb(139, 128, 76); +} + +.resource-timing-view .network-timing-bar.dns { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(153, 208, 216)), to(rgb(81, 174, 189))); + border-left: 1px solid rgb(81, 174, 189); +} + +.resource-timing-view .network-timing-bar.connecting { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(203, 232, 145)), to(rgb(160, 214, 56))); + border-left: 1px solid rgb(160, 214, 56); +} + +.resource-timing-view .network-timing-bar.ssl { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(21, 232, 145)), to(rgb(216, 149, 132))); + border-left: 1px solid rgb(216, 149, 132); +} + +.resource-timing-view .network-timing-bar.sending { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(232, 192, 182)), to(rgb(216, 147, 130))); + border-left: 1px solid rgb(216, 147, 130); +} + +.resource-timing-view .network-timing-bar.waiting { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(188, 179, 208)), to(rgb(141, 125, 175))); + border-left: 1px solid rgb(141, 125, 175); +} + +.resource-timing-view .network-timing-bar.receiving { + background-image: -webkit-gradient(linear, left top, left bottom, from(rgb(214, 214, 214)), to(rgb(182, 182, 182))); + border-left: 1px solid rgb(182, 182, 182); +} + +.resource-timing-view.visible { + display: block; +} diff --git a/WebCore/inspector/front-end/textViewer.css b/WebCore/inspector/front-end/textViewer.css index 8a96b1f..bee9fe5 100644 --- a/WebCore/inspector/front-end/textViewer.css +++ b/WebCore/inspector/front-end/textViewer.css @@ -64,8 +64,8 @@ vertical-align: top; word-break: normal; -webkit-user-select: none; - padding-right: 4px; - padding-left: 6px; + padding-right: 4px; + padding-left: 6px; } .webkit-line-number-outer { @@ -141,6 +141,19 @@ outline: 1px solid rgb(64, 115, 244); } +.diff-container .webkit-added-line .webkit-line-content { + background-color: rgb(220, 255, 220); +} + +.diff-container .webkit-removed-line .webkit-line-content { + background-color: rgb(255, 220, 220); + text-decoration: line-through; +} + +.diff-container .webkit-changed-line .webkit-line-content { + background-color: rgb(220, 220, 255); +} + .webkit-search-result { -webkit-border-radius: 4px; padding: 2px 2px 2px 3px; diff --git a/WebCore/inspector/front-end/utilities.js b/WebCore/inspector/front-end/utilities.js index 3aff6bb..f978c6f 100644 --- a/WebCore/inspector/front-end/utilities.js +++ b/WebCore/inspector/front-end/utilities.js @@ -24,6 +24,9 @@ * 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. + * + * Contains diff method based on Javascript Diff Algorithm By John Resig + * http://ejohn.org/files/jsdiff.js (released under the MIT license). */ Function.prototype.bind = function(thisObject) @@ -731,6 +734,51 @@ Array.prototype.keySet = function() return keys; } +Array.diff = function(left, right) +{ + var o = left; + var n = right; + + var ns = {}; + var os = {}; + + for (var i = 0; i < n.length; i++) { + if (ns[n[i]] == null) + ns[n[i]] = { rows: [], o: null }; + ns[n[i]].rows.push(i); + } + + for (var i = 0; i < o.length; i++) { + if (os[o[i]] == null) + os[o[i]] = { rows: [], n: null }; + os[o[i]].rows.push(i); + } + + for (var i in ns) { + if (ns[i].rows.length == 1 && typeof(os[i]) != "undefined" && os[i].rows.length == 1) { + n[ns[i].rows[0]] = { text: n[ns[i].rows[0]], row: os[i].rows[0] }; + o[os[i].rows[0]] = { text: o[os[i].rows[0]], row: ns[i].rows[0] }; + } + } + + for (var i = 0; i < n.length - 1; i++) { + if (n[i].text != null && n[i + 1].text == null && n[i].row + 1 < o.length && o[n[i].row + 1].text == null && n[i + 1] == o[n[i].row + 1]) { + n[i + 1] = { text: n[i + 1], row: n[i].row + 1 }; + o[n[i].row + 1] = { text: o[n[i].row + 1], row: i + 1 }; + } + } + + for (var i = n.length - 1; i > 0; i--) { + if (n[i].text != null && n[i - 1].text == null && n[i].row > 0 && o[n[i].row - 1].text == null && + n[i - 1] == o[n[i].row - 1]) { + n[i - 1] = { text: n[i - 1], row: n[i].row - 1 }; + o[n[i].row - 1] = { text: o[n[i].row - 1], row: i - 1 }; + } + } + + return { left: o, right: n }; +} + Array.convert = function(list) { // Cast array-like object to an array. |